Linux kbuild/kconfig development
 help / color / mirror / Atom feed
* [PATCH 0/1] kbuild: record real-prereqs in .cmd files
@ 2026-08-14 11:21 Luis Augenstein
  2026-08-14 11:21 ` [PATCH 1/1] " Luis Augenstein
  0 siblings, 1 reply; 5+ messages in thread
From: Luis Augenstein @ 2026-08-14 11:21 UTC (permalink / raw)
  To: nathan, nsc
  Cc: linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
	maximilian.huber, Luis Augenstein

KernelSbom (scripts/sbom/sbom.py) reconstructs the kernel build graph
from the .cmd files written by Kbuild. For most build outputs,
KernelSbom must infer the build inputs from the shell command stored in
savedcmd_*. This requires command-specific parsers, which add
unnecessary complexity and are difficult to maintain.

Kbuild already knows these inputs as $(real-prereqs), the non-phony
prerequisites of the Make rule. This patch records them in .cmd files
using a new metadata field:

    make_prereqs_<target> := <prerequisites>

KernelSbom will be able to read the new field instead of parsing the
shell command. This submission only records the field, support for using
it in KernelSbom will follow separately.

The issue of manually parsing shell commands was originally mentioned in
https://lore.kernel.org/r/a01233b9-23a2-4666-91ed-f1cf030dcb9f@tngtech.com.
This patch is a proposal to address that.

Cmd writers and consumers
=========================

The new field should not affect existing behavior. 
Below is a summary of what I checked.

.cmd files are primarily written by cmd_and_savecmd and cmd_and_fixdep.
This patch extends both writers to add make_prereqs_*.

The following rules append information to existing .cmd files.
None of these is affected by the new field:

- scripts/Makefile.lib: cmd_gen_objtooldep only appends new rule
  target: $(wildcard ./tools/objtool/objtool)
- scripts/Makefile.build: gen_symversions only appends comments
  #SYMVER <name> <crc>
- scripts/Makefile.lib: cmd_save_c_flags only appends a variable
  saved_c_flags_<target> := <flags>
- rust/Makefile: cmd_gendwarfksyms only appends comments
  #SYMVER <name> <crc>
- kernel/Makefile: kheaders_data_dep appends a deps_* block
  deps_<target> := <headers>.

This patch updates the following .cmd file consumers to account for the
new field:

- scripts/sbom/sbom/cmd_graph/cmd_file.py: CmdFile.create() parses
  savedcmd_<target>, source_<target>, and deps_<target>. It is updated
  to ignore make_prereqs_<target> for now. Parsing the new field will
  follow in a separate patch.
- scripts/make_fit.py: process_dtb() previously read and split the
  complete .cmd file to find the fdtoverlay command. It is changed to
  read only savedcmd_<target>.

The remaining consumers are not affected:

- Kbuild Makefiles: -include reads .cmd files as Makefile fragments. The
  new field is an ordinary variable assignment not used in any dependency
  rule.
- scripts/Makefile.thinlto: the saved_c_flags_* lookup only reads
  saved_c_flags_<target> := <flags>.
- scripts/mod/modpost.c: extract_crcs_for_object() only reads comments
  #SYMVER <name> <crc>.
- scripts/mod/sumversion.c: parse_source_files() only reads
  source_<target> := <source> and deps_<target> := <dependencies>.
- scripts/clang-tools/gen_compile_commands.py: main() only reads the
  first line containing savedcmd_<target> := <command>.
- scripts/generate_builtin_ranges.awk and
  scripts/verify_builtin_ranges.awk: get_module_info() only reads the
  first line and searches the saved command for DKBUILD_MODFILE or
  RUST_MODFILE.

Alternative: extending the deps_* field
=======================================

An alternative to the new make_prereqs_* field is to merge $(real-prereqs)
into the existing deps_* field for both cmd_and_savecmd and cmd_and_fixdep.
This would avoid a new field and provide one dependency list. However, it
would broaden the meaning of deps_* from dependencies discovered through
generated .d files to include prerequisites already declared to Make.
This increases the risk of undesired side effects.

The writers listed above would need to ensure that each .cmd file
contains only one deps_* block. In particular, kheaders_data_dep would
need to merge its header dependencies into the block written by
cmd_and_savecmd instead of appending a second deps_* block.
cmd_and_fixdep, or fixdep.c depending on the implementation, would
likewise need to merge $(real-prereqs) with the generated dependencies.

Apart from KernelSbom, scripts/mod/sumversion.c is the only consumer
that explicitly reads deps_*. It uses selected dependency files to
calculate a module's srcversion. Extending deps_* could change this
module metadata. Such an unrelated change should probably be avoided.

Kbuild Makefiles also consume deps_* by including .cmd files. This
should not be an issue though, because $(real-prereqs) are already
present on the original target rule, so repeating them through deps_*
should not change rebuild behavior.

Luis Augenstein (1):
  kbuild: record real-prereqs in .cmd files

 scripts/Kbuild.include                  |  9 +++++++--
 scripts/basic/fixdep.c                  | 16 ++++++++++------
 scripts/make_fit.py                     |  2 +-
 scripts/sbom/sbom/cmd_graph/cmd_file.py |  4 ++++
 4 files changed, 22 insertions(+), 9 deletions(-)

-- 
2.43.0


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

* [PATCH 1/1] kbuild: record real-prereqs in .cmd files
  2026-08-14 11:21 [PATCH 0/1] kbuild: record real-prereqs in .cmd files Luis Augenstein
@ 2026-08-14 11:21 ` Luis Augenstein
  2026-08-18 19:51   ` Nathan Chancellor
  0 siblings, 1 reply; 5+ messages in thread
From: Luis Augenstein @ 2026-08-14 11:21 UTC (permalink / raw)
  To: nathan, nsc
  Cc: linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
	maximilian.huber, Luis Augenstein

Record $(real-prereqs), the non-phony prerequisites of the target, in a
new metadata field:

    make_prereqs_<target> := <prerequisites>

Write the field from both cmd_and_savecmd and cmd_and_fixdep.

Update scripts/make_fit.py to read only savedcmd_* instead of parsing the
complete .cmd file.

Ignore make_prereqs_* in KernelSbom.

Link: https://lore.kernel.org/r/a01233b9-23a2-4666-91ed-f1cf030dcb9f@tngtech.com
Assisted-by: Cursor:GPT-5.6 Sol
Co-developed-by: Maximilian Huber <maximilian.huber@tngtech.com>
Signed-off-by: Maximilian Huber <maximilian.huber@tngtech.com>
Signed-off-by: Luis Augenstein <luis.augenstein@tngtech.com>
---
 scripts/Kbuild.include                  |  9 +++++++--
 scripts/basic/fixdep.c                  | 16 ++++++++++------
 scripts/make_fit.py                     |  2 +-
 scripts/sbom/sbom/cmd_graph/cmd_file.py |  4 ++++
 4 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 8c311b997e2..6daa244ba0e 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -181,6 +181,9 @@ endif
 # (needed for the shell)
 make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
 
+# prerequisites to record in .cmd files, excluding those covered in deps_*
+cmd-prereqs = $(call escsq,$(filter-out $(deps_$@), $(real-prereqs)))
+
 # Find any prerequisites that are newer than target or that do not exist.
 # PHONY targets skipped in both cases.
 # If there is no prerequisite other than phony targets, $(newer-prereqs) becomes
@@ -198,14 +201,16 @@ if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:)
 
 cmd_and_savecmd =                                                            \
 	$(cmd);                                                              \
-	printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd
+	printf '%s\n\n%s\n' 'savedcmd_$@ := $(make-cmd)'                    \
+		'make_prereqs_$@ := $(cmd-prereqs)' > $(dot-target).cmd
 
 # Execute the command and also postprocess generated .d dependencies file.
 if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:)
 
 cmd_and_fixdep =                                                             \
 	$(cmd);                                                              \
-	$(objtree)/scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
+	$(objtree)/scripts/basic/fixdep $(depfile) $@ '$(make-cmd)'          \
+		'$(cmd-prereqs)' > $(dot-target).cmd;                        \
 	rm -f $(depfile)
 
 # Usage: $(call if_changed_rule,foo)
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index cdd5da7e009..03831a6f8f7 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -62,15 +62,17 @@
  *
  * It is invoked as
  *
- *   fixdep <depfile> <target> <cmdline>
+ *   fixdep <depfile> <target> <cmdline> <prereqs>
  *
  * and will read the dependency file <depfile>
  *
  * The transformed dependency snipped is written to stdout.
  *
- * It first generates a line
+ * It first generates the lines
  *
- *   savedcmd_<target> = <cmdline>
+ *   savedcmd_<target> := <cmdline>
+ *
+ *   make_prereqs_<target> := <prereqs>
  *
  * and then basically copies the .<target>.d file to stdout, in the
  * process filtering out the dependency on autoconf.h and adding
@@ -103,7 +105,7 @@
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline> <prereqs>\n");
 	exit(1);
 }
 
@@ -409,17 +411,19 @@ static void parse_dep_file(char *p, const char *target)
 
 int main(int argc, char *argv[])
 {
-	const char *depfile, *target, *cmdline;
+	const char *depfile, *target, *cmdline, *prereqs;
 	void *buf;
 
-	if (argc != 4)
+	if (argc != 5)
 		usage();
 
 	depfile = argv[1];
 	target = argv[2];
 	cmdline = argv[3];
+	prereqs = argv[4];
 
 	printf("savedcmd_%s := %s\n\n", target, cmdline);
+	printf("make_prereqs_%s := %s\n\n", target, prereqs);
 
 	buf = read_file(depfile);
 	parse_dep_file(buf, target);
diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 15ba26974fd..346e8a7ec12 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -288,7 +288,7 @@ def process_dtb(fname, args):
         path, basename = os.path.split(fname)
         cmd_fname = os.path.join(path, f'.{basename}.cmd')
         with open(cmd_fname, 'r', encoding='ascii') as inf:
-            cmd = inf.read()
+            cmd = inf.readline()
 
         if 'scripts/dtc/fdtoverlay' in cmd:
             # This depends on the structure of the composite DTB command
diff --git a/scripts/sbom/sbom/cmd_graph/cmd_file.py b/scripts/sbom/sbom/cmd_graph/cmd_file.py
index dcd63e284a3..08819b4d117 100644
--- a/scripts/sbom/sbom/cmd_graph/cmd_file.py
+++ b/scripts/sbom/sbom/cmd_graph/cmd_file.py
@@ -50,6 +50,10 @@ class CmdFile:
         with open(cmd_file_path, "rt", encoding="utf-8") as f:
             lines = [line.strip() for line in f.readlines() if line.strip() != "" and not line.startswith("#")]
 
+        # make_prereqs_* is recorded for future use. Ignore it for now to
+        # preserve the existing parser behavior.
+        lines = [line for line in lines if not line.startswith("make_prereqs_")]
+
         # savedcmd
         match = SAVEDCMD_PATTERN.match(lines[0] if lines else "")
         if match is None:
-- 
2.43.0


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

* Re: [PATCH 1/1] kbuild: record real-prereqs in .cmd files
  2026-08-14 11:21 ` [PATCH 1/1] " Luis Augenstein
