mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] kbuild: add header check facility as a manually run static analyzer
@ 2026-09-15 10:43 Jani Nikula
  2026-09-16 22:24 ` Randy Dunlap
  0 siblings, 1 reply; 8+ messages in thread
From: Jani Nikula @ 2026-09-15 10:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: jani.nikula, Linus Torvalds, Nathan Chancellor, Nicolas Schier,
	Jason Gunthorpe, Masahiro Yamada, linux-kbuild

There have been various attempts at adding a header test or check
mechanism in the kernel build system. The header check primarily
consists of ensuring headers are self-contained, have include guards,
and, in some cases, pass kernel-doc.

The main problems have been:

- The dependency tracking creates undesirable artefacts (infamously also
  known as disgusting turds) in the build directory.

- Gating the feature behind a kconfig option is complicated due to
  allyesconfig builds. It's possible, but requires a verbose and
  confusing negative proxy config option.

- Naming the dependency tracking files with a dot prefix or placing them
  in a dot prefixed subdirectory in the build directory to hide them has
  been exceedingly difficult to achieve. (In part due to some Makefiles
  building files in subdirectory hierarchies.)

- The debate which headers, if any, should really be self-contained is
  virtually open-ended.

Approach the problem from a slightly different angle. Add a top level
"headercheck" static analysis target which you have to explicitly run,
and where you have to explicitly state which headers to check:

$ make HEADER_CHECK="(headers|dirs)" headercheck

For example:

$ make HEADER_CHECK="include/drm drivers/gpu/drm/drm_draw_internal.h" headercheck

You can specify multiple path/to/header.h or path/to/dir, relative to
$(srctree), where path/to/dir is recursively scanned for any .h files.

Add a generic %.header-check rule in scripts/Makefile.build to support
this. Note that this rule should *not* be used in, say, driver or
subsystem makefile targets, precisely because of the problems listed
above.

While this still generates the .header-check dependency tracking
artefacts in the build directory, you will only get them as a result of
manually running 'make headercheck', not as part of the regular build.

This approach also allows anyone to check any headers in the tree, with
no makefile modification or kconfig changes required. What you do with
the results is up to you, and the header check facility does not enforce
anything like it would as part of the regular build.

Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nicolas Schier <nsc@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: linux-kbuild@vger.kernel.org
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 .gitignore             |  1 +
 Makefile               | 25 ++++++++++++++++++++++++-
 scripts/Makefile.build | 21 +++++++++++++++++++++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 9875120ea7bd..948c760b2704 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@
 *.gcno
 *.gcda
 *.gz
+*.header-check
 *.i
 *.ko
 *.lex.c
diff --git a/Makefile b/Makefile
index 0f1b80100b47..4851a4407149 100644
--- a/Makefile
+++ b/Makefile
@@ -301,7 +301,7 @@ no-dot-config-targets := $(clean-targets) \
 			 run-command
 no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
 			  image_name
-single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %/
+single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.header-check %/
 
 config-build	:=
 mixed-build	:=
@@ -1540,6 +1540,26 @@ PHONY += scripts_gen_packed_field_checks
 scripts_gen_packed_field_checks: scripts_basic
 	$(Q)$(MAKE) $(build)=scripts scripts/gen_packed_field_checks
 
+# ---------------------------------------------------------------------------
+# Header check
+
+# Check the headers in HEADER_CHECK=(headers|dirs)
+PHONY += headercheck
+
+ifneq ($(HEADER_CHECK),)
+
+header-check-dirs := $(filter-out %.h,$(HEADER_CHECK))
+header-check-files := $(filter %.h,$(HEADER_CHECK)) $(if $(header-check-dirs),$(shell cd $(srctree) && find $(header-check-dirs) -name '*.h' 2>/dev/null))
+header-check-targets := $(patsubst %.h,%.header-check,$(sort $(header-check-files)))
+
+headercheck:
+	$(if $(header-check-targets),,$(error $@ found no headers in HEADER_CHECK="$(HEADER_CHECK)"))
+	$(Q)$(MAKE) $(header-check-targets)
+else
+headercheck:
+	$(error $@ requires HEADER_CHECK=(headers|dirs))
+endif
+
 # ---------------------------------------------------------------------------
 # Install
 
@@ -1886,6 +1906,8 @@ help:
 	@echo  '  versioncheck      - Sanity check on version.h usage'
 	@echo  '  includecheck      - Check for duplicate included header files'
 	@echo  '  headerdep         - Detect inclusion cycles in headers'
+	@echo  '  headercheck       - Check headers in HEADER_CHECK=(headers|dirs) are'
+	@echo  '                      self-contained, have header guards, and pass kernel-doc.'
 	@echo  '  coccicheck        - Check with Coccinelle'
 	@echo  '  kconfig-sym-check - Check for dangling Kconfig symbol references'
 	@echo  '  clang-analyzer    - Check with clang static analyzer'
@@ -2251,6 +2273,7 @@ clean: $(clean-dirs)
 		-o -name '*.ll' \
 		-o -name '*.gcno' \
 		-o -name '*.long-type-*.txt' \
+		-o -name '*.header-check' \
 		\) -type f -print \
 		-o -name '.tmp_*' -print \
 		| xargs rm -rf
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 4349108e75e1..6127feb970c6 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -306,6 +306,27 @@ quiet_cmd_cc_lst_c = MKLST   $@
 $(obj)/%.lst: $(obj)/%.c FORCE
 	$(call if_changed_dep,cc_lst_c)
 
+# Compile C headers (.h) for header check
+# ---------------------------------------------------------------------------
+
+# Check a header is self-contained, has header guards, and passes kernel-doc.
+#
+# This is for 'make HEADER_CHECK=(headers|dirs) headercheck'. Not to be confused
+# with CONFIG_UAPI_HEADER_TEST.
+#
+# Please do *not* plug %.header-check into any configurable targets, unless you
+# also figure out a way to completely hide the %.header-check artefacts.
+
+quiet_cmd_header_check = HDRCHK  $(patsubst %.header-check,%.h,$@)
+      cmd_header_check = \
+		$(CC) $(c_flags) -fsyntax-only -x c /dev/null -include $< -include $<; \
+		PYTHONDONTWRITEBYTECODE=1 $(PYTHON3) $(KERNELDOC) -none $(KDOCFLAGS) \
+			$(if $(findstring e, $(KBUILD_EXTRA_WARN))$(CONFIG_WERROR),-Werror) $<; \
+		touch $@
+
+$(obj)/%.header-check: $(obj)/%.h FORCE
+	$(call if_changed_dep,header_check)
+
 # Compile Rust sources (.rs)
 # ---------------------------------------------------------------------------
 
-- 
2.47.3


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-15 10:43 [PATCH] kbuild: add header check facility as a manually run static analyzer Jani Nikula
@ 2026-09-16 22:24 ` Randy Dunlap
  2026-09-16 23:13   ` Nathan Chancellor
  0 siblings, 1 reply; 8+ messages in thread
From: Randy Dunlap @ 2026-09-16 22:24 UTC (permalink / raw)
  To: Jani Nikula, linux-kernel
  Cc: Linus Torvalds, Nathan Chancellor, Nicolas Schier,
	Jason Gunthorpe, Masahiro Yamada, linux-kbuild

Hi Jani,

On 9/15/26 3:43 AM, Jani Nikula wrote:
> There have been various attempts at adding a header test or check
> mechanism in the kernel build system. The header check primarily
> consists of ensuring headers are self-contained, have include guards,
> and, in some cases, pass kernel-doc.
> 
> The main problems have been:
> 
> - The dependency tracking creates undesirable artefacts (infamously also
>   known as disgusting turds) in the build directory.
> 
> - Gating the feature behind a kconfig option is complicated due to
>   allyesconfig builds. It's possible, but requires a verbose and
>   confusing negative proxy config option.
> 
> - Naming the dependency tracking files with a dot prefix or placing them
>   in a dot prefixed subdirectory in the build directory to hide them has
>   been exceedingly difficult to achieve. (In part due to some Makefiles
>   building files in subdirectory hierarchies.)
> 
> - The debate which headers, if any, should really be self-contained is
>   virtually open-ended.

I would expect that headers in include/uapi/*.h should be self-contained,
but apparently that's just a pipe dream on my part, or maybe it's just
a maintainer option.


With 'make HEADER_CHECK="include/uapi/" headercheck'
I see over 70 errors (mostly typedefs or defined constants, but not only
those), such as:

In file included from <command-line>:
./../include/uapi/linux/hdlc/ioctl.h:74:21: error: ‘IFNAMSIZ’ undeclared here (not in a function)
   74 |         char master[IFNAMSIZ];  /* Name of master FRAD device */
      |                     ^~~~~~~~
In file included from <command-line>:
./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
   29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
      |      ^~~~~~~~~~~~~~~
./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
   34 |         __kernel_ulong_t __sec;
      |         ^~~~~~~~~~~~~~~~
In file included from ./../include/uapi/linux/papr_pdsm.h:14,
                 from <command-line>:
../include/linux/ndctl.h:19:33: error: ‘PAGE_SIZE’ undeclared here (not in a function)
   19 |         ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
      |                                 ^~~~~~~~~
In file included from <command-line>:
./../include/uapi/linux/patchkey.h:15:2: error: #error "patchkey.h included directly"
   15 | #error "patchkey.h included directly"
      |  ^~~~~
In file included from <command-line>:
include/uapi/xen/gntdev.h:159:25: error: unknown type name ‘grant_ref_t’
  159 |                         grant_ref_t ref;
      |                         ^~~~~~~~~~~
include/uapi/xen/gntdev.h:161:25: error: unknown type name ‘domid_t’
  161 |                         domid_t domid;
      |                         ^~~~~~~



I like it; I think it's useful.

Tested-by: Randy Dunlap <rdunlap@infradead.org>
Acked-by: Randy Dunlap <rdunlap@infradead.org>

> Approach the problem from a slightly different angle. Add a top level
> "headercheck" static analysis target which you have to explicitly run,
> and where you have to explicitly state which headers to check:
> 
> $ make HEADER_CHECK="(headers|dirs)" headercheck
> 
> For example:
> 
> $ make HEADER_CHECK="include/drm drivers/gpu/drm/drm_draw_internal.h" headercheck
> 
> You can specify multiple path/to/header.h or path/to/dir, relative to
> $(srctree), where path/to/dir is recursively scanned for any .h files.
> 
> Add a generic %.header-check rule in scripts/Makefile.build to support
> this. Note that this rule should *not* be used in, say, driver or
> subsystem makefile targets, precisely because of the problems listed
> above.
> 
> While this still generates the .header-check dependency tracking
> artefacts in the build directory, you will only get them as a result of
> manually running 'make headercheck', not as part of the regular build.
> 
> This approach also allows anyone to check any headers in the tree, with
> no makefile modification or kconfig changes required. What you do with
> the results is up to you, and the header check facility does not enforce
> anything like it would as part of the regular build.
> 
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Cc: Nathan Chancellor <nathan@kernel.org>
> Cc: Nicolas Schier <nsc@kernel.org>
> Cc: Jason Gunthorpe <jgg@nvidia.com>
> Cc: Masahiro Yamada <masahiroy@kernel.org>
> Cc: linux-kbuild@vger.kernel.org
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  .gitignore             |  1 +
>  Makefile               | 25 ++++++++++++++++++++++++-
>  scripts/Makefile.build | 21 +++++++++++++++++++++
>  3 files changed, 46 insertions(+), 1 deletion(-)


thanks.
-- 
~Randy

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-16 22:24 ` Randy Dunlap
@ 2026-09-16 23:13   ` Nathan Chancellor
  2026-09-17  2:26     ` Randy Dunlap
                       ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Nathan Chancellor @ 2026-09-16 23:13 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Jani Nikula, linux-kernel, Linus Torvalds, Nicolas Schier,
	Jason Gunthorpe, Masahiro Yamada, linux-kbuild

