build: add header includes check
authorBruce Richardson <bruce.richardson@intel.com>
Fri, 29 Jan 2021 16:48:21 +0000 (16:48 +0000)
committerDavid Marchand <david.marchand@redhat.com>
Fri, 29 Jan 2021 19:59:37 +0000 (20:59 +0100)
To verify that all DPDK headers are ok for inclusion directly in a C file,
and are not missing any other pre-requisite headers, we can auto-generate
for each header an empty C file that includes that header. Compiling these
files will throw errors if any header has unmet dependencies.

For some libraries, there may be some header files which are not for direct
inclusion, but rather are to be included via other header files. To allow
later checking of these files for missing includes, we separate out the
indirect include files from the direct ones.

To ensure ongoing compliance, we enable this build test as part of the
default x86 build in "test-meson-builds.sh".

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
20 files changed:
MAINTAINERS
buildtools/chkincs/gen_c_file_for_header.py [new file with mode: 0755]
buildtools/chkincs/main.c [new file with mode: 0644]
buildtools/chkincs/meson.build [new file with mode: 0644]
devtools/test-meson-builds.sh
doc/guides/contributing/coding_style.rst
doc/guides/rel_notes/release_21_02.rst
lib/librte_eal/include/meson.build
lib/librte_eal/x86/include/meson.build
lib/librte_ethdev/meson.build
lib/librte_hash/meson.build
lib/librte_ipsec/meson.build
lib/librte_lpm/meson.build
lib/librte_regexdev/meson.build
lib/librte_ring/meson.build
lib/librte_stack/meson.build
lib/librte_table/meson.build
lib/meson.build
meson.build
meson_options.txt

index 6af59ea..ec20314 100644 (file)
@@ -98,6 +98,7 @@ F: Makefile
 F: meson.build
 F: meson_options.txt
 F: config/
+F: buildtools/chkincs/
 F: buildtools/call-sphinx-build.py
 F: buildtools/list-dir-globs.py
 F: buildtools/pkg-config/
diff --git a/buildtools/chkincs/gen_c_file_for_header.py b/buildtools/chkincs/gen_c_file_for_header.py
new file mode 100755 (executable)
index 0000000..ed46948
--- /dev/null
@@ -0,0 +1,12 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2021 Intel Corporation
+
+from sys import argv
+from os.path import abspath
+
+(h_file, c_file) = argv[1:]
+
+contents = '#include "' + abspath(h_file) + '"'
+with open(c_file, 'w') as cf:
+    cf.write(contents)
diff --git a/buildtools/chkincs/main.c b/buildtools/chkincs/main.c
new file mode 100644 (file)
index 0000000..d25bb88
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Intel Corporation
+ */
+int main(void) { return 0; }
diff --git a/buildtools/chkincs/meson.build b/buildtools/chkincs/meson.build
new file mode 100644 (file)
index 0000000..f345e87
--- /dev/null
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2021 Intel Corporation
+
+if not get_option('check_includes')
+       build = false
+       subdir_done()
+endif
+
+if is_windows
+       # for windows, the shebang line in the script won't work.
+       error('option "check_includes" is not supported on windows')
+endif
+
+gen_c_file_for_header = find_program('gen_c_file_for_header.py')
+gen_c_files = generator(gen_c_file_for_header,
+       output: '@BASENAME@.c',
+       arguments: ['@INPUT@', '@OUTPUT@'])
+
+cflags = machine_args
+cflags += '-Wno-unused-function' # needed if we include generic headers
+cflags += '-DALLOW_EXPERIMENTAL_API'
+
+sources = files('main.c')
+sources += gen_c_files.process(dpdk_chkinc_headers)
+
+deps = []
+foreach l:enabled_libs
+       deps += get_variable('static_rte_' + l)
+endforeach
+
+executable('chkincs', sources,
+       c_args: cflags,
+       include_directories: includes,
+       dependencies: deps,
+       link_whole: dpdk_static_libraries + dpdk_drivers,
+       install: false)
index efa91e0..a99a177 100755 (executable)
@@ -227,7 +227,7 @@ default_machine='nehalem'
 if ! check_cc_flags "-march=$default_machine" ; then
        default_machine='corei7'
 fi
-build build-x86-default cc skipABI \
+build build-x86-default cc skipABI -Dcheck_includes=true \
        -Dlibdir=lib -Dmachine=$default_machine $use_shared
 
 # 32-bit with default compiler
index bb3f3ef..734d190 100644 (file)
@@ -891,6 +891,18 @@ headers
        installed to $PREFIX/include when ``ninja install`` is run. As with
        source files, these should be specified using the meson ``files()``
        function.
