From: Luis Augenstein <luis.augenstein@tngtech.com>
To: nathan@kernel.org, nsc@kernel.org
Cc: linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org,
akpm@linux-foundation.org, gregkh@linuxfoundation.org,
kstewart@linuxfoundation.org, maximilian.huber@tngtech.com,
Luis Augenstein <luis.augenstein@tngtech.com>
Subject: [PATCH v3 6/7] scripts/sbom: use make_prereqs to determine build inputs
Date: Mon, 12 Oct 2026 23:33:21 +0200 [thread overview]
Message-ID: <20261012213337.2466524-7-luis.augenstein@tngtech.com> (raw)
In-Reply-To: <20261012213337.2466524-1-luis.augenstein@tngtech.com>
Build the list of file dependencies of a target from the
make_prereqs_<target> field and the deps_<target> entries of the .cmd
file instead of parsing the shell command stored in savedcmd_.
The prerequisites include more than KernelSbom wants to track: files
should be tracked if they end up in the kernel image or loadable
modules, but not each and every host tool or helper script used to
build them. Add a manually maintained exclude list for such
dependencies. It is still manual, but much easier to maintain than
the command-specific parsers that were needed to extract the relevant
inputs from each individual build command.
Assisted-by: LLM
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/sbom/sbom/cmd_graph/cmd_file.py | 46 ++-----------
.../sbom/sbom/cmd_graph/dependency_filter.py | 59 +++++++++++++++++
scripts/sbom/sbom/spdx_graph/kernel_file.py | 64 ++++++++++++-------
3 files changed, 105 insertions(+), 64 deletions(-)
create mode 100644 scripts/sbom/sbom/cmd_graph/dependency_filter.py
diff --git a/scripts/sbom/sbom/cmd_graph/cmd_file.py b/scripts/sbom/sbom/cmd_graph/cmd_file.py
index cc576c7c6be..ab4b00b252b 100644
--- a/scripts/sbom/sbom/cmd_graph/cmd_file.py
+++ b/scripts/sbom/sbom/cmd_graph/cmd_file.py
@@ -5,7 +5,7 @@ import os
import re
from dataclasses import dataclass, field
from sbom.cmd_graph.deps_parser import parse_cmd_file_deps
-from sbom.cmd_graph.savedcmd_parser import parse_inputs_from_commands
+from sbom.cmd_graph.dependency_filter import should_include_dependency
import sbom.sbom_logging as sbom_logging
from sbom.path_utils import PathStr
@@ -85,51 +85,17 @@ class CmdFile:
Returns:
list[PathStr]: dependency file paths relative to `obj_tree`.
"""
- input_files: list[PathStr] = [
- str(p) for p in parse_inputs_from_commands(self.savedcmd, fail_on_unknown_build_command)
- ]
+ input_files: list[PathStr] = list(self.make_prereqs)
+
if self.deps:
input_files += [str(p) for p in parse_cmd_file_deps(self.deps)]
- input_files = _expand_resolve_files(input_files, obj_tree)
cmd_file_dependencies: list[PathStr] = []
for input_file in input_files:
- # input files are either absolute or relative to the object tree
+ # input files are either absolute or already relative to the object tree
if os.path.isabs(input_file):
input_file = os.path.relpath(input_file, obj_tree)
- if input_file == target_path:
- # Skip target file to prevent cycles. This is necessary because some multi stage commands first create an output and then pass it as input to the next command, e.g., objcopy.
- continue
- cmd_file_dependencies.append(input_file)
+ if should_include_dependency(input_file):
+ cmd_file_dependencies.append(input_file)
unique_cmd_file_dependencies = list(dict.fromkeys(cmd_file_dependencies))
return unique_cmd_file_dependencies
-
-
-def _expand_resolve_files(input_files: list[PathStr], obj_tree: PathStr) -> list[PathStr]:
- """
- Expands resolve files which may reference additional files via '@' notation.
-
- Args:
- input_files (list[PathStr]): List of file paths relative to the object tree, where paths starting with '@' refer to files
- containing further file paths, each on a separate line.
- obj_tree: Absolute path to the root of the object tree.
-
- Returns:
- list[PathStr]: Flattened list of all input file paths, with any nested '@' file references resolved recursively.
- """
- expanded_input_files: list[PathStr] = []
- for input_file in input_files:
- if not input_file.startswith("@"):
- expanded_input_files.append(input_file)
- continue
- resolve_file_path = os.path.join(obj_tree, input_file.removeprefix("@"))
- if not os.path.exists(resolve_file_path):
- sbom_logging.error(
- "Skip resolving '{resolve_file_path}' because the response file does not exist.",
- resolve_file_path=resolve_file_path,
- )
- continue
- with open(resolve_file_path, "rt", encoding="utf-8") as f:
- resolve_file_content = [line_stripped for line in f.readlines() if (line_stripped := line.strip())]
- expanded_input_files += _expand_resolve_files(resolve_file_content, obj_tree)
- return expanded_input_files
diff --git a/scripts/sbom/sbom/cmd_graph/dependency_filter.py b/scripts/sbom/sbom/cmd_graph/dependency_filter.py
new file mode 100644
index 00000000000..f1fdc2cb965
--- /dev/null
+++ b/scripts/sbom/sbom/cmd_graph/dependency_filter.py
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0-only OR MIT
+# Copyright (C) 2025 TNG Technology Consulting GmbH
+
+import re
+
+from sbom.path_utils import PathStr
+
+# Regex patterns for dependencies that should not be tracked in the dependency graph.
+_COMPILED_EXCLUDE_PATTERNS: tuple[re.Pattern[str], ...] = (
+ # scripts in source tree (except module-common.c, which is compiled into every module)
+ re.compile(r"^\.\./scripts/(?!module-common\.c$)"),
+ # scripts and tools in obj tree
+ re.compile(r"^scripts/"),
+ re.compile(r"^tools/"),
+ re.compile(r"^arch/[^/]+/tools/"),
+ # Host helper scripts
+ re.compile(r".*\.sh$"),
+ re.compile(r".*\.py$"),
+ re.compile(r".*\.pl$"),
+ # Host-tool executables
+ re.compile(r"^certs/extract-cert$"),
+ re.compile(r"^security/selinux/genheaders$"),
+ re.compile(r"^usr/gen_init_cpio$"),
+ re.compile(r"^drivers/gpu/drm/radeon/mkregtable$"),
+ re.compile(r"^drivers/video/logo/pnmtologo$"),
+ re.compile(r"^lib/raid/raid6/mktables$"),
+ re.compile(r"^\.\./fs/smb/client/gen_smb1_mapping$"),
+ re.compile(r"^\.\./fs/smb/client/gen_smb2_mapping$"),
+ # Other
+ re.compile(r".*\.xsd$"),
+ re.compile(r".*purgatory\.chk$"),
+ re.compile(r".*\.genkey$"),
+ re.compile(r".*\.md$"),
+ re.compile(r"^include/config/"),
+ # x86
+ re.compile(r"^arch/x86/boot/compressed/mkpiggy$"),
+ re.compile(r"^arch/x86/boot/mkcpustr$"),
+ # arm
+ re.compile(r"^arch/arm/vdso/vdsomunge$"),
+ # arm64
+ re.compile(r"^arch/arm64/kvm/hyp/nvhe/gen-hyprel$"),
+ re.compile(r"^arch/arm64/kernel/pi/relacheck$"),
+)
+
+def should_include_dependency(path: PathStr) -> bool:
+ """
+ Return whether a `.cmd` dependency should appear in the tracked dependency graph.
+
+ Track files that are inputs to compiling or linking artifacts that end up in the
+ kernel image or loadable modules (e.g. source → object → archive → image/module).
+ Exclude host tools and helper scripts whose code is not linked into the kernel.
+
+ Args:
+ path: Dependency path relative to the object tree.
+
+ Returns:
+ True if the dependency should be included in the dependency graph.
+ """
+ return not any(pattern.match(path) for pattern in _COMPILED_EXCLUDE_PATTERNS)
diff --git a/scripts/sbom/sbom/spdx_graph/kernel_file.py b/scripts/sbom/sbom/spdx_graph/kernel_file.py
index 505f25f66eb..cea14cb3538 100644
--- a/scripts/sbom/sbom/spdx_graph/kernel_file.py
+++ b/scripts/sbom/sbom/spdx_graph/kernel_file.py
@@ -245,7 +245,7 @@ def _get_primary_purpose(absolute_path: PathStr) -> SoftwarePurpose | None:
return any(segment in absolute_path for segment in path_segments)
# Source code
- if ends_with([".c", ".h", ".S", ".s", ".rs", ".pl", "gen_smb1_mapping", "gen_smb2_mapping"]):
+ if ends_with([".c", ".h", ".S", ".s", ".rs"]):
return "source"
# Libraries
@@ -271,45 +271,61 @@ def _get_primary_purpose(absolute_path: PathStr) -> SoftwarePurpose | None:
# Data files
if ends_with(
[
- ".tbl",
- ".relocs",
- ".rmeta",
- ".in",
+ ".awk",
".dbg",
- ".x509",
- ".pbm",
- ".ppm",
".dtb",
- ".uc",
- ".inc",
+ ".dtbo",
".dts",
".dtsi",
- ".dtbo",
- ".xml",
+ ".dtso",
+ ".in",
+ ".inc",
+ ".json",
+ ".ld",
+ ".lds",
+ ".mod",
+ ".order",
+ ".pbm",
+ ".ppm",
+ ".relocs",
+ ".rmeta",
".ro",
- "initramfs_inc_data",
- "default_cpio_list",
- "x509_certificate_list",
- "utf8data.c_shipped",
+ ".tbl",
+ ".uc",
+ ".x509",
+ ".xml",
"blacklist_hash_list",
- "x509_revocation_list",
"cpucaps",
- "sysreg",
+ "default_cpio_list",
+ "initramfs_inc_data",
+ "kheaders.md5",
+ "kheaders-objlist",
+ "kheaders-srclist",
"mach-types",
+ "sysreg",
+ "utf8data.c_shipped",
+ "x509_certificate_list",
+ "x509_revocation_list",
]
) or includes_path_segments(["drivers/gpu/drm/radeon/reg_srcs/"]):
return "data"
# Configuration files
- if ends_with([".pem", ".key", ".conf", ".config", ".cfg", ".bconf"]):
+ if ends_with([
+ ".pem",
+ ".key",
+ ".conf",
+ ".config",
+ ".cfg",
+ ".bconf",
+ "config_data",
+ ".genkey",
+ "bindgen_parameters",
+ ]):
return "configuration"
- # Documentation
- if ends_with([".md"]):
- return "documentation"
-
# Other / miscellaneous
- if ends_with([".o", ".tmp"]):
+ if ends_with([".o"]):
return "other"
sbom_logging.warning("Could not infer primary purpose for {absolute_path}", absolute_path=absolute_path)
--
2.43.0
next prev parent reply other threads:[~2026-10-12 21:34 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 21:33 [PATCH v3 0/7] kbuild: record cmd-prereqs in .cmd files Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 1/7] scripts/make_fit: limit .cmd file parsing to the savedcmd_ line Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 2/7] kbuild: refactor fixdep to collect dependencies before printing Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 3/7] scripts/sbom: skip make_prereqs lines when parsing .cmd files Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 4/7] kbuild: record cmd-prereqs in " Luis Augenstein
2026-10-12 21:33 ` [PATCH v3 5/7] scripts/sbom: parse make_prereqs from " Luis Augenstein
2026-10-12 21:33 ` Luis Augenstein [this message]
2026-10-12 21:33 ` [PATCH v3 7/7] scripts/sbom: remove the command-specific parsers Luis Augenstein
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261012213337.2466524-7-luis.augenstein@tngtech.com \
--to=luis.augenstein@tngtech.com \
--cc=akpm@linux-foundation.org \
--cc=gregkh@linuxfoundation.org \
--cc=kstewart@linuxfoundation.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maximilian.huber@tngtech.com \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®