[PATCH 3/3] selftests/bpf: Route test_kmods build artifacts to OUTPUT

From: Ricardo B. Marlière (SUSE)

Date: Tue Jul 28 2026 - 20:10:58 EST


When building bpf selftests with O=, the kernel module intermediates (.ko,
.o, .mod.*, .cmd files, Module.symvers, modules.order) produced by the
test_kmods sub-make are placed in the source tree instead of the
out-of-tree directory, because kbuild external-module builds always write
output to the M= source directory by default.

Introduce TEST_KMODS_OUTDIR in bpf/Makefile that resolves to
$(OUTPUT)/test_kmods when OUTPUT is set, and fall back to the in-tree
test_kmods/ directory for standalone builds. Update the pattern rule, the
RM invocation, and the copy rule to use this variable, and pass
OUTPUT=$(OUTPUT)/test_kmods to the test_kmods sub-make.

In test_kmods/Makefile, forward the received OUTPUT value as MO= to the
kernel Makefile. The top-level kernel Makefile maps MO= to
KBUILD_EXTMOD_OUTPUT, which redirects all external-module build output to
the specified directory. The kernel also creates that directory
automatically, so no explicit mkdir is needed.

Also update the CLEAN target in bpf/Makefile to propagate OUTPUT to both
the test_kmods and libarena sub-makes so that clean removes from the
correct location.

Signed-off-by: Ricardo B. Marlière (SUSE) <ricardo@xxxxxxxxxxxx>
---
tools/testing/selftests/bpf/Makefile | 16 ++++++++++------
tools/testing/selftests/bpf/test_kmods/Makefile | 3 +++
2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 7d42632f9d42..b150a66f3c25 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -135,6 +135,9 @@ TEST_PROGS_EXTENDED := \
TEST_KMODS := bpf_testmod.ko bpf_test_no_cfi.ko bpf_test_modorder_x.ko \
bpf_test_modorder_y.ko bpf_test_rqspinlock.ko
TEST_KMOD_TARGETS = $(addprefix $(OUTPUT)/,$(TEST_KMODS))
+# Build directory for kernel modules: routed to $(OUTPUT)/test_kmods when
+# OUTPUT is set so that kbuild intermediates stay out of the source tree.
+TEST_KMODS_OUTDIR := $(if $(OUTPUT),$(OUTPUT)/test_kmods,test_kmods)

# Compile but not part of 'make run_tests'
TEST_GEN_PROGS_EXTENDED = \
@@ -163,8 +166,8 @@ override define CLEAN
$(Q)$(RM) -r $(TEST_GEN_FILES)
$(Q)$(RM) -r $(TEST_KMODS)
$(Q)$(RM) -r $(EXTRA_CLEAN)
- $(Q)$(MAKE) -C test_kmods clean
- $(Q)$(MAKE) -C libarena clean
+ $(Q)$(MAKE) -C test_kmods $(if $(OUTPUT),OUTPUT=$(OUTPUT)/test_kmods) clean
+ $(Q)$(MAKE) -C libarena $(if $(OUTPUT),OUTPUT=$(OUTPUT)/libarena) clean
$(Q)$(MAKE) docs-clean
endef

@@ -301,17 +304,18 @@ $(OUTPUT)/sign-file: ../../../../scripts/sign-file.c
# support that for regular rules. However, pattern matching rules are implicitly
# treated as grouped even with older versions of make, so as a workaround, the
# subst() turns the rule into a pattern matching rule
-$(addprefix test_kmods/,$(subst .ko,%ko,$(TEST_KMODS))): $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard test_kmods/Makefile test_kmods/*.[ch])
- $(Q)$(RM) test_kmods/*.ko test_kmods/*.mod.o # force re-compilation
+$(addprefix $(TEST_KMODS_OUTDIR)/,$(subst .ko,%ko,$(TEST_KMODS))): $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard test_kmods/Makefile test_kmods/*.[ch])
+ $(Q)$(RM) $(TEST_KMODS_OUTDIR)/*.ko $(TEST_KMODS_OUTDIR)/*.mod.o # force re-compilation
$(Q)$(MAKE) $(submake_extras) -C test_kmods \
$(if $(O),O=$(abspath $(O))) \
$(if $(KBUILD_OUTPUT),KBUILD_OUTPUT=$(abspath $(KBUILD_OUTPUT)))\
+ $(if $(OUTPUT),OUTPUT=$(OUTPUT)/test_kmods) \
RESOLVE_BTFIDS=$(RESOLVE_BTFIDS) \
EXTRA_CFLAGS='' EXTRA_LDFLAGS=''

-$(TEST_KMOD_TARGETS): $(addprefix test_kmods/,$(TEST_KMODS))
+$(TEST_KMOD_TARGETS): $(addprefix $(TEST_KMODS_OUTDIR)/,$(TEST_KMODS))
$(call msg,MOD,,$@)
- $(Q)$(if $(PERMISSIVE),if [ -f test_kmods/$(@F) ]; then )cp test_kmods/$(@F) $@$(if $(PERMISSIVE),; fi)
+ $(Q)$(if $(PERMISSIVE),if [ -f $(TEST_KMODS_OUTDIR)/$(@F) ]; then )cp $(TEST_KMODS_OUTDIR)/$(@F) $@$(if $(PERMISSIVE),; fi)


DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool
diff --git a/tools/testing/selftests/bpf/test_kmods/Makefile b/tools/testing/selftests/bpf/test_kmods/Makefile
index 031c7454ce65..53e47e715ec4 100644
--- a/tools/testing/selftests/bpf/test_kmods/Makefile
+++ b/tools/testing/selftests/bpf/test_kmods/Makefile
@@ -32,14 +32,17 @@ PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
all:
ifeq ($(PERMISSIVE),)
$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O_VALID),O=$(KMOD_O_VALID) KBUILD_OUTPUT=$(KMOD_O_VALID),KBUILD_OUTPUT=) \
+ $(if $(OUTPUT),MO=$(OUTPUT)) \
M=$(TEST_KMOD_DIR) modules
else ifneq ("$(wildcard $(KDIR))", "")
$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O_VALID),O=$(KMOD_O_VALID) KBUILD_OUTPUT=$(KMOD_O_VALID),KBUILD_OUTPUT=) \
+ $(if $(OUTPUT),MO=$(OUTPUT)) \
M=$(TEST_KMOD_DIR) modules
endif

clean:
ifneq ("$(wildcard $(KDIR))", "")
$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O_VALID),O=$(KMOD_O_VALID) KBUILD_OUTPUT=$(KMOD_O_VALID),KBUILD_OUTPUT=) \
+ $(if $(OUTPUT),MO=$(OUTPUT)) \
M=$(TEST_KMOD_DIR) clean
endif

--
2.55.0