On Wed, Sep 16, 2026 at 03:24:09PM -0700, Randy Dunlap wrote:
> On 9/15/26 3:43 AM, Jani Nikula wrote:
> > There have been various attempts at adding a header test or check
> > mechanism in the kernel build system. The header check primarily
> > consists of ensuring headers are self-contained, have include guards,
> > and, in some cases, pass kernel-doc.
> > 
> > The main problems have been:
> > 
> > - The dependency tracking creates undesirable artefacts (infamously also
> >   known as disgusting turds) in the build directory.
> > 
> > - Gating the feature behind a kconfig option is complicated due to
> >   allyesconfig builds. It's possible, but requires a verbose and
> >   confusing negative proxy config option.
> > 
> > - Naming the dependency tracking files with a dot prefix or placing them
> >   in a dot prefixed subdirectory in the build directory to hide them has
> >   been exceedingly difficult to achieve. (In part due to some Makefiles
> >   building files in subdirectory hierarchies.)
> > 
> > - The debate which headers, if any, should really be self-contained is
> >   virtually open-ended.
> 
> I would expect that headers in include/uapi/*.h should be self-contained,
> but apparently that's just a pipe dream on my part, or maybe it's just
> a maintainer option.
> 
> With 'make HEADER_CHECK="include/uapi/" headercheck'
> I see over 70 errors (mostly typedefs or defined constants, but not only
> those), such as:
> 
> In file included from <command-line>:
> ./../include/uapi/linux/hdlc/ioctl.h:74:21: error: ‘IFNAMSIZ’ undeclared here (not in a function)
>    74 |         char master[IFNAMSIZ];  /* Name of master FRAD device */
>       |                     ^~~~~~~~
> In file included from <command-line>:
> ./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
>    29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
>       |      ^~~~~~~~~~~~~~~
> ./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
>    34 |         __kernel_ulong_t __sec;
>       |         ^~~~~~~~~~~~~~~~
> In file included from ./../include/uapi/linux/papr_pdsm.h:14,
>                  from <command-line>:
> ../include/linux/ndctl.h:19:33: error: ‘PAGE_SIZE’ undeclared here (not in a function)
>    19 |         ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
>       |                                 ^~~~~~~~~
> In file included from <command-line>:
> ./../include/uapi/linux/patchkey.h:15:2: error: #error "patchkey.h included directly"
>    15 | #error "patchkey.h included directly"
>       |  ^~~~~
> In file included from <command-line>:
> include/uapi/xen/gntdev.h:159:25: error: unknown type name ‘grant_ref_t’
>   159 |                         grant_ref_t ref;
>       |                         ^~~~~~~~~~~
> include/uapi/xen/gntdev.h:161:25: error: unknown type name ‘domid_t’
>   161 |                         domid_t domid;
>       |                         ^~~~~~~