@ 2026-08-18 19:51   ` Nathan Chancellor
  2026-08-21 19:57     ` Luis Augenstein
  0 siblings, 1 reply; 5+ messages in thread
From: Nathan Chancellor @ 2026-08-18 19:51 UTC (permalink / raw)
  To: Luis Augenstein
  Cc: nathan, nsc, linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
	maximilian.huber

> Record $(real-prereqs), the non-phony prerequisites of the target, in a
> new metadata field:
> 
>     make_prereqs_<target> := <prerequisites>
> 
> Write the field from both cmd_and_savecmd and cmd_and_fixdep.
> 
> Update scripts/make_fit.py to read only savedcmd_* instead of parsing the
> complete .cmd file.
> 
> Ignore make_prereqs_* in KernelSbom.
> 
> Link: https://lore.kernel.org/r/a01233b9-23a2-4666-91ed-f1cf030dcb9f@tngtech.com
> Assisted-by: Cursor:GPT-5.6 Sol
> Co-developed-by: Maximilian Huber <maximilian.huber@tngtech.com>
> Signed-off-by: Maximilian Huber <maximilian.huber@tngtech.com>
> Signed-off-by: Luis Augenstein <luis.augenstein@tngtech.com>
>
> diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
> index 8c311b997e24..6daa244ba0ef 100644
> --- a/scripts/Kbuild.include
> +++ b/scripts/Kbuild.include
> @@ -181,6 +181,9 @@ endif
>  # (needed for the shell)
>  make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
>  
> +# prerequisites to record in .cmd files, excluding those covered in deps_*
> +cmd-prereqs = $(call escsq,$(filter-out $(deps_$@), $(real-prereqs)))