+       When ``check_includes`` build option is set to ``true``, each header file
+       has additional checks performed on it, for example to ensure that it is
+       not missing any include statements for dependent headers.
+       For header files which are public, but only included indirectly in
+       applications, these checks can be skipped by using the ``indirect_headers``
+       variable rather than ``headers``.
+
+indirect_headers
+       **Default Value = []**.
+       As with ``headers`` option above, except that the files are not checked
+       for all needed include files as part of a DPDK build when
+       ``check_includes`` is set to ``true``.
 
 includes:
        **Default Value = []**.
index d26e581..29046a6 100644 (file)
@@ -138,6 +138,14 @@ New Features
 
   See the :doc:`../compressdevs/mlx5` for more details.
 
+* **Added support for build-time checking of header includes.**
+
+  A new build option ``check_includes`` has been added, which, when enabled,
+  will perform build-time checking on DPDK public header files, to ensure none
+  are missing dependent header includes. This feature, disabled by default, is
+  intended for use by developers contributing to the DPDK SDK itself, and is
+  integrated into the build scripts and automated CI for patch contributions.
+
 
 Removed Items
 -------------
index 0dea342..3969cf4 100644 (file)
@@ -16,7 +16,6 @@ headers += files(
        'rte_dev.h',
        'rte_devargs.h',
        'rte_eal.h',
-       'rte_eal_interrupts.h',
        'rte_eal_memconfig.h',
        'rte_eal_trace.h',
        'rte_errno.h',
@@ -49,6 +48,7 @@ headers += files(
        'rte_version.h',
        'rte_vfio.h',
 )
+indirect_headers += files('rte_eal_interrupts.h')
 
 # special case install the generic headers, since they go in a subdir
 generic_headers = files(
index 549cc21..1a6ad0b 100644 (file)
@@ -2,11 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 arch_headers = files(
-       'rte_atomic_32.h',
-       'rte_atomic_64.h',
        'rte_atomic.h',
-       'rte_byteorder_32.h',
-       'rte_byteorder_64.h',
        'rte_byteorder.h',
        'rte_cpuflags.h',
        'rte_cycles.h',
@@ -22,4 +18,12 @@ arch_headers = files(
        'rte_ticketlock.h',
        'rte_vect.h',
 )
-install_headers(arch_headers, subdir: get_option('include_subdir_arch'))
+arch_indirect_headers = files(
+       'rte_atomic_32.h',
+       'rte_atomic_64.h',
+       'rte_byteorder_32.h',
+       'rte_byteorder_64.h',
+)
+install_headers(arch_headers + arch_indirect_headers,
+               subdir: get_option('include_subdir_arch'))
+dpdk_chkinc_headers += arch_headers
index 829abd4..c37b2e3 100644 (file)
@@ -11,10 +11,8 @@ sources = files('ethdev_private.c',
        'rte_tm.c')
 
 headers = files('rte_ethdev.h',
-       'rte_ethdev_core.h',
        'rte_ethdev_trace.h',
        'rte_ethdev_trace_fp.h',
-       'rte_eth_ctrl.h',
        'rte_dev_info.h',
        'rte_flow.h',
        'rte_flow_driver.h',
@@ -22,5 +20,8 @@ headers = files('rte_ethdev.h',
        'rte_mtr_driver.h',
        'rte_tm.h',
        'rte_tm_driver.h')
+indirect_headers += files(
+       'rte_ethdev_core.h',
+       'rte_eth_ctrl.h')
 
 deps += ['net', 'kvargs', 'meter', 'telemetry']
index 0977a63..242859f 100644 (file)
@@ -1,12 +1,12 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-headers = files('rte_crc_arm64.h',
-       'rte_fbk_hash.h',
+headers = files('rte_fbk_hash.h',
        'rte_hash_crc.h',
        'rte_hash.h',
        'rte_jhash.h',
        'rte_thash.h')
+indirect_headers += files('rte_crc_arm64.h')
 
 sources = files('rte_cuckoo_hash.c', 'rte_fbk_hash.c')
 deps += ['ring']
index fc69970..1497f57 100644 (file)
@@ -3,6 +3,7 @@
 
 sources = files('esp_inb.c', 'esp_outb.c', 'sa.c', 'ses.c', 'ipsec_sad.c')
 
-headers = files('rte_ipsec.h', 'rte_ipsec_group.h', 'rte_ipsec_sa.h', 'rte_ipsec_sad.h')
+headers = files('rte_ipsec.h', 'rte_ipsec_sa.h', 'rte_ipsec_sad.h')
+indirect_headers += files('rte_ipsec_group.h')
 
 deps += ['mbuf', 'net', 'cryptodev', 'security', 'hash']
index f93c866..90cbf86 100644 (file)
@@ -5,6 +5,6 @@ sources = files('rte_lpm.c', 'rte_lpm6.c')
 headers = files('rte_lpm.h', 'rte_lpm6.h')
 # since header files have different names, we can install all vector headers
 # without worrying about which architecture we actually need
-headers += files('rte_lpm_altivec.h', 'rte_lpm_neon.h', 'rte_lpm_sse.h', 'rte_lpm_sve.h')
+indirect_headers += files('rte_lpm_altivec.h', 'rte_lpm_neon.h', 'rte_lpm_sse.h', 'rte_lpm_sve.h')
 deps += ['hash']
 deps += ['rcu']
index c417b9c..1b3b6db 100644 (file)
@@ -3,6 +3,6 @@
 
 sources = files('rte_regexdev.c')
 headers = files('rte_regexdev.h',
-       'rte_regexdev_core.h',
        'rte_regexdev_driver.h')
+indirect_headers += files('rte_regexdev_core.h')
 deps += ['mbuf']
index f007893..ea050d5 100644 (file)
@@ -2,7 +2,9 @@
 # Copyright(c) 2017 Intel Corporation
 
 sources = files('rte_ring.c')
-headers = files('rte_ring.h',
+headers = files('rte_ring.h')
+# most sub-headers are not for direct inclusion
+indirect_headers += files (
                'rte_ring_core.h',
                'rte_ring_elem.h',
                'rte_ring_elem_pvt.h',
index 8f82a40..9ff3372 100644 (file)
@@ -2,7 +2,9 @@
 # Copyright(c) 2019 Intel Corporation
 
 sources = files('rte_stack.c', 'rte_stack_std.c', 'rte_stack_lf.c')
-headers = files('rte_stack.h',
+headers = files('rte_stack.h')
+# subheaders, not for direct inclusion by apps
+indirect_headers += files(
                'rte_stack_std.h',
                'rte_stack_lf.h',
                'rte_stack_lf_generic.h',
index d696783..aa1e1d0 100644 (file)
@@ -20,7 +20,6 @@ headers = files('rte_table.h',
                'rte_table_hash.h',
                'rte_table_hash_cuckoo.h',
                'rte_table_hash_func.h',
-               'rte_table_hash_func_arm64.h',
                'rte_lru.h',
                'rte_table_array.h',
                'rte_table_stub.h',
@@ -28,6 +27,6 @@ headers = files('rte_table.h',
                'rte_swx_table_em.h',)
 deps += ['mbuf', 'port', 'lpm', 'hash', 'acl']
 
-if arch_subdir == 'x86'
-       headers += files('rte_lru_x86.h')
-endif
+indirect_headers += files('rte_lru_x86.h',
+               'rte_lru_arm64.h',
+               'rte_table_hash_func_arm64.h')
index 44f0a62..7712aa4 100644 (file)
@@ -66,6 +66,7 @@ foreach l:libraries
        use_function_versioning = false
        sources = []
        headers = []
+       indirect_headers = [] # public headers not directly included by apps
        includes = []
        cflags = default_cflags
        objs = [] # other object files to link against, used e.g. for
@@ -103,6 +104,8 @@ foreach l:libraries
                enabled_libs += name
                dpdk_conf.set('RTE_LIB_' + name.to_upper(), 1)
                install_headers(headers)
+               install_headers(indirect_headers)
+               dpdk_chkinc_headers += headers
 
                libname = 'rte_' + name
                includes += include_directories(dir_name)
index 2b9c37e..fcc4d4c 100644 (file)
@@ -16,6 +16,7 @@ cc = meson.get_compiler('c')
 dpdk_conf = configuration_data()
 dpdk_libraries = []
 dpdk_static_libraries = []
+dpdk_chkinc_headers = []
 dpdk_driver_classes = []
 dpdk_drivers = []
 dpdk_extra_ldflags = []
@@ -67,6 +68,11 @@ if get_option('enable_kmods')
        subdir('kernel')
 endif
 
+# check header includes if requested
+if get_option('check_includes')
+       subdir('buildtools/chkincs')
+endif
+
 # write the build config
 build_cfg = 'rte_build_config.h'
 configure_file(output: build_cfg,
index 4604328..5c38248 100644 (file)
@@ -1,5 +1,7 @@
 # Please keep these options sorted alphabetically.
 
+option('check_includes', type: 'boolean', value: false,
+       description: 'build "chkincs" to verify each header file can compile alone')
 option('disable_drivers', type: 'string', value: '',
        description: 'Comma-separated list of drivers to explicitly disable.')
 option('drivers_install_subdir', type: 'string', value: 'dpdk/pmds-<VERSION>',