include/uapi already has its own header checking infrastructure under
CONFIG_UAPI_HEADER_TEST and usr/include/Makefile, which avoids this with
a no-header-test list that includes many of the files listed in these
messages. To be honest, we should probably forbid HEADER_CHECK from
including 'include/uapi' and refer people to use CONFIG_UAPI_HEADER_TEST
instead, as there are other differences like being built under a
different C standard or C++ and such that the existing infrastructure
handles.

That said, I think the overall idea seems fine and relatively clean, at
least from my Kbuild perspective, as it is completely opt in, so the
previous objection to CONFIG_HEADER_CHECK_DISABLE and widely exposing
this to builds is pretty much moot.

-- 
Cheers,
Nathan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-16 23:13   ` Nathan Chancellor
@ 2026-09-17  2:26     ` Randy Dunlap
  2026-09-17  8:14     ` Jani Nikula
  2026-09-17  9:05     ` Thomas Weißschuh
  2 siblings, 0 replies; 8+ messages in thread
From: Randy Dunlap @ 2026-09-17  2:26 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Jani Nikula, linux-kernel, Linus Torvalds, Nicolas Schier,
	Jason Gunthorpe, Masahiro Yamada, linux-kbuild



On 9/16/26 4:13 PM, Nathan Chancellor wrote:
> On Wed, Sep 16, 2026 at 03:24:09PM -0700, Randy Dunlap wrote:
>> On 9/15/26 3:43 AM, Jani Nikula wrote:
>>> There have been various attempts at adding a header test or check
>>> mechanism in the kernel build system. The header check primarily
>>> consists of ensuring headers are self-contained, have include guards,
>>> and, in some cases, pass kernel-doc.
>>>
>>> The main problems have been:
>>>
>>> - The dependency tracking creates undesirable artefacts (infamously also
>>>   known as disgusting turds) in the build directory.
>>>
>>> - Gating the feature behind a kconfig option is complicated due to
>>>   allyesconfig builds. It's possible, but requires a verbose and
>>>   confusing negative proxy config option.
>>>
>>> - Naming the dependency tracking files with a dot prefix or placing them
>>>   in a dot prefixed subdirectory in the build directory to hide them has
>>>   been exceedingly difficult to achieve. (In part due to some Makefiles
>>>   building files in subdirectory hierarchies.)
>>>
>>> - The debate which headers, if any, should really be self-contained is
>>>   virtually open-ended.
>>
>> I would expect that headers in include/uapi/*.h should be self-contained,
>> but apparently that's just a pipe dream on my part, or maybe it's just
>> a maintainer option.
>>
>> With 'make HEADER_CHECK="include/uapi/" headercheck'
>> I see over 70 errors (mostly typedefs or defined constants, but not only
>> those), such as:
>>
>> In file included from <command-line>:
>> ./../include/uapi/linux/hdlc/ioctl.h:74:21: error: ‘IFNAMSIZ’ undeclared here (not in a function)
>>    74 |         char master[IFNAMSIZ];  /* Name of master FRAD device */
>>       |                     ^~~~~~~~
>> In file included from <command-line>:
>> ./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
>>    29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
>>       |      ^~~~~~~~~~~~~~~
>> ./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
>>    34 |         __kernel_ulong_t __sec;
>>       |         ^~~~~~~~~~~~~~~~
>> In file included from ./../include/uapi/linux/papr_pdsm.h:14,
>>                  from <command-line>:
>> ../include/linux/ndctl.h:19:33: error: ‘PAGE_SIZE’ undeclared here (not in a function)
>>    19 |         ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
>>       |                                 ^~~~~~~~~
>> In file included from <command-line>:
>> ./../include/uapi/linux/patchkey.h:15:2: error: #error "patchkey.h included directly"
>>    15 | #error "patchkey.h included directly"
>>       |  ^~~~~
>> In file included from <command-line>:
>> include/uapi/xen/gntdev.h:159:25: error: unknown type name ‘grant_ref_t’
>>   159 |                         grant_ref_t ref;
>>       |                         ^~~~~~~~~~~
>> include/uapi/xen/gntdev.h:161:25: error: unknown type name ‘domid_t’
>>   161 |                         domid_t domid;
>>       |                         ^~~~~~~
> 
> include/uapi already has its own header checking infrastructure under
> CONFIG_UAPI_HEADER_TEST and usr/include/Makefile, which avoids this with
> a no-header-test list that includes many of the files listed in these
> messages. To be honest, we should probably forbid HEADER_CHECK from
> including 'include/uapi' and refer people to use CONFIG_UAPI_HEADER_TEST
> instead, as there are other differences like being built under a
> different C standard or C++ and such that the existing infrastructure
> handles.
> 