Sashiko has a comment that this produces different results based on a
clean versus incremental build:

  https://sashiko.dev/#/patchset/59032

I can reproduce this with:

  $ make -skj"$(nproc)" ARCH=x86_64 mrproper defconfig lib/oid_registry.o

  $ grep -n oid_registry_data lib/.oid_registry.o.cmd
  3:make_prereqs_lib/oid_registry.o := lib/oid_registry.c lib/oid_registry_data.c
  1111:  lib/oid_registry_data.c \

  $ touch lib/oid_registry.c

  $ make -skj"$(nproc)" ARCH=x86_64 lib/oid_registry.o

  $ grep -n oid_registry_data lib/.oid_registry.o.cmd
  1111:  lib/oid_registry_data.c \

As this is just metadata for external tools (i.e., it does not get
consumed by Kbuild again), we could just require them to filter
duplicates after the fact?

-- 
Cheers,
Nathan


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

* Re: [PATCH 1/1] kbuild: record real-prereqs in .cmd files
  2026-08-18 19:51   ` Nathan Chancellor
@ 2026-08-21 19:57     ` Luis Augenstein
  2026-08-25  3:22       ` Nathan Chancellor
  0 siblings, 1 reply; 5+ messages in thread
From: Luis Augenstein @ 2026-08-21 19:57 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: nsc, linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
	maximilian.huber


[-- Attachment #1.1: Type: text/plain, Size: 1686 bytes --]



On 8/18/26 21:51, Nathan Chancellor wrote:
> Sashiko has a comment that this produces different results based on a
> clean versus incremental build:
> 
>    https://sashiko.dev/#/patchset/59032
> 
> I can reproduce this with:
> 
>    $ make -skj"$(nproc)" ARCH=x86_64 mrproper defconfig lib/oid_registry.o
> 
>    $ grep -n oid_registry_data lib/.oid_registry.o.cmd
>    3:make_prereqs_lib/oid_registry.o := lib/oid_registry.c lib/oid_registry_data.c
>    1111:  lib/oid_registry_data.c \
> 
>    $ touch lib/oid_registry.c
> 
>    $ make -skj"$(nproc)" ARCH=x86_64 lib/oid_registry.o
> 
>    $ grep -n oid_registry_data lib/.oid_registry.o.cmd
>    1111:  lib/oid_registry_data.c \
> 
> As this is just metadata for external tools (i.e., it does not get
> consumed by Kbuild again), we could just require them to filter
> duplicates after the fact?

True, some Make prerequisites also appear in deps_*, so the filter
dropped them from make_prereqs_* on incremental builds.

However, we cannot just remove the filter. After the .cmd is included,
$(real-prereqs) contains $(deps_$@), so the whole deps_* list would
show up in make_prereqs_* on a rebuild.

We could move the filter into fixdep and filter based on the new .d 
file, so the overlap is removed already on a clean build.

thanks,
Luis

-- 
Luis Augenstein * luis.augenstein@tngtech.com * +4915225275761
TNG Technology Consulting GmbH, Beta-Str. 13, 85774 Unterföhring
Geschäftsführer: Dr. Robert Dahlke, Thomas Endres, Moritz Prinz
Aufsichtsratsvorsitzender: Henrik Klagges
Sitz: Unterföhring * Registergericht: Amtsgericht München * 
Handelsregisternummer: HRB 135082


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 1/1] kbuild: record real-prereqs in .cmd files
  2026-08-21 19:57     ` Luis Augenstein
