[PATCH 10/23] kbuild: cache list, composite object state per object

From: Lorenzo Stoakes (ARM)

Date: Tue Sep 08 2026 - 17:10:52 EST


When each object's command line is expanded, kbuild has to figure out on
multiple occasions whether it's built-in or part of a module and which
composite object it belongs to.

This causes the time spent on each directory in the kernel tree to grow
O(n^2) with its object count, which is especially problematic for instance
in drivers/gpu/drm/amd/amdgpu with 310 objects.

No-op builds (i.e. make -j $(nproc) when nothing has changed) are
particularly impacted by this.

Fix the issue by caching this data and looking it up instead of getting it
over and over again.

This has a particularly large impact on allmodconfig builds.

Whole build, 128-thread Threadripper 9980X, best of N runs:

before after delta
-------------------------------
x86 defconfig, no-op make, gcc 0.94s 0.92s -0.02s (-2%)
x86 defconfig, no-op make, clang 1.1s 1.1s -0.01s (-1%)
x86 allmodconfig, no-op make, gcc 13.0s 12.3s -0.64s (-5%)
x86 allmodconfig, no-op make, clang 13.8s 13.2s -0.64s (-5%)
x86 allmodconfig, touch mm/vma.c, gcc 41.6s 40.9s -0.70s (-2%)
x86 allmodconfig, touch mm/vma.c, clang 38.1s 37.6s -0.52s (-1%)

Assisted-by: LLM
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx>
---
scripts/Makefile.build | 8 ++++++++
scripts/Makefile.lib | 7 +++----
2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 4349108e75e1..2cabfe85b798 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -122,6 +122,14 @@ multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m))
subdir-ym := $(addprefix $(obj)/, $(subdir-ym))
endif

+# Cache which list each object is in and which composite objects it belongs to,
+# once per object for $(part-of-builtin), $(part-of-module) and $(modname-multi).
+$(foreach o, $(real-obj-y) $(lib-y), $(eval part-of-builtin_$o := y))
+$(foreach o, $(real-obj-m), $(eval part-of-module_$o := y))
+$(foreach m, $(multi-obj-ym), \
+ $(foreach o, $(call suffix-search, $m, .o, -objs -y -m), \
+ $(eval modname-multi_$o += $(m:.o=))))
+
ifndef obj
$(warning kbuild: Makefile.build is included improperly)
endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0a4fdd8bd975..2f447bc25e7b 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -2,8 +2,7 @@

# Finds the multi-part object the current object will be linked into.
# If the object belongs to two or more multi-part objects, list them all.
-modname-multi = $(sort $(foreach m,$(multi-obj-ym),\
- $(if $(filter $*.o, $(call suffix-search, $m, .o, -objs -y -m)),$(m:.o=))))
+modname-multi = $(sort $(modname-multi_$*.o))

__modname = $(or $(modname-multi),$(basetarget))

@@ -149,8 +148,8 @@ endif
# If $(is-kernel-object) is 'y', this object will be linked to vmlinux or modules
is-kernel-object = $(or $(part-of-builtin),$(part-of-module))

-part-of-builtin = $(if $(filter $(basename $@).o, $(real-obj-y) $(lib-y)),y)
-part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y)
+part-of-builtin = $(part-of-builtin_$(basename $@).o)
+part-of-module = $(part-of-module_$(basename $@).o)
quiet_modtag = $(if $(part-of-module),[M], )

modkern_cflags = \

--
2.55.0