Thanks for the reminder. I'll limit any checking I do to non-uapi files.

> That said, I think the overall idea seems fine and relatively clean, at
> least from my Kbuild perspective, as it is completely opt in, so the
> previous objection to CONFIG_HEADER_CHECK_DISABLE and widely exposing
> this to builds is pretty much moot.
> 

-- 
~Randy


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-16 23:13   ` Nathan Chancellor
  2026-09-17  2:26     ` Randy Dunlap
@ 2026-09-17  8:14     ` Jani Nikula
  2026-09-17  9:05     ` Thomas Weißschuh
  2 siblings, 0 replies; 8+ messages in thread
From: Jani Nikula @ 2026-09-17  8:14 UTC (permalink / raw)
  To: Nathan Chancellor, Randy Dunlap
  Cc: linux-kernel, Linus Torvalds, Nicolas Schier, Jason Gunthorpe,
	Masahiro Yamada, linux-kbuild

On Wed, 16 Sep 2026, Nathan Chancellor <nathan@kernel.org> wrote:
> On Wed, Sep 16, 2026 at 03:24:09PM -0700, Randy Dunlap wrote:
>> On 9/15/26 3:43 AM, Jani Nikula wrote:
>> > There have been various attempts at adding a header test or check
>> > mechanism in the kernel build system. The header check primarily
>> > consists of ensuring headers are self-contained, have include guards,
>> > and, in some cases, pass kernel-doc.
>> > 
>> > The main problems have been:
>> > 
>> > - The dependency tracking creates undesirable artefacts (infamously also
>> >   known as disgusting turds) in the build directory.
>> > 
>> > - Gating the feature behind a kconfig option is complicated due to
>> >   allyesconfig builds. It's possible, but requires a verbose and
>> >   confusing negative proxy config option.
>> > 
>> > - Naming the dependency tracking files with a dot prefix or placing them
>> >   in a dot prefixed subdirectory in the build directory to hide them has
>> >   been exceedingly difficult to achieve. (In part due to some Makefiles
>> >   building files in subdirectory hierarchies.)
>> > 
>> > - The debate which headers, if any, should really be self-contained is
>> >   virtually open-ended.
>> 
>> I would expect that headers in include/uapi/*.h should be self-contained,
>> but apparently that's just a pipe dream on my part, or maybe it's just
>> a maintainer option.
>> 
>> With 'make HEADER_CHECK="include/uapi/" headercheck'
>> I see over 70 errors (mostly typedefs or defined constants, but not only
>> those), such as:
>> 
>> In file included from <command-line>:
>> ./../include/uapi/linux/hdlc/ioctl.h:74:21: error: ‘IFNAMSIZ’ undeclared here (not in a function)
>>    74 |         char master[IFNAMSIZ];  /* Name of master FRAD device */
>>       |                     ^~~~~~~~
>> In file included from <command-line>:
>> ./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
>>    29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
>>       |      ^~~~~~~~~~~~~~~
>> ./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
>>    34 |         __kernel_ulong_t __sec;
>>       |         ^~~~~~~~~~~~~~~~
>> In file included from ./../include/uapi/linux/papr_pdsm.h:14,
>>                  from <command-line>:
>> ../include/linux/ndctl.h:19:33: error: ‘PAGE_SIZE’ undeclared here (not in a function)
>>    19 |         ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
>>       |                                 ^~~~~~~~~
>> In file included from <command-line>:
>> ./../include/uapi/linux/patchkey.h:15:2: error: #error "patchkey.h included directly"
>>    15 | #error "patchkey.h included directly"
>>       |  ^~~~~
>> In file included from <command-line>:
>> include/uapi/xen/gntdev.h:159:25: error: unknown type name ‘grant_ref_t’
>>   159 |                         grant_ref_t ref;
>>       |                         ^~~~~~~~~~~
>> include/uapi/xen/gntdev.h:161:25: error: unknown type name ‘domid_t’
>>   161 |                         domid_t domid;
>>       |                         ^~~~~~~
>
> include/uapi already has its own header checking infrastructure under
> CONFIG_UAPI_HEADER_TEST and usr/include/Makefile, which avoids this with
> a no-header-test list that includes many of the files listed in these
> messages. To be honest, we should probably forbid HEADER_CHECK from
> including 'include/uapi' and refer people to use CONFIG_UAPI_HEADER_TEST
> instead, as there are other differences like being built under a
> different C standard or C++ and such that the existing infrastructure
> handles.