@ 2026-08-25  3:22       ` Nathan Chancellor
  0 siblings, 0 replies; 5+ messages in thread
From: Nathan Chancellor @ 2026-08-25  3:22 UTC (permalink / raw)
  To: Luis Augenstein
  Cc: nsc, linux-kbuild, linux-kernel, akpm, gregkh, kstewart,
	maximilian.huber

On Fri, Aug 21, 2026 at 09:57:03PM +0200, Luis Augenstein wrote:
> True, some Make prerequisites also appear in deps_*, so the filter
> dropped them from make_prereqs_* on incremental builds.
> 
> However, we cannot just remove the filter. After the .cmd is included,
> $(real-prereqs) contains $(deps_$@), so the whole deps_* list would
> show up in make_prereqs_* on a rebuild.

Ah, makes sense.

> We could move the filter into fixdep and filter based on the new .d file, so
> the overlap is removed already on a clean build.

If this is not that complicated, I would not mind seeing what it looked
like.

-- 
Cheers,
Nathan

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

end of thread, other threads:[~2026-08-25  3:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 11:21 [PATCH 0/1] kbuild: record real-prereqs in .cmd files Luis Augenstein
2026-08-14 11:21 ` [PATCH 1/1] " Luis Augenstein
2026-08-18 19:51   ` Nathan Chancellor
2026-08-21 19:57     ` Luis Augenstein
2026-08-25  3:22       ` Nathan Chancellor

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