Something like this on top would fail if there are any include/uapi
headers in there:

diff --git a/Makefile b/Makefile
index 4851a4407149..77253506975e 100644
--- a/Makefile
+++ b/Makefile
@@ -1554,6 +1554,7 @@ header-check-targets := $(patsubst %.h,%.header-check,$(sort $(header-check-file
 
 headercheck:
 	$(if $(header-check-targets),,$(error $@ found no headers in HEADER_CHECK="$(HEADER_CHECK)"))
+	$(if $(filter include/uapi/%,$(header-check-targets)),$(error $@ found include/uapi headers in HEADER_CHECK="$(HEADER_CHECK)"))
 	$(Q)$(MAKE) $(header-check-targets)
 else
 headercheck:


I'll wait a bit for more feedback before sending a v2.

> That said, I think the overall idea seems fine and relatively clean, at
> least from my Kbuild perspective, as it is completely opt in, so the
> previous objection to CONFIG_HEADER_CHECK_DISABLE and widely exposing
> this to builds is pretty much moot.

Thanks Nathan and Randy, this feels encouraging. :)

BR,
Jani.

-- 
Jani Nikula, Intel

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-16 23:13   ` Nathan Chancellor
  2026-09-17  2:26     ` Randy Dunlap
  2026-09-17  8:14     ` Jani Nikula
@ 2026-09-17  9:05     ` Thomas Weißschuh
  2026-09-17 11:58       ` Jason Gunthorpe
  2026-09-17 17:17       ` Nathan Chancellor
  2 siblings, 2 replies; 8+ messages in thread
From: Thomas Weißschuh @ 2026-09-17  9:05 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Randy Dunlap, Jani Nikula, linux-kernel, Linus Torvalds,
	Nicolas Schier, Jason Gunthorpe, Masahiro Yamada, linux-kbuild

On 2026-09-16 16:13:19-0700, Nathan Chancellor wrote:
> On Wed, Sep 16, 2026 at 03:24:09PM -0700, Randy Dunlap wrote:
> > On 9/15/26 3:43 AM, Jani Nikula wrote:
> > > There have been various attempts at adding a header test or check
> > > mechanism in the kernel build system. The header check primarily
> > > consists of ensuring headers are self-contained, have include guards,
> > > and, in some cases, pass kernel-doc.
> > > 
> > > The main problems have been:
> > > 
> > > - The dependency tracking creates undesirable artefacts (infamously also
> > >   known as disgusting turds) in the build directory.
> > > 
> > > - Gating the feature behind a kconfig option is complicated due to
> > >   allyesconfig builds. It's possible, but requires a verbose and
> > >   confusing negative proxy config option.
> > > 
> > > - Naming the dependency tracking files with a dot prefix or placing them
> > >   in a dot prefixed subdirectory in the build directory to hide them has
> > >   been exceedingly difficult to achieve. (In part due to some Makefiles
> > >   building files in subdirectory hierarchies.)
> > > 
> > > - The debate which headers, if any, should really be self-contained is
> > >   virtually open-ended.
> > 
> > I would expect that headers in include/uapi/*.h should be self-contained,
> > but apparently that's just a pipe dream on my part, or maybe it's just
> > a maintainer option.
> > 
> > With 'make HEADER_CHECK="include/uapi/" headercheck'
> > I see over 70 errors (mostly typedefs or defined constants, but not only
> > those), such as:
> > 
> > In file included from <command-line>:
> > ./../include/uapi/linux/hdlc/ioctl.h:74:21: error: ‘IFNAMSIZ’ undeclared here (not in a function)
> >    74 |         char master[IFNAMSIZ];  /* Name of master FRAD device */
> >       |                     ^~~~~~~~
> > In file included from <command-line>:
> > ./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
> >    29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
> >       |      ^~~~~~~~~~~~~~~
> > ./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
> >    34 |         __kernel_ulong_t __sec;
> >       |         ^~~~~~~~~~~~~~~~
> > In file included from ./../include/uapi/linux/papr_pdsm.h:14,
> >                  from <command-line>:
> > ../include/linux/ndctl.h:19:33: error: ‘PAGE_SIZE’ undeclared here (not in a function)
> >    19 |         ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
> >       |                                 ^~~~~~~~~
> > In file included from <command-line>:
> > ./../include/uapi/linux/patchkey.h:15:2: error: #error "patchkey.h included directly"
> >    15 | #error "patchkey.h included directly"
> >       |  ^~~~~
> > In file included from <command-line>:
> > include/uapi/xen/gntdev.h:159:25: error: unknown type name ‘grant_ref_t’
> >   159 |                         grant_ref_t ref;
> >       |                         ^~~~~~~~~~~
> > include/uapi/xen/gntdev.h:161:25: error: unknown type name ‘domid_t’
> >   161 |                         domid_t domid;
> >       |                         ^~~~~~~
> 
> include/uapi already has its own header checking infrastructure under
> CONFIG_UAPI_HEADER_TEST and usr/include/Makefile, which avoids this with
> a no-header-test list that includes many of the files listed in these
> messages. To be honest, we should probably forbid HEADER_CHECK from
> including 'include/uapi' and refer people to use CONFIG_UAPI_HEADER_TEST
> instead, as there are other differences like being built under a
> different C standard or C++ and such that the existing infrastructure
> handles.

Testing the UAPI headers here too would still be valuable.
CONFIG_UAPI_HEADER_TEST tests the headers from the perspective of
userspace after they have undergone processing. The kernel build
might see the same headers quite differently.

For instance the example from above:

./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
   29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
      |      ^~~~~~~~~~~~~~~
./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
   34 |         __kernel_ulong_t __sec;
      |         ^~~~~~~~~~~~~~~~

These are legitimate issues, the inclusion of the necessary header is
gated behind #ifndef __KERNEL__ although it should not be.

(...)


Thomas

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-17  9:05     ` Thomas Weißschuh
@ 2026-09-17 11:58       ` Jason Gunthorpe
  2026-09-17 17:17       ` Nathan Chancellor
  1 sibling, 0 replies; 8+ messages in thread
From: Jason Gunthorpe @ 2026-09-17 11:58 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Nathan Chancellor, Randy Dunlap, Jani Nikula, linux-kernel,
	Linus Torvalds, Nicolas Schier, Masahiro Yamada, linux-kbuild

On Thu, Sep 17, 2026 at 11:05:32AM +0200, Thomas Weißschuh wrote:
> For instance the example from above:
> 
> ./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
>    29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
>       |      ^~~~~~~~~~~~~~~
> ./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
>    34 |         __kernel_ulong_t __sec;
>       |         ^~~~~~~~~~~~~~~~
> 
> These are legitimate issues, the inclusion of the necessary header is
> gated behind #ifndef __KERNEL__ although it should not be.

Yeah, if the header is included by a kernel file then this makefile
test should evaluate it under those conditions, and it should still be
self-contained within the kernel environment.. Wasn't that one of the
problems with earlier draft that it did not figure out the right
compilation options for the context the header is included in?

FWIW I think this is a reasonable compromise too

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kbuild: add header check facility as a manually run static analyzer
  2026-09-17  9:05     ` Thomas Weißschuh
  2026-09-17 11:58       ` Jason Gunthorpe
@ 2026-09-17 17:17       ` Nathan Chancellor
  1 sibling, 0 replies; 8+ messages in thread
From: Nathan Chancellor @ 2026-09-17 17:17 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Randy Dunlap, Jani Nikula, linux-kernel, Linus Torvalds,
	Nicolas Schier, Jason Gunthorpe, Masahiro Yamada, linux-kbuild

On Thu, Sep 17, 2026 at 11:05:32AM +0200, Thomas Weißschuh wrote:
> On 2026-09-16 16:13:19-0700, Nathan Chancellor wrote:
> > include/uapi already has its own header checking infrastructure under
> > CONFIG_UAPI_HEADER_TEST and usr/include/Makefile, which avoids this with
> > a no-header-test list that includes many of the files listed in these
> > messages. To be honest, we should probably forbid HEADER_CHECK from
> > including 'include/uapi' and refer people to use CONFIG_UAPI_HEADER_TEST
> > instead, as there are other differences like being built under a
> > different C standard or C++ and such that the existing infrastructure
> > handles.
> 
> Testing the UAPI headers here too would still be valuable.
> CONFIG_UAPI_HEADER_TEST tests the headers from the perspective of
> userspace after they have undergone processing. The kernel build
> might see the same headers quite differently.
> 
> For instance the example from above:
> 
> ./../include/uapi/linux/input.h:29:6: warning: ‘__BITS_PER_LONG’ is not defined, evaluates to ‘0’ [-Wundef]
>    29 | #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
>       |      ^~~~~~~~~~~~~~~
> ./../include/uapi/linux/input.h:34:9: error: unknown type name ‘__kernel_ulong_t’
>    34 |         __kernel_ulong_t __sec;
>       |         ^~~~~~~~~~~~~~~~
> 
> These are legitimate issues, the inclusion of the necessary header is
> gated behind #ifndef __KERNEL__ although it should not be.

Hmmm, fair enough. I guess we can leave this functionality in place for
UAPI headers then but I just worry about people doing what Randy did and
reporting these issues when they are already known and handled in some
other way. Maybe the UAPI header test could grow an "internal kernel
usage" check similar to the other checks that it has at some point then
we could forbid HEADER_CHECK=include/uapi but it is fine for now.

-- 
Cheers,
Nathan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-17 17:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-15 10:43 [PATCH] kbuild: add header check facility as a manually run static analyzer Jani Nikula
2026-09-16 22:24 ` Randy Dunlap
2026-09-16 23:13   ` Nathan Chancellor
2026-09-17  2:26     ` Randy Dunlap
2026-09-17  8:14     ` Jani Nikula
2026-09-17  9:05     ` Thomas Weißschuh
2026-09-17 11:58       ` Jason Gunthorpe
2026-09-17 17:17       ` Nathan Chancellor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®