* [PATCH bpf-next v7 1/9] selftests/bpf: keep headers off the generic link command line
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies Mykola Lysenko
` (7 subsequent siblings)
8 siblings, 0 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
The generic '$(OUTPUT)/%:%.c' rule links with '$(LINK.c) $^', so
every prerequisite of such a binary lands on the compiler driver's
command line. That only works while none of them is a header: gcc
tolerates a stray .h argument on a link line, but clang treats it as
a request to precompile the header and fails with "cannot specify -o
when generating multiple output files".
Filter headers out of the recipe, with a comment: header
prerequisites on these targets are useful for dependency tracking -
the next patch declares one - and the constraint is easy to
rediscover the hard way.
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 5f1a3bfc0569..118a7c356e26 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -258,9 +258,12 @@ $(OUTPUT)/%.o: %.c
$(call msg,CC,,$@)
$(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
+# Headers may appear among the prerequisites for dependency tracking;
+# they must not reach the clang/gcc command line (clang treats a bare .h
+# argument as a precompiled-header job and refuses -o).
$(OUTPUT)/%:%.c
$(call msg,BINARY,,$@)
- $(Q)$(LINK.c) $^ $(LDLIBS) -o $@
+ $(Q)$(LINK.c) $(filter-out %.h,$^) $(LDLIBS) -o $@
# LLVM's ld.lld doesn't support all the architectures, so use it only on x86
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 riscv))
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 1/9] selftests/bpf: keep headers off the generic link command line Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 20:41 ` bot+bpf-ci
2026-08-24 22:47 ` Eduard Zingerman
2026-08-23 19:42 ` [PATCH bpf-next v7 3/9] selftests/bpf: factor the permissive-mode skip suffix into a helper Mykola Lysenko
` (6 subsequent siblings)
8 siblings, 2 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
Four target-specific lines name objects nothing builds. Three name
the BPF objects by their pre-rename names: commit afef88e65554
("selftests/bpf: Store BPF object files with .bpf.o extension") left
them without a target; the flow_dissector_load.o dependency names an
intermediate the generic one-step compile+link rule does not produce.
Three linked-skeleton dependency map entries (xsk_xdp_progs,
xdp_hw_metadata, xdp_features) were dead on arrival: commit
f0a249df1b07 ("selftests/xsk: get rid of built-in XDP program"),
commit 297a3f124155 ("selftests/bpf: Simple program to dump XDP RX
metadata") and commit 4dba3e7852b7 ("selftests/bpf: introduce XDP
compliance test tool") each added one, mimicking the neighboring
entries without adding the skeleton to LINKED_SKELS, the only place
the -deps map is read from; these three skeletons are generated by
the regular pattern rule, which never consults it.
The '-fno-inline' pair (test_l4lb_noinline, test_xdp_noinline) had
stopped taking effect even earlier, with commit 74b5a5968fe8
("selftests/bpf: Replace test_progs and test_maps w/ general rule"):
since then the BPF compile recipe expands TRUNNER_BPF_CFLAGS, a
simply-expanded copy of BPF_CFLAGS taken when the runner rules are
instantiated, which a target-specific 'BPF_CFLAGS +=' cannot reach.
Both programs have compiled without the flag since, and nothing was
lost: every function they define
carries a noinline annotation, except the SEC() entry points, which
nothing in the file calls, and the single __always_inline helper in
each, a deliberate exception the flag never overrode; and
compiling with -fno-inline restored yields byte-identical objects.
The two header dependencies with remaining value are restored in
working form. flow_dissector_load.h moves to the binary itself, which
is linked straight from its .c by the generic '$(OUTPUT)/%:%.c' rule
- editing the header now rebuilds it - on the line that already lists
the binary's helper object. cgroup_getset_retval_hooks.h -
added by commit e7215f574079 ("selftests/bpf: Make sure
bpf_{g,s}et_retval is exposed everywhere") days before the rename
orphaned it - lived in the top directory, outside the progs/*.h
blanket prerequisite of the BPF object rules, so editing it never
rebuilt the BPF object. Move it under progs/, next to its only BPF
consumer, where the blanket prerequisite covers it - the arrangement
several other headers shared between progs/ and prog_tests/ already
use. Its userspace consumer is tracked exactly by the
compiler-generated dependency files.
'CURDIR := $(abspath .)' redefines make's builtin to the value it
already has, and 'OBJCOPY ?= $(CROSS_COMPILE)objcopy' defines a
variable nothing in the selftests build or the included kselftest
infrastructure ever reads; drop both.
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 13 +------------
.../selftests/bpf/prog_tests/cgroup_getset_retval.c | 2 +-
.../bpf/{ => progs}/cgroup_getset_retval_hooks.h | 0
3 files changed, 2 insertions(+), 13 deletions(-)
rename tools/testing/selftests/bpf/{ => progs}/cgroup_getset_retval_hooks.h (100%)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 118a7c356e26..c7c7f27dd860 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -4,9 +4,7 @@ include ../../../scripts/Makefile.arch
include ../../../scripts/Makefile.include
CXX ?= $(CROSS_COMPILE)g++
-OBJCOPY ?= $(CROSS_COMPILE)objcopy
-CURDIR := $(abspath .)
TOOLSDIR := $(abspath ../../..)
LIBDIR := $(TOOLSDIR)/lib
BPFDIR := $(LIBDIR)/bpf
@@ -342,7 +340,7 @@ $(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELP
$(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
$(OUTPUT)/test_tag: $(TESTING_HELPERS)
$(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
-$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
+$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS) flow_dissector_load.h
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
$(OUTPUT)/xsk.o: $(BPFOBJ)
@@ -480,12 +478,6 @@ BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
CLANG_CFLAGS = $(CLANG_SYS_INCLUDES)
-$(OUTPUT)/test_l4lb_noinline.o: BPF_CFLAGS += -fno-inline
-$(OUTPUT)/test_xdp_noinline.o: BPF_CFLAGS += -fno-inline
-
-$(OUTPUT)/flow_dissector_load.o: flow_dissector_load.h
-$(OUTPUT)/cgroup_getset_retval_hooks.o: cgroup_getset_retval_hooks.h
-
# Build BPF object using Clang
# $1 - input .c file
# $2 - output .o file
@@ -546,9 +538,6 @@ linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o
test_usdt.skel.h-deps := test_usdt.bpf.o test_usdt_multispec.bpf.o
-xsk_xdp_progs.skel.h-deps := xsk_xdp_progs.bpf.o
-xdp_hw_metadata.skel.h-deps := xdp_hw_metadata.bpf.o
-xdp_features.skel.h-deps := xdp_features.bpf.o
tracing_multi.skel.h-deps := tracing_multi_attach.bpf.o tracing_multi_check.bpf.o
tracing_multi_module.skel.h-deps := tracing_multi_attach_module.bpf.o tracing_multi_check.bpf.o
tracing_multi_intersect.skel.h-deps := tracing_multi_intersect_attach.bpf.o tracing_multi_check.bpf.o
diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c b/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c
index 2bb5773d6f99..ea342859d6ce 100644
--- a/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c
+++ b/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c
@@ -465,7 +465,7 @@ struct exposed_hook {
.expected_err = EXPECTED_ERR, \
},
-#include "cgroup_getset_retval_hooks.h"
+#include "progs/cgroup_getset_retval_hooks.h"
#undef BPF_RETVAL_HOOK
};
diff --git a/tools/testing/selftests/bpf/cgroup_getset_retval_hooks.h b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_hooks.h
similarity index 100%
rename from tools/testing/selftests/bpf/cgroup_getset_retval_hooks.h
rename to tools/testing/selftests/bpf/progs/cgroup_getset_retval_hooks.h
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies
2026-08-23 19:42 ` [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies Mykola Lysenko
@ 2026-08-23 20:41 ` bot+bpf-ci
2026-08-24 22:47 ` Eduard Zingerman
1 sibling, 0 replies; 19+ messages in thread
From: bot+bpf-ci @ 2026-08-23 20:41 UTC (permalink / raw)
To: nickolay.lysenko, bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1053 bytes --]
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 118a7c356e26c..c7c7f27dd8605 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -4,9 +4,7 @@ include ../../../scripts/Makefile.arch
> include ../../../scripts/Makefile.include
>
> CXX ?= $(CROSS_COMPILE)g++
> -OBJCOPY ?= $(CROSS_COMPILE)objcopy
>
> -CURDIR := $(abspath .)
> TOOLSDIR := $(abspath ../../..)
This isn't a bug, but would it be worth splitting the OBJCOPY and CURDIR
variable removals into their own small cleanup patch? The subject and the
bulk of the changelog focus on stale build rules and the two restored
header dependencies, while these variable removals are unused/redundant
definitions that get their own paragraph at the end.
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32662817569
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies
2026-08-23 19:42 ` [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies Mykola Lysenko
2026-08-23 20:41 ` bot+bpf-ci
@ 2026-08-24 22:47 ` Eduard Zingerman
1 sibling, 0 replies; 19+ messages in thread
From: Eduard Zingerman @ 2026-08-24 22:47 UTC (permalink / raw)
To: Mykola Lysenko, bpf
Cc: ast, daniel, andrii, martin.lau, song, yonghong.song, jolsa,
memxor
On Sun, 2026-08-23 at 12:42 -0700, Mykola Lysenko wrote:
> Four target-specific lines name objects nothing builds. Three name
> the BPF objects by their pre-rename names: commit afef88e65554
> ("selftests/bpf: Store BPF object files with .bpf.o extension") left
> them without a target; the flow_dissector_load.o dependency names an
> intermediate the generic one-step compile+link rule does not produce.
>
> Three linked-skeleton dependency map entries (xsk_xdp_progs,
> xdp_hw_metadata, xdp_features) were dead on arrival: commit
> f0a249df1b07 ("selftests/xsk: get rid of built-in XDP program"),
> commit 297a3f124155 ("selftests/bpf: Simple program to dump XDP RX
> metadata") and commit 4dba3e7852b7 ("selftests/bpf: introduce XDP
> compliance test tool") each added one, mimicking the neighboring
> entries without adding the skeleton to LINKED_SKELS, the only place
> the -deps map is read from; these three skeletons are generated by
> the regular pattern rule, which never consults it.
>
> The '-fno-inline' pair (test_l4lb_noinline, test_xdp_noinline) had
> stopped taking effect even earlier, with commit 74b5a5968fe8
> ("selftests/bpf: Replace test_progs and test_maps w/ general rule"):
> since then the BPF compile recipe expands TRUNNER_BPF_CFLAGS, a
> simply-expanded copy of BPF_CFLAGS taken when the runner rules are
> instantiated, which a target-specific 'BPF_CFLAGS +=' cannot reach.
> Both programs have compiled without the flag since, and nothing was
> lost: every function they define
> carries a noinline annotation, except the SEC() entry points, which
> nothing in the file calls, and the single __always_inline helper in
> each, a deliberate exception the flag never overrode; and
> compiling with -fno-inline restored yields byte-identical objects.
>
> The two header dependencies with remaining value are restored in
> working form. flow_dissector_load.h moves to the binary itself, which
> is linked straight from its .c by the generic '$(OUTPUT)/%:%.c' rule
> - editing the header now rebuilds it - on the line that already lists
> the binary's helper object. cgroup_getset_retval_hooks.h -
> added by commit e7215f574079 ("selftests/bpf: Make sure
> bpf_{g,s}et_retval is exposed everywhere") days before the rename
> orphaned it - lived in the top directory, outside the progs/*.h
> blanket prerequisite of the BPF object rules, so editing it never
> rebuilt the BPF object. Move it under progs/, next to its only BPF
> consumer, where the blanket prerequisite covers it - the arrangement
> several other headers shared between progs/ and prog_tests/ already
> use. Its userspace consumer is tracked exactly by the
> compiler-generated dependency files.
>
> 'CURDIR := $(abspath .)' redefines make's builtin to the value it
> already has, and 'OBJCOPY ?= $(CROSS_COMPILE)objcopy' defines a
> variable nothing in the selftests build or the included kselftest
> infrastructure ever reads; drop both.
>
> Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
...
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH bpf-next v7 3/9] selftests/bpf: factor the permissive-mode skip suffix into a helper
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 1/9] selftests/bpf: keep headers off the generic link command line Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 2/9] selftests/bpf: drop stale lines, restore two header dependencies Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 19:51 ` sashiko-bot
2026-08-23 19:42 ` [PATCH bpf-next v7 4/9] selftests/bpf: generate the signing key and certificate once Mykola Lysenko
` (5 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
With BPF_STRICT_BUILD=0, eleven recipes append the same "|| { remove
the target, print a SKIP marker, report success }" tail, each spelled
out inline. Factor the tail into skip_on_fail; every call site keeps its
exact message and behavior.
The permissive fragments of other shapes are not suffixes and keep
their current form: the rsync --ignore-missing-args flags, the
missing-input guards in the skeleton recipes, the link rule's
wildcard handling and the test_kmods copy wrapper.
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 49 +++++++++++-----------------
1 file changed, 19 insertions(+), 30 deletions(-)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index c7c7f27dd860..e4c8efd1e6f1 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -48,6 +48,14 @@ SKIP_CRYPTO ?=
BPF_STRICT_BUILD ?= 1
PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
+# Permissive-mode recipe suffix: on failure, remove the target, emit a
+# SKIP marker and report success so the rest of the build continues.
+# $(1) - SKIP tag (BPF, TEST, BENCH, SKEL, LINK, ...)
+# $(2) - optional extra files to remove alongside the target
+# $(3) - optional note appended to the SKIP message
+skip_on_fail = $(if $(PERMISSIVE),|| { $(RM) $@ $(2); \
+ printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)$(if $(3), $(3))' 1>&2; })
+
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
@@ -485,26 +493,22 @@ CLANG_CFLAGS = $(CLANG_SYS_INCLUDES)
# $4 - binary name
define CLANG_BPF_BUILD_RULE
$(call msg,CLNG-BPF,$4,$2)
- $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v3 -o $2 $(if $(PERMISSIVE),|| \
- ($(RM) $2; printf ' %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
+ $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v3 -o $2 $(call skip_on_fail,BPF)
endef
# Similar to CLANG_BPF_BUILD_RULE, but with disabled alu32
define CLANG_NOALU32_BPF_BUILD_RULE
$(call msg,CLNG-BPF,$4,$2)
- $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v2 -o $2 $(if $(PERMISSIVE),|| \
- ($(RM) $2; printf ' %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
+ $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v2 -o $2 $(call skip_on_fail,BPF)
endef
# Similar to CLANG_BPF_BUILD_RULE, but with cpu-v4
define CLANG_CPUV4_BPF_BUILD_RULE
$(call msg,CLNG-BPF,$4,$2)
- $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v4 -o $2 $(if $(PERMISSIVE),|| \
- ($(RM) $2; printf ' %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
+ $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v4 -o $2 $(call skip_on_fail,BPF)
endef
# Build BPF object using GCC
define GCC_BPF_BUILD_RULE
$(call msg,GCC-BPF,$4,$2)
- $(Q)$(BPF_GCC) $3 -DBPF_NO_PRESERVE_ACCESS_INDEX -Wno-attributes -O2 -c $1 -o $2 $(if $(PERMISSIVE),|| \
- ($(RM) $2; printf ' %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
+ $(Q)$(BPF_GCC) $3 -DBPF_NO_PRESERVE_ACCESS_INDEX -Wno-attributes -O2 -c $1 -o $2 $(call skip_on_fail,BPF)
endef
SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
@@ -632,10 +636,7 @@ $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o) && \
diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) && \
$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@ && \
- $$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) $(if $(PERMISSIVE),|| { \
- $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
+ $$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h)) && \
rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
$(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
@@ -649,10 +650,7 @@ $(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o) && \
$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) && \
diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) && \
- $$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $(if $(PERMISSIVE),|| { \
- $$(RM) $$@; \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
+ $$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $$(call skip_on_fail,SKEL) && \
rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
$(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
@@ -666,10 +664,7 @@ $(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o) && \
$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) && \
diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) && \
- $$(BPFTOOL) gen skeleton $(LSKEL_SIGN) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $(if $(PERMISSIVE),|| { \
- $$(RM) $$@; \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
+ $$(BPFTOOL) gen skeleton $(LSKEL_SIGN) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $$(call skip_on_fail,SKEL) && \
rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
$(LINKED_BPF_OBJS): %: $(TRUNNER_OUTPUT)/%
@@ -691,10 +686,7 @@ $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_OUTPUT)/%: $$$$(%-deps) $(BPFTOOL) | $(TR
diff $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o) && \
printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2 && \
$$(BPFTOOL) gen skeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$@ && \
- $$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h) $(if $(PERMISSIVE),|| { \
- $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
+ $$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h) $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h)) && \
rm -f $$(@:.skel.h=.linked1.o) $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
# When the compiler generates a %.d file, only skel basenames (not
@@ -727,8 +719,7 @@ $(TRUNNER_TEST_OBJS): $(TRUNNER_OUTPUT)/%.test.o: \
$(TRUNNER_TESTS_DIR)/%.c \
| $(TRUNNER_OUTPUT)/%.test.d
$$(call msg,TEST-OBJ,$(TRUNNER_BINARY),$$@)
- $(Q)(cd $$(@D) && $$(CC) -I. $$(CFLAGS) -MMD -MT $$@ -c $(CURDIR)/$$< $$(LDLIBS) -o $$(@F)) $(if $(filter test_progs%,$1),$(if $(PERMISSIVE),|| \
- ($(RM) $$@; printf ' %-12s %s\n' 'SKIP-TEST' '$$(notdir $$@)' 1>&2)))
+ $(Q)(cd $$(@D) && $$(CC) -I. $$(CFLAGS) -MMD -MT $$@ -c $(CURDIR)/$$< $$(LDLIBS) -o $$(@F)) $(if $(filter test_progs%,$1),$$(call skip_on_fail,TEST))
$$(if $$(TEST_NEEDS_BTFIDS), \
$(Q)if [ -f $$@ ]; then \
$(if $(filter 1,$(V)),true,printf ' %-8s%s %s\n' "BTFIDS" " [$(TRUNNER_BINARY)]" "$$(notdir $$@)"); \
@@ -962,8 +953,7 @@ $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ)
# Benchmark runner
$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ)
$(call msg,CC,,$@)
- $(Q)$(CC) $(CFLAGS) -O2 -c $(filter %.c,$^) $(LDLIBS) -o $@ $(if $(PERMISSIVE),|| \
- ($(RM) $@; printf ' %-12s %s\n' 'SKIP-BENCH' '$(notdir $@)' 1>&2))
+ $(Q)$(CC) $(CFLAGS) -O2 -c $(filter %.c,$^) $(LDLIBS) -o $@ $(call skip_on_fail,BENCH)
$(OUTPUT)/bench_rename.o: $(OUTPUT)/test_overhead.skel.h
$(OUTPUT)/bench_trigger.o: $(OUTPUT)/trigger_bench.skel.h
$(OUTPUT)/bench_ringbufs.o: $(OUTPUT)/ringbuf_bench.skel.h \
@@ -1016,8 +1006,7 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
$(OUTPUT)/usdt_2.o \
#
$(call msg,BINARY,,$@)
- $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@ $(if $(PERMISSIVE),|| \
- ($(RM) $@; printf ' %-12s %s\n' 'SKIP-LINK' '$(notdir $@) (some benchmarks may have been skipped)' 1>&2))
+ $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@ $(call skip_on_fail,LINK,,(some benchmarks may have been skipped))
# This works around GCC warning about snprintf truncating strings like:
#
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 3/9] selftests/bpf: factor the permissive-mode skip suffix into a helper
2026-08-23 19:42 ` [PATCH bpf-next v7 3/9] selftests/bpf: factor the permissive-mode skip suffix into a helper Mykola Lysenko
@ 2026-08-23 19:51 ` sashiko-bot
0 siblings, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-08-23 19:51 UTC (permalink / raw)
To: Mykola Lysenko; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Missing space in "SKIP-LINK" message for skipped benchmarks.
--
--- Patch [3]: [PATCH bpf-next v7 3/9] selftests/bpf: factor the permissive-mode skip suffix into a helper ---
commit 390f83151721ccaeb21976f48c2d352d76658f37
Author: Mykola Lysenko <nickolay.lysenko@gmail.com>
selftests/bpf: factor the permissive-mode skip suffix into a helper
This commit factors out the duplicated permissive-mode skip suffix across
multiple Makefile recipes into a single skip_on_fail helper macro. This
reduces duplication while maintaining the original behavior and messages.
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index c7c7f27dd8605..e4c8efd1e6f1b 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -48,6 +48,14 @@ SKIP_CRYPTO ?=
> BPF_STRICT_BUILD ?= 1
> PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
>
> +# Permissive-mode recipe suffix: on failure, remove the target, emit a
> +# SKIP marker and report success so the rest of the build continues.
> +# $(1) - SKIP tag (BPF, TEST, BENCH, SKEL, LINK, ...)
> +# $(2) - optional extra files to remove alongside the target
> +# $(3) - optional note appended to the SKIP message
> +skip_on_fail = $(if $(PERMISSIVE),|| { $(RM) $@ $(2); \
> + printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)$(if $(3), $(3))' 1>&2; })
[ ... ]
> @@ -1016,8 +1006,7 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
> $(OUTPUT)/usdt_2.o \
> #
> $(call msg,BINARY,,$@)
> - $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@ $(if $(PERMISSIVE),|| \
> - ($(RM) $@; printf ' %-12s %s\n' 'SKIP-LINK' '$(notdir $@) (some benchmarks may have been skipped)' 1>&2))
> + $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@ $(call skip_on_fail,LINK,,(some benchmarks may have been skipped))
[Severity: Low]
This isn't a bug, but does the resulting string lack a space between the
target name and the note?
GNU Make ignores whitespace following a comma in function arguments. Because
of this, $(if $(3), $(3)) in the skip_on_fail macro will evaluate without
a leading space, even if one is provided in the invocation or in the string
itself.
Could this cause the printed message to become "bench(some benchmarks may
have been skipped)" instead of the original "bench (some benchmarks may have
been skipped)"?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260823194241.3415152-1-nickolay.lysenko@gmail.com?part=3
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH bpf-next v7 4/9] selftests/bpf: generate the signing key and certificate once
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
` (2 preceding siblings ...)
2026-08-23 19:42 ` [PATCH bpf-next v7 3/9] selftests/bpf: factor the permissive-mode skip suffix into a helper Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 5/9] selftests/bpf: generate verifier/tests.h in a regular recipe Mykola Lysenko
` (4 subsequent siblings)
8 siblings, 0 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
$(VERIFICATION_CERT) and $(PRIVATE_KEY) come from a single genkey
invocation, but a rule with two normal targets runs its recipe once
per stale target. Today only $(VERIFICATION_CERT) is ever a
prerequisite (of $(VERIFY_SIG_HDR)), so the recipe runs once; the
runner patch later in this series lists both files as prerequisites
of the same target, at which point both runs would execute, under -j
concurrently, and the openssl invocations would race on the same
output files.
Rewrite it as a pattern rule, the same workaround the test_kmods
rule already uses, with the stem narrowed to the fixed name: genkey
hardcodes signing_key.pem / signing_key.der, and a wider pattern
would claim every .pem/.der under $(BUILD_DIR) and "succeed" without
producing the requested file.
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index e4c8efd1e6f1..7b80a1b1ef76 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -787,7 +787,12 @@ VERIFY_SIG_HDR := verification_cert.h
VERIFICATION_CERT := $(BUILD_DIR)/signing_key.der
PRIVATE_KEY := $(BUILD_DIR)/signing_key.pem
-$(VERIFICATION_CERT) $(PRIVATE_KEY): $(VERIFY_SIG_SETUP)
+# One genkey run produces both files. A plain two-target rule is not
+# grouped - if both files are stale make would run genkey twice, under
+# -j concurrently, and the openssl invocations race; the pattern form
+# is implicitly grouped even with make < 4.3. The stem only stands in
+# for 'signing' so that no other .pem/.der under $(BUILD_DIR) matches.
+$(BUILD_DIR)/%_key.pem $(BUILD_DIR)/%_key.der: $(VERIFY_SIG_SETUP)
$(Q)mkdir -p $(BUILD_DIR)
$(Q)$(VERIFY_SIG_SETUP) genkey $(BUILD_DIR)
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH bpf-next v7 5/9] selftests/bpf: generate verifier/tests.h in a regular recipe
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
` (3 preceding siblings ...)
2026-08-23 19:42 ` [PATCH bpf-next v7 4/9] selftests/bpf: generate the signing key and certificate once Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 6/9] selftests/bpf: derive the bench object list from the sources Mykola Lysenko
` (3 subsequent siblings)
8 siblings, 0 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
The verifier/tests.h recipe is a $(shell ...) expansion: the command
runs while make expands the recipe line - including under make -n -
its exit status is discarded, and the resulting (empty) expansion is
what make actually executes.
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 7b80a1b1ef76..2070a07015ae 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -914,12 +914,12 @@ $(eval $(call DEFINE_TEST_RUNNER,test_maps))
# them (e.g., test.h is using completely pattern), that it's worth just
# explicitly defining all the rules explicitly.
verifier/tests.h: verifier/*.c
- $(shell ( cd verifier/; \
+ $(Q)( cd verifier/; \
echo '/* Generated header, do not edit */'; \
echo '#ifdef FILL_ARRAY'; \
ls *.c 2> /dev/null | sed -e 's@\(.*\)@#include \"\1\"@'; \
echo '#endif' \
- ) > verifier/tests.h)
+ ) > verifier/tests.h
$(OUTPUT)/test_verifier: test_verifier.c verifier/tests.h $(BPFOBJ) | $(OUTPUT)
$(call msg,BINARY,,$@)
$(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH bpf-next v7 6/9] selftests/bpf: derive the bench object list from the sources
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
` (4 preceding siblings ...)
2026-08-23 19:42 ` [PATCH bpf-next v7 5/9] selftests/bpf: generate verifier/tests.h in a regular recipe Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-24 23:42 ` Eduard Zingerman
2026-08-23 19:42 ` [PATCH bpf-next v7 7/9] selftests/bpf: extract BPF skeleton generation into a helper script Mykola Lysenko
` (2 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
The bench binary links every benchs/bench_*.c object, but the link
rule names them one by one in a hand-maintained list, which has to be
extended by hand for every new benchmark although the pattern rule
already builds any bench_*.c placed in benchs/. Derive the list with
a wildcard instead: a new benchmark is compiled and linked in by
dropping its source there (its skeleton dependency line, when it has
one, is still declared next to the others).
The derived list is sorted, which changes the link order of the bench
objects (previously roughly chronological) and with it the symbol
layout of the binary; no benchmark behaves differently. The trailing
'#' terminator goes away together with the block it closed: the two
remaining entries after the variable are fixed, so the append
friendliness it provided no longer buys anything.
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 28 ++++------------------------
1 file changed, 4 insertions(+), 24 deletions(-)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 2070a07015ae..9f18dd291736 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -955,7 +955,8 @@ $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ)
$(call msg,CXX,,$@)
$(Q)$(CXX) $(CXXFLAGS) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@
-# Benchmark runner
+# Benchmark runner. Every benchs/bench_*.c is compiled and linked in.
+BENCH_OBJS := $(sort $(patsubst benchs/%.c,$(OUTPUT)/%.o,$(wildcard benchs/bench_*.c)))
$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ)
$(call msg,CC,,$@)
$(Q)$(CC) $(CFLAGS) -O2 -c $(filter %.c,$^) $(LDLIBS) -o $@ $(call skip_on_fail,BENCH)
@@ -986,30 +987,9 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
$(TESTING_HELPERS) \
$(TRACE_HELPERS) \
$(CGROUP_HELPERS) \
- $(OUTPUT)/bench_count.o \
- $(OUTPUT)/bench_rename.o \
- $(OUTPUT)/bench_trigger.o \
- $(OUTPUT)/bench_ringbufs.o \
- $(OUTPUT)/bench_bloom_filter_map.o \
- $(OUTPUT)/bench_bpf_loop.o \
- $(OUTPUT)/bench_bpf_for.o \
- $(OUTPUT)/bench_strncmp.o \
- $(OUTPUT)/bench_bpf_hashmap_full_update.o \
- $(OUTPUT)/bench_local_storage.o \
- $(OUTPUT)/bench_local_storage_rcu_tasks_trace.o \
- $(OUTPUT)/bench_bpf_hashmap_lookup.o \
- $(OUTPUT)/bench_local_storage_create.o \
- $(OUTPUT)/bench_htab_mem.o \
- $(OUTPUT)/bench_bpf_crypto.o \
- $(OUTPUT)/bench_sockmap.o \
- $(OUTPUT)/bench_lpm_trie_map.o \
- $(OUTPUT)/bench_bpf_timing.o \
- $(OUTPUT)/bench_bpf_nop.o \
- $(OUTPUT)/bench_xdp_lb.o \
- $(OUTPUT)/bench_libarena.o \
+ $(BENCH_OBJS) \
$(OUTPUT)/usdt_1.o \
- $(OUTPUT)/usdt_2.o \
- #
+ $(OUTPUT)/usdt_2.o
$(call msg,BINARY,,$@)
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@ $(call skip_on_fail,LINK,,(some benchmarks may have been skipped))
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 6/9] selftests/bpf: derive the bench object list from the sources
2026-08-23 19:42 ` [PATCH bpf-next v7 6/9] selftests/bpf: derive the bench object list from the sources Mykola Lysenko
@ 2026-08-24 23:42 ` Eduard Zingerman
0 siblings, 0 replies; 19+ messages in thread
From: Eduard Zingerman @ 2026-08-24 23:42 UTC (permalink / raw)
To: Mykola Lysenko, bpf
Cc: ast, daniel, andrii, martin.lau, song, yonghong.song, jolsa,
memxor
On Sun, 2026-08-23 at 12:42 -0700, Mykola Lysenko wrote:
> The bench binary links every benchs/bench_*.c object, but the link
> rule names them one by one in a hand-maintained list, which has to be
> extended by hand for every new benchmark although the pattern rule
> already builds any bench_*.c placed in benchs/. Derive the list with
> a wildcard instead: a new benchmark is compiled and linked in by
> dropping its source there (its skeleton dependency line, when it has
> one, is still declared next to the others).
>
> The derived list is sorted, which changes the link order of the bench
> objects (previously roughly chronological) and with it the symbol
> layout of the binary; no benchmark behaves differently. The trailing
> '#' terminator goes away together with the block it closed: the two
> remaining entries after the variable are fixed, so the append
> friendliness it provided no longer buys anything.
>
> Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
...
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH bpf-next v7 7/9] selftests/bpf: extract BPF skeleton generation into a helper script
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
` (5 preceding siblings ...)
2026-08-23 19:42 ` [PATCH bpf-next v7 6/9] selftests/bpf: derive the bench object list from the sources Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars Mykola Lysenko
2026-08-23 19:42 ` [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make Mykola Lysenko
8 siblings, 0 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
The four skeleton generation recipes (regular, light, signed light and
linked) are near-identical pipelines - link via "bpftool gen
object" three times, compare the second and third results as a
regression test for bpftool's determinism, generate the skeleton (and
possibly subskeleton), remove intermediates - duplicated with small
variations inside DEFINE_TEST_RUNNER_RULES, where every line pays the
double-expansion escaping tax.
Move the pipeline into gen_bpf_skel.sh; the differences between the
four variants become the --lskel, --sign and --subskel flags. Signing
takes the key and certificate from $PRIVATE_KEY and $VERIFICATION_CERT
in the environment, like the bpftool binary comes from $BPFTOOL; the
script checks for both up front, before any intermediate exists. The
distinct linked/llinked intermediate infixes are kept but derived
inside the script (its header says why they matter). The intermediates
are now named after the output header rather than the input object
(foo.linked1.o instead of foo.bpf.linked1.o for the single-object
variants; the linked-skeleton variant already used that form), which
keeps the stems distinct just the same.
The permissive-mode missing-input checks at the top of the recipes -
when the object's compile already failed and was skipped, skip the
skeleton quietly instead of running bpftool against a missing file -
are kept, factored into a skip_if_missing helper.
The build-log messages stay folded behind the guard as in the original
recipes, so a skipped skeleton prints SKIP-SKEL and nothing else. What
does change is the failure path: the script removes the intermediates
it created (the recipes left them behind), the determinism check
reports through cmp plus one message instead of a diff listing, and
the linked-skeleton recipe prints its GEN-SKEL line before the link
rather than after it, like the other three always did.
Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Assisted-by: Claude:claude-fable-5 shellcheck
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 93 ++++++++-----------
tools/testing/selftests/bpf/gen_bpf_skel.sh | 99 +++++++++++++++++++++
2 files changed, 136 insertions(+), 56 deletions(-)
create mode 100755 tools/testing/selftests/bpf/gen_bpf_skel.sh
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 9f18dd291736..8ac6c8844d4a 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -56,6 +56,17 @@ PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
skip_on_fail = $(if $(PERMISSIVE),|| { $(RM) $@ $(2); \
printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)$(if $(3), $(3))' 1>&2; })
+# Permissive-mode recipe prefix: when a prerequisite object is missing
+# (its compile failed and was skipped), remove the target and $(3),
+# emit a SKIP marker and report success without running the rest of
+# the recipe.
+# $(1) - SKIP tag
+# $(2) - input files to check
+# $(3) - optional extra files to remove alongside the target
+skip_if_missing = $(if $(PERMISSIVE),for f in $(2); do [ -f $$f ] || { \
+ $(RM) $@ $(3); \
+ printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)' 1>&2; exit 0; }; done;)
+
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
@@ -564,7 +575,6 @@ HEADERS_FOR_BPF_OBJS := $(wildcard $(BPFDIR)/*.bpf.h) \
# $2 - test runner extra "flavor" (e.g., no_alu32, cpuv4, bpf_gcc, etc)
define DEFINE_TEST_RUNNER
-LSKEL_SIGN := -S -k $(PRIVATE_KEY) -i $(VERIFICATION_CERT)
TRUNNER_OUTPUT := $(OUTPUT)$(if $2,/)$2
TRUNNER_BINARY := $1$(if $2,-)$2
TRUNNER_TEST_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.test.o, \
@@ -624,70 +634,41 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o: \
$$($$<-CFLAGS) \
$$($$<-$2-CFLAGS),$(TRUNNER_BINARY))
-$(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
- $(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then \
- $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- exit 0; \
- fi;) \
+$(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
+ $(Q)$$(call skip_if_missing,SKEL,$$<,$$(@:.skel.h=.subskel.h)) \
printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
- $$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$< && \
- $$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o) && \
- $$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o) && \
- diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) && \
- $$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@ && \
- $$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h)) && \
- rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
-
-$(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
- $(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then \
- $$(RM) $$@; \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- exit 0; \
- fi;) \
+ BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh \
+ --name $$(notdir $$(<:.bpf.o=)) \
+ --skel $$@ --subskel $$(@:.skel.h=.subskel.h) $$< $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h))
+
+$(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
+ $(Q)$$(call skip_if_missing,SKEL,$$<) \
printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
- $$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$< && \
- $$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o) && \
- $$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) && \
- diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) && \
- $$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $$(call skip_on_fail,SKEL) && \
- rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
-
-$(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
- $(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then \
- $$(RM) $$@; \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- exit 0; \
- fi;) \
+ BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh \
+ --name $$(notdir $$(<:.bpf.o=_lskel)) --lskel \
+ --skel $$@ $$< $$(call skip_on_fail,SKEL)
+
+$(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
+ $(Q)$$(call skip_if_missing,SKEL,$$<) \
printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY) (signed)] $$(notdir $$@)' 1>&2; \
- $$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$< && \
- $$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o) && \
- $$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) && \
- diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) && \
- $$(BPFTOOL) gen skeleton $(LSKEL_SIGN) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $$(call skip_on_fail,SKEL) && \
- rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+ BPFTOOL=$$(BPFTOOL) PRIVATE_KEY=$(PRIVATE_KEY) \
+ VERIFICATION_CERT=$(VERIFICATION_CERT) \
+ ./gen_bpf_skel.sh --sign \
+ --name $$(notdir $$(<:.bpf.o=_lskel)) \
+ --skel $$@ $$< $$(call skip_on_fail,SKEL)
$(LINKED_BPF_OBJS): %: $(TRUNNER_OUTPUT)/%
# .SECONDEXPANSION here allows to correctly expand %-deps variables as prerequisites
.SECONDEXPANSION:
-$(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_OUTPUT)/%: $$$$(%-deps) $(BPFTOOL) | $(TRUNNER_OUTPUT)
- $(Q)$(if $(PERMISSIVE),for f in $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)); do \
- if [ ! -f $$$$f ]; then \
- $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- exit 0; \
- fi; \
- done;) \
+$(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_OUTPUT)/%: $$$$(%-deps) $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
+ $(Q)$$(call skip_if_missing,SKEL,$$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)),$$(@:.skel.h=.subskel.h)) \
printf ' %-12s %s\n' 'LINK-BPF' '[$(TRUNNER_BINARY)] $$(notdir $$(@:.skel.h=.bpf.o))' 1>&2; \
- $$(BPFTOOL) gen object $$(@:.skel.h=.linked1.o) $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)) && \
- $$(BPFTOOL) gen object $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked1.o) && \
- $$(BPFTOOL) gen object $$(@:.skel.h=.linked3.o) $$(@:.skel.h=.linked2.o) && \
- diff $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o) && \
- printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2 && \
- $$(BPFTOOL) gen skeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$@ && \
- $$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h) $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h)) && \
- rm -f $$(@:.skel.h=.linked1.o) $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
+ printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
+ BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh \
+ --name $$(notdir $$(@:.skel.h=)) \
+ --skel $$@ --subskel $$(@:.skel.h=.subskel.h) \
+ $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)) $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h))
# When the compiler generates a %.d file, only skel basenames (not
# full paths) are specified as prerequisites for corresponding %.o
diff --git a/tools/testing/selftests/bpf/gen_bpf_skel.sh b/tools/testing/selftests/bpf/gen_bpf_skel.sh
new file mode 100755
index 000000000000..e43ccf095575
--- /dev/null
+++ b/tools/testing/selftests/bpf/gen_bpf_skel.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Link BPF object file(s) with "bpftool gen object" and generate a
+# skeleton (or light skeleton) header from the result.
+#
+# Usage:
+# BPFTOOL=<bpftool> gen_bpf_skel.sh --name NAME --skel OUT [options] OBJ...
+#
+# --name NAME skeleton object name ("name NAME" for bpftool)
+# --skel OUT output header ("foo.skel.h" or "foo.lskel.h")
+# --subskel OUT also generate a subskeleton header into OUT
+# --lskel generate a light skeleton (bpftool gen skeleton -L)
+# --sign sign the (light) skeleton, with the key and
+# certificate taken from $PRIVATE_KEY and
+# $VERIFICATION_CERT
+#
+# The inputs are linked three times and the 2nd and 3rd results
+# compared, as a regression test for the determinism of "bpftool gen
+# object".
+#
+# Intermediate files are named after the output header with a "linked"
+# infix - "llinked" for light or signed skeletons, so generating a
+# .skel.h and a .lskel.h from the same .bpf.o in parallel never races
+# on the intermediates.
+#
+# The bpftool binary is taken from $BPFTOOL (default: bpftool from PATH).
+# On failure all outputs and intermediates are removed and the script
+# exits non-zero; permissive-mode skipping is the caller's business
+# (see skip_on_fail in the Makefile).
+
+set -u
+
+bpftool=${BPFTOOL:-bpftool}
+name='' skel='' subskel=''
+lskel=0 sign=0
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --name) name=$2; shift 2 ;;
+ --skel) skel=$2; shift 2 ;;
+ --subskel) subskel=$2; shift 2 ;;
+ --lskel) lskel=1; shift ;;
+ --sign) sign=1; shift ;;
+ --) shift; break ;;
+ -*) echo "$0: unknown option: $1" >&2; exit 1 ;;
+ *) break ;;
+ esac
+done
+
+if [ -z "$name" ] || [ -z "$skel" ] || [ $# -eq 0 ]; then
+ echo "usage: $0 --name NAME --skel OUT [options] OBJ..." >&2
+ exit 1
+fi
+
+infix=linked
+if [ "$lskel" -eq 1 ] || [ "$sign" -eq 1 ]; then
+ infix=llinked
+fi
+
+if [ "$sign" -eq 1 ] && { [ -z "${PRIVATE_KEY-}" ] || [ -z "${VERIFICATION_CERT-}" ]; }; then
+ echo "$0: --sign requires PRIVATE_KEY and VERIFICATION_CERT in the environment" >&2
+ exit 1
+fi
+
+base=${skel%.skel.h}
+base=${base%.lskel.h}
+t1=$base.${infix}1.o
+t2=$base.${infix}2.o
+t3=$base.${infix}3.o
+
+fail() {
+ rm -f "$skel" ${subskel:+"$subskel"} "$t1" "$t2" "$t3"
+ exit 1
+}
+
+"$bpftool" gen object "$t1" "$@" || fail
+"$bpftool" gen object "$t2" "$t1" || fail
+"$bpftool" gen object "$t3" "$t2" || fail
+if ! cmp -s "$t2" "$t3"; then
+ echo "$0: bpftool gen object is not deterministic for $skel" >&2
+ fail
+fi
+
+args=()
+if [ "$sign" -eq 1 ]; then
+ args+=(-S -k "$PRIVATE_KEY" -i "$VERIFICATION_CERT")
+fi
+if [ "$lskel" -eq 1 ]; then
+ args+=(-L)
+fi
+"$bpftool" gen skeleton ${args[@]+"${args[@]}"} "$t3" name "$name" > "$skel" || fail
+
+if [ -n "$subskel" ]; then
+ "$bpftool" gen subskeleton "$t3" name "$name" > "$subskel" || fail
+fi
+
+rm -f "$t1" "$t2" "$t3"
+exit 0
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
` (6 preceding siblings ...)
2026-08-23 19:42 ` [PATCH bpf-next v7 7/9] selftests/bpf: extract BPF skeleton generation into a helper script Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 20:53 ` bot+bpf-ci
2026-08-25 6:45 ` Eduard Zingerman
2026-08-23 19:42 ` [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make Mykola Lysenko
8 siblings, 2 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
Move the build definitions a test runner needs - tree layout and
tool locations, flag assembly, feature probes, signing key paths, the
permissive-mode helpers - into Makefile.buildvars, in their current
order, as preparation for building each test runner instance in its
own sub-make: the definitions become includable by more than one
makefile. No rules or recipes are changed.
The include sits directly after ../lib.mk, ahead of the
../../../build/Makefile.feature evaluation, so the definitions are in
place for everything the top Makefile parses afterwards - in particular
the LLVM feature probe captures srctree and PKG_CONFIG from their new
location, and the top Makefile's remaining uses of both are all
recipe-time expansions. Two evaluation-time changes follow from
the new position and a third is made on the way, each commented in
place: CFLAGS and LDFLAGS are
reassembled around a snapshot taken before lib.mk, keeping the
pre-split order;
CLANG_SYS_INCLUDES becomes an immediate assignment (its inputs are
final by this point, and expanding it forks shells); and the
CLANG_HAS_ARENA_ASAN probe now sees CLANG as resolved from
LLVM=<suffix-or-path> rather than the bare 'clang' default it saw
above the include, while the CLANG_CPUV4 probe, needed before lib.mk,
keeps the old behavior.
BPF_GCC, TEST_KMODS and the knobs the runner never reads (SKIP_*,
submake_extras, TEST_KMOD_TARGETS, the VMLINUX_BTF block) stay in the
Makefile - the first two are needed before lib.mk is included, where
Makefile.buildvars cannot yet be, and reach the runners from there once
a later patch adds them: TEST_KMODS exported in the environment, BPF_GCC
as the bpf_gcc flavor's compiler parameter. Definitions that reach no
runner, directly or as a sub-make parameter, also stay - except
HOST_INCLUDE_DIR, which moves with the conditional block it shares
with the host build directories - and the four that derive from
Makefile.buildvars values sit in a block right after the include.
Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Assisted-by: Claude:claude-fable-5 shellcheck
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 175 ++---------------
.../testing/selftests/bpf/Makefile.buildvars | 184 ++++++++++++++++++
2 files changed, 198 insertions(+), 161 deletions(-)
create mode 100644 tools/testing/selftests/bpf/Makefile.buildvars
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 8ac6c8844d4a..432897613b90 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -5,109 +5,21 @@ include ../../../scripts/Makefile.include
CXX ?= $(CROSS_COMPILE)g++
-TOOLSDIR := $(abspath ../../..)
-LIBDIR := $(TOOLSDIR)/lib
-BPFDIR := $(LIBDIR)/bpf
-TOOLSINCDIR := $(TOOLSDIR)/include
-TOOLSARCHINCDIR := $(TOOLSDIR)/arch/$(SRCARCH)/include
-BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool
-APIDIR := $(TOOLSINCDIR)/uapi
-ifneq ($(O),)
-GENDIR := $(O)/include/generated
-else
-GENDIR := $(abspath ../../../../include/generated)
-endif
-GENHDR := $(GENDIR)/autoconf.h
-PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
-
-ifneq ($(wildcard $(GENHDR)),)
- GENFLAGS := -DHAVE_GENHDR
-endif
-
BPF_GCC ?= $(shell command -v bpf-gcc;)
-ifdef ASAN
-SAN_CFLAGS ?= -fsanitize=address -fno-omit-frame-pointer
-else
-SAN_CFLAGS ?=
-endif
-SAN_LDFLAGS ?= $(SAN_CFLAGS)
-RELEASE ?=
-OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0)
-
-LIBELF_CFLAGS := $(shell $(PKG_CONFIG) libelf --cflags 2>/dev/null)
-LIBELF_LIBS := $(shell $(PKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
SKIP_DOCS ?=
SKIP_LLVM ?=
SKIP_LIBBFD ?=
SKIP_CRYPTO ?=
-# When BPF_STRICT_BUILD is 1, any BPF object, skeleton, test object, or
-# benchmark compilation failure is fatal. Set to 0 to tolerate failures
-# and continue building the remaining tests.
-BPF_STRICT_BUILD ?= 1
-PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
-
-# Permissive-mode recipe suffix: on failure, remove the target, emit a
-# SKIP marker and report success so the rest of the build continues.
-# $(1) - SKIP tag (BPF, TEST, BENCH, SKEL, LINK, ...)
-# $(2) - optional extra files to remove alongside the target
-# $(3) - optional note appended to the SKIP message
-skip_on_fail = $(if $(PERMISSIVE),|| { $(RM) $@ $(2); \
- printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)$(if $(3), $(3))' 1>&2; })
-
-# Permissive-mode recipe prefix: when a prerequisite object is missing
-# (its compile failed and was skipped), remove the target and $(3),
-# emit a SKIP marker and report success without running the rest of
-# the recipe.
-# $(1) - SKIP tag
-# $(2) - input files to check
-# $(3) - optional extra files to remove alongside the target
-skip_if_missing = $(if $(PERMISSIVE),for f in $(2); do [ -f $$f ] || { \
- $(RM) $@ $(3); \
- printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)' 1>&2; exit 0; }; done;)
-
-ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(CURDIR)))
-srctree := $(patsubst %/,%,$(dir $(srctree)))
-srctree := $(patsubst %/,%,$(dir $(srctree)))
-srctree := $(patsubst %/,%,$(dir $(srctree)))
-endif
-
-COMMON_CFLAGS = -g $(OPT_FLAGS) -rdynamic -std=gnu11 \
- -Wall -Werror -fno-omit-frame-pointer \
- -Wno-unused-but-set-variable \
- $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \
- -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
- -I$(TOOLSINCDIR) -I$(TOOLSARCHINCDIR) -I$(APIDIR) -I$(OUTPUT) \
- -I$(CURDIR)/libarena/include
-LDFLAGS += $(SAN_LDFLAGS)
-LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread
-
-PCAP_CFLAGS := $(shell $(PKG_CONFIG) --cflags libpcap 2>/dev/null && echo "-DTRAFFIC_MONITOR=1")
-PCAP_LIBS := $(shell $(PKG_CONFIG) --libs libpcap 2>/dev/null)
-LDLIBS += $(PCAP_LIBS)
-CFLAGS += $(COMMON_CFLAGS) $(PCAP_CFLAGS)
-
# Some utility functions use LLVM libraries
jit_disasm_helpers.c-CFLAGS = $(LLVM_CFLAGS)
-ifneq ($(LLVM),)
-# Silence some warnings when compiled with clang
-CFLAGS += -Wno-unused-command-line-argument
-endif
-
# Check whether bpf cpu=v4 is supported or not by clang
ifneq ($(shell $(CLANG) --target=bpf -mcpu=help 2>&1 | grep 'v4'),)
CLANG_CPUV4 := 1
endif
-# Check whether clang supports BPF address sanitizer (requires LLVM 22+)
-CLANG_HAS_ARENA_ASAN := $(shell echo 'int x;' | \
- $(CLANG) --target=bpf -fsanitize=kernel-address \
- -mllvm -asan-shadow-addr-space=1 \
- -x c -c - -o /dev/null 2>/dev/null && echo 1)
-
# Order correspond to 'make run_tests' order
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_progs \
test_sockmap \
@@ -185,7 +97,21 @@ override define CLEAN
$(Q)$(MAKE) docs-clean
endef
+# ../lib.mk appends to the flags inherited from the environment;
+# Makefile.buildvars rebuilds CFLAGS and LDFLAGS around these snapshots
+# so that its own additions precede lib.mk's, as they did when they
+# were defined above the include.
+INHERITED_CFLAGS := $(CFLAGS)
+INHERITED_LDFLAGS := $(LDFLAGS)
include ../lib.mk
+include Makefile.buildvars
+
+# Definitions only this Makefile consumes; placed after the include
+# because some of them derive from Makefile.buildvars values.
+BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool
+HOST_BPFOBJ := $(HOST_BUILD_DIR)/libbpf/libbpf.a
+BPF_TARGET_ENDIAN:=$(if $(IS_LITTLE_ENDIAN),--target=bpfel,--target=bpfeb)
+CLANG_CFLAGS = $(CLANG_SYS_INCLUDES)
NON_CHECK_FEAT_TARGETS := clean docs-clean emit_tests
CHECK_FEAT := $(filter-out $(NON_CHECK_FEAT_TARGETS),$(or $(MAKECMDGOALS), "none"))
@@ -230,21 +156,6 @@ ifeq ($(feature-llvm),1)
endif
endif
-SCRATCH_DIR := $(OUTPUT)/tools
-BUILD_DIR := $(SCRATCH_DIR)/build
-INCLUDE_DIR := $(SCRATCH_DIR)/include
-BPFOBJ := $(BUILD_DIR)/libbpf/libbpf.a
-ifneq ($(CROSS_COMPILE),)
-HOST_BUILD_DIR := $(BUILD_DIR)/host
-HOST_SCRATCH_DIR := $(OUTPUT)/host-tools
-HOST_INCLUDE_DIR := $(HOST_SCRATCH_DIR)/include
-else
-HOST_BUILD_DIR := $(BUILD_DIR)
-HOST_SCRATCH_DIR := $(SCRATCH_DIR)
-HOST_INCLUDE_DIR := $(INCLUDE_DIR)
-endif
-HOST_BPFOBJ := $(HOST_BUILD_DIR)/libbpf/libbpf.a
-RESOLVE_BTFIDS := $(HOST_BUILD_DIR)/resolve_btfids/resolve_btfids
VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
$(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
../../../../vmlinux \
@@ -333,17 +244,6 @@ $(TEST_KMOD_TARGETS): $(addprefix test_kmods/,$(TEST_KMODS))
$(call msg,MOD,,$@)
$(Q)$(if $(PERMISSIVE),if [ -f test_kmods/$(@F) ]; then )cp test_kmods/$(@F) $@$(if $(PERMISSIVE),; fi)
-
-DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool
-ifneq ($(CROSS_COMPILE),)
-CROSS_BPFTOOL := $(SCRATCH_DIR)/sbin/bpftool
-TRUNNER_BPFTOOL := $(CROSS_BPFTOOL)
-USE_BOOTSTRAP := ""
-else
-TRUNNER_BPFTOOL := $(DEFAULT_BPFTOOL)
-USE_BOOTSTRAP := "bootstrap/"
-endif
-
$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
TESTING_HELPERS := $(OUTPUT)/testing_helpers.o
@@ -364,7 +264,6 @@ $(OUTPUT)/test_maps: $(TESTING_HELPERS)
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
$(OUTPUT)/xsk.o: $(BPFOBJ)
-BPFTOOL ?= $(DEFAULT_BPFTOOL)
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
@@ -457,46 +356,6 @@ $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
HOSTPKG_CONFIG='$(PKG_CONFIG)' \
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
-# Get Clang's default includes on this system, as opposed to those seen by
-# '--target=bpf'. This fixes "missing" files on some architectures/distros,
-# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
-#
-# Use '-idirafter': Don't interfere with include mechanics except where the
-# build would have failed anyways.
-define get_sys_includes
-$(shell $(1) $(2) -v -E - </dev/null 2>&1 \
- | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') \
-$(shell $(1) $(2) -dM -E - </dev/null | grep '__riscv_xlen ' | awk '{printf("-D__riscv_xlen=%d -D__BITS_PER_LONG=%d", $$3, $$3)}') \
-$(shell $(1) $(2) -dM -E - </dev/null | grep '__loongarch_grlen ' | awk '{printf("-D__BITS_PER_LONG=%d", $$3)}') \
-$(shell $(1) $(2) -dM -E - </dev/null | grep -E 'MIPS(EL|EB)|_MIPS_SZ(PTR|LONG) |_MIPS_SIM |_ABI(O32|N32|64) ' | awk '{printf("-D%s=%s ", $$2, $$3)}')
-endef
-
-# Determine target endianness.
-IS_LITTLE_ENDIAN := $(shell $(CC) -dM -E - </dev/null | \
- grep 'define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__')
-MENDIAN:=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian)
-BPF_TARGET_ENDIAN:=$(if $(IS_LITTLE_ENDIAN),--target=bpfel,--target=bpfeb)
-
-ifneq ($(CROSS_COMPILE),)
-CLANG_TARGET_ARCH = --target=$(notdir $(CROSS_COMPILE:%-=%))
-endif
-
-CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH))
-BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
- -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \
- -I$(TOOLSINCDIR) -I$(CURDIR)/libarena/include \
- -I$(abspath $(OUTPUT)/../usr/include) \
- -std=gnu11 \
- -fno-strict-aliasing \
- -Wno-microsoft-anon-tag \
- -fms-extensions \
- -Wno-compare-distinct-pointer-types \
- -Wno-initializer-overrides \
- #
-# TODO: enable me -Wsign-compare
-
-CLANG_CFLAGS = $(CLANG_SYS_INCLUDES)
-
# Build BPF object using Clang
# $1 - input .c file
# $2 - output .o file
@@ -763,10 +622,7 @@ $(OUTPUT)/$(TRUNNER_BINARY): $(if $(filter test_progs%,$1),$(if $(PERMISSIVE),$$
endef
-VERIFY_SIG_SETUP := $(CURDIR)/verify_sig_setup.sh
VERIFY_SIG_HDR := verification_cert.h
-VERIFICATION_CERT := $(BUILD_DIR)/signing_key.der
-PRIVATE_KEY := $(BUILD_DIR)/signing_key.pem
# One genkey run produces both files. A plain two-target rule is not
# grouped - if both files are stale make would run genkey twice, under
@@ -802,7 +658,6 @@ LIBARENA_COMMON_DEPS := $(wildcard libarena/Makefile \
LIBARENA_BPF_DEPS := $(LIBARENA_COMMON_DEPS) $(wildcard libarena/selftests/*)
LIBARENA_BENCH_BPF_DEPS := $(LIBARENA_COMMON_DEPS) $(wildcard libarena/benchs/*)
-LIBARENA_SKEL := libarena/libarena.skel.h
LIBARENA_BENCH_SKEL := libarena/libarena_bench.skel.h
$(LIBARENA_SKEL): $(INCLUDE_DIR)/vmlinux.h $(BPFOBJ) $(LIBARENA_BPF_DEPS)
@@ -812,8 +667,6 @@ $(LIBARENA_BENCH_SKEL): $(INCLUDE_DIR)/vmlinux.h $(BPFOBJ) $(LIBARENA_BENCH_BPF_
+$(MAKE) -C libarena benchmarks $(LIBARENA_MAKE_ARGS)
ifneq ($(CLANG_HAS_ARENA_ASAN),)
-LIBARENA_ASAN_SKEL := libarena/libarena_asan.skel.h
-CFLAGS += -DHAS_BPF_ARENA_ASAN
$(LIBARENA_ASAN_SKEL): $(INCLUDE_DIR)/vmlinux.h $(BPFOBJ) $(LIBARENA_BPF_DEPS)
+$(MAKE) -C libarena libarena_asan.skel.h $(LIBARENA_MAKE_ARGS)
diff --git a/tools/testing/selftests/bpf/Makefile.buildvars b/tools/testing/selftests/bpf/Makefile.buildvars
new file mode 100644
index 000000000000..dc0be9ee72bc
--- /dev/null
+++ b/tools/testing/selftests/bpf/Makefile.buildvars
@@ -0,0 +1,184 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Shared toolchain, path and flag definitions for the BPF selftests
+# build, included by both Makefile and Makefile.runner. Definitions
+# follow the order they had in the Makefile before the split.
+
+TOOLSDIR := $(abspath ../../..)
+LIBDIR := $(TOOLSDIR)/lib
+BPFDIR := $(LIBDIR)/bpf
+TOOLSINCDIR := $(TOOLSDIR)/include
+TOOLSARCHINCDIR := $(TOOLSDIR)/arch/$(SRCARCH)/include
+APIDIR := $(TOOLSINCDIR)/uapi
+ifneq ($(O),)
+GENDIR := $(O)/include/generated
+else
+GENDIR := $(abspath ../../../../include/generated)
+endif
+GENHDR := $(GENDIR)/autoconf.h
+PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
+
+ifneq ($(wildcard $(GENHDR)),)
+ GENFLAGS := -DHAVE_GENHDR
+endif
+
+ifdef ASAN
+SAN_CFLAGS ?= -fsanitize=address -fno-omit-frame-pointer
+else
+SAN_CFLAGS ?=
+endif
+SAN_LDFLAGS ?= $(SAN_CFLAGS)
+RELEASE ?=
+OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0)
+
+LIBELF_CFLAGS := $(shell $(PKG_CONFIG) libelf --cflags 2>/dev/null)
+LIBELF_LIBS := $(shell $(PKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
+
+# When BPF_STRICT_BUILD is 1, any BPF object, skeleton, test object, or
+# benchmark compilation failure is fatal. Set to 0 to tolerate failures
+# and continue building the remaining tests.
+BPF_STRICT_BUILD ?= 1
+PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
+
+# Permissive-mode recipe suffix: on failure, remove the target, emit a
+# SKIP marker and report success so the rest of the build continues.
+# $(1) - SKIP tag (BPF, TEST, BENCH, SKEL, LINK, ...)
+# $(2) - optional extra files to remove alongside the target
+# $(3) - optional note appended to the SKIP message
+skip_on_fail = $(if $(PERMISSIVE),|| { $(RM) $@ $(2); \
+ printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)$(if $(3), $(3))' 1>&2; })
+
+# Permissive-mode recipe prefix: when a prerequisite object is missing
+# (its compile failed and was skipped), remove the target and $(3),
+# emit a SKIP marker and report success without running the rest of
+# the recipe.
+# $(1) - SKIP tag
+# $(2) - input files to check
+# $(3) - optional extra files to remove alongside the target
+skip_if_missing = $(if $(PERMISSIVE),for f in $(2); do [ -f $$f ] || { \
+ $(RM) $@ $(3); \
+ printf ' %-12s %s\n' 'SKIP-$(1)' '$(notdir $@)' 1>&2; exit 0; }; done;)
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+
+COMMON_CFLAGS = -g $(OPT_FLAGS) -rdynamic -std=gnu11 \
+ -Wall -Werror -fno-omit-frame-pointer \
+ -Wno-unused-but-set-variable \
+ $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \
+ -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
+ -I$(TOOLSINCDIR) -I$(TOOLSARCHINCDIR) -I$(APIDIR) -I$(OUTPUT) \
+ -I$(CURDIR)/libarena/include
+LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread
+
+PCAP_CFLAGS := $(shell $(PKG_CONFIG) --cflags libpcap 2>/dev/null && echo "-DTRAFFIC_MONITOR=1")
+PCAP_LIBS := $(shell $(PKG_CONFIG) --libs libpcap 2>/dev/null)
+LDLIBS += $(PCAP_LIBS)
+
+ifneq ($(LLVM),)
+# Silence some warnings when compiled with clang
+CLANG_WARN_CFLAGS := -Wno-unused-command-line-argument
+endif
+
+# Before the split these definitions sat above the ../lib.mk include:
+# they appended to the flags inherited from the environment, and
+# lib.mk's additions (USERCFLAGS/USERLDFLAGS among them) came last.
+# This file is parsed after lib.mk at the top level and in its place
+# in the runner sub-makes, so the same order is rebuilt here. The
+# includer snapshots the inherited flags in INHERITED_CFLAGS and
+# INHERITED_LDFLAGS before lib.mk runs; whatever lib.mk appended since
+# is the tail of the current value.
+lib_mk_added = $(wordlist $(words x $(INHERITED_$(1))),$(words $($(1))),$($(1)))
+LIB_MK_CFLAGS := $(call lib_mk_added,CFLAGS)
+LIB_MK_LDFLAGS := $(call lib_mk_added,LDFLAGS)
+CFLAGS = $(INHERITED_CFLAGS) $(COMMON_CFLAGS) $(PCAP_CFLAGS) \
+ $(CLANG_WARN_CFLAGS) $(LIB_MK_CFLAGS)
+LDFLAGS = $(INHERITED_LDFLAGS) $(SAN_LDFLAGS) $(LIB_MK_LDFLAGS)
+
+# Check whether clang supports BPF address sanitizer (requires LLVM 22+).
+# This runs after ../lib.mk has resolved CLANG from LLVM=<suffix or path>,
+# so it probes the compiler that builds the BPF objects.
+CLANG_HAS_ARENA_ASAN := $(shell echo 'int x;' | \
+ $(CLANG) --target=bpf -fsanitize=kernel-address \
+ -mllvm -asan-shadow-addr-space=1 \
+ -x c -c - -o /dev/null 2>/dev/null && echo 1)
+
+SCRATCH_DIR := $(OUTPUT)/tools
+BUILD_DIR := $(SCRATCH_DIR)/build
+INCLUDE_DIR := $(SCRATCH_DIR)/include
+BPFOBJ := $(BUILD_DIR)/libbpf/libbpf.a
+ifneq ($(CROSS_COMPILE),)
+HOST_BUILD_DIR := $(BUILD_DIR)/host
+HOST_SCRATCH_DIR := $(OUTPUT)/host-tools
+HOST_INCLUDE_DIR := $(HOST_SCRATCH_DIR)/include
+else
+HOST_BUILD_DIR := $(BUILD_DIR)
+HOST_SCRATCH_DIR := $(SCRATCH_DIR)
+HOST_INCLUDE_DIR := $(INCLUDE_DIR)
+endif
+RESOLVE_BTFIDS := $(HOST_BUILD_DIR)/resolve_btfids/resolve_btfids
+
+DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool
+ifneq ($(CROSS_COMPILE),)
+CROSS_BPFTOOL := $(SCRATCH_DIR)/sbin/bpftool
+TRUNNER_BPFTOOL := $(CROSS_BPFTOOL)
+USE_BOOTSTRAP := ""
+else
+TRUNNER_BPFTOOL := $(DEFAULT_BPFTOOL)
+USE_BOOTSTRAP := "bootstrap/"
+endif
+
+BPFTOOL ?= $(DEFAULT_BPFTOOL)
+
+# Get Clang's default includes on this system, as opposed to those seen by
+# '--target=bpf'. This fixes "missing" files on some architectures/distros,
+# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
+#
+# Use '-idirafter': Don't interfere with include mechanics except where the
+# build would have failed anyways.
+define get_sys_includes
+$(shell $(1) $(2) -v -E - </dev/null 2>&1 \
+ | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') \
+$(shell $(1) $(2) -dM -E - </dev/null | grep '__riscv_xlen ' | awk '{printf("-D__riscv_xlen=%d -D__BITS_PER_LONG=%d", $$3, $$3)}') \
+$(shell $(1) $(2) -dM -E - </dev/null | grep '__loongarch_grlen ' | awk '{printf("-D__BITS_PER_LONG=%d", $$3)}') \
+$(shell $(1) $(2) -dM -E - </dev/null | grep -E 'MIPS(EL|EB)|_MIPS_SZ(PTR|LONG) |_MIPS_SIM |_ABI(O32|N32|64) ' | awk '{printf("-D%s=%s ", $$2, $$3)}')
+endef
+
+# Determine target endianness.
+IS_LITTLE_ENDIAN := $(shell $(CC) -dM -E - </dev/null | \
+ grep 'define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__')
+MENDIAN:=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian)
+
+ifneq ($(CROSS_COMPILE),)
+CLANG_TARGET_ARCH = --target=$(notdir $(CROSS_COMPILE:%-=%))
+endif
+
+# Immediate on purpose: expanding get_sys_includes forks several shells.
+CLANG_SYS_INCLUDES := $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH))
+BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
+ -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \
+ -I$(TOOLSINCDIR) -I$(CURDIR)/libarena/include \
+ -I$(abspath $(OUTPUT)/../usr/include) \
+ -std=gnu11 \
+ -fno-strict-aliasing \
+ -Wno-microsoft-anon-tag \
+ -fms-extensions \
+ -Wno-compare-distinct-pointer-types \
+ -Wno-initializer-overrides \
+ #
+# TODO: enable me -Wsign-compare
+
+VERIFY_SIG_SETUP := $(CURDIR)/verify_sig_setup.sh
+VERIFICATION_CERT := $(BUILD_DIR)/signing_key.der
+PRIVATE_KEY := $(BUILD_DIR)/signing_key.pem
+
+LIBARENA_SKEL := libarena/libarena.skel.h
+
+ifneq ($(CLANG_HAS_ARENA_ASAN),)
+LIBARENA_ASAN_SKEL := libarena/libarena_asan.skel.h
+CFLAGS += -DHAS_BPF_ARENA_ASAN
+endif
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars
2026-08-23 19:42 ` [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars Mykola Lysenko
@ 2026-08-23 20:53 ` bot+bpf-ci
2026-08-25 6:45 ` Eduard Zingerman
1 sibling, 0 replies; 19+ messages in thread
From: bot+bpf-ci @ 2026-08-23 20:53 UTC (permalink / raw)
To: nickolay.lysenko, bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 5339 bytes --]
> commit 79d6c61a930a7bcff9e424734672a09c86fbdcf2
> Author: Mykola Lysenko <nickolay.lysenko@gmail.com>
> Date: Sun Aug 23 12:42:40 2026 -0700
>
> selftests/bpf: move shared build definitions into Makefile.buildvars
>
> Move the build definitions a test runner needs - tree layout and
> tool locations, flag assembly, feature probes, signing key paths, the
> permissive-mode helpers - into Makefile.buildvars, in their current
> order, as preparation for building each test runner instance in its
> own sub-make: the definitions become includable by more than one
> makefile. No rules or recipes are changed.
>
> The include sits directly after ../lib.mk, ahead of the
> ../../../build/Makefile.feature evaluation, so the definitions are in
> place for everything the top Makefile parses afterwards - in particular
> the LLVM feature probe captures srctree and PKG_CONFIG from their new
> location, and the top Makefile's remaining uses of both are all
> recipe-time expansions. Two evaluation-time changes follow from
> the new position and a third is made on the way, each commented in
> place: CFLAGS and LDFLAGS are
> reassembled around a snapshot taken before lib.mk, keeping the
> pre-split order;
> CLANG_SYS_INCLUDES becomes an immediate assignment (its inputs are
> final by this point, and expanding it forks shells); and the
> CLANG_HAS_ARENA_ASAN probe now sees CLANG as resolved from
> LLVM=<suffix-or-path> rather than the bare 'clang' default it saw
> above the include, while the CLANG_CPUV4 probe, needed before lib.mk,
> keeps the old behavior.
>
> BPF_GCC, TEST_KMODS and the knobs the runner never reads (SKIP_*,
> submake_extras, TEST_KMOD_TARGETS, the VMLINUX_BTF block) stay in the
> Makefile - the first two are needed before lib.mk is included, where
> Makefile.buildvars cannot yet be, and reach the runners from there once
> a later patch adds them: TEST_KMODS exported in the environment, BPF_GCC
> as the bpf_gcc flavor's compiler parameter. Definitions that reach no
> runner, directly or as a sub-make parameter, also stay - except
> HOST_INCLUDE_DIR, which moves with the conditional block it shares
> with the host build directories - and the four that derive from
> Makefile.buildvars values sit in a block right after the include.
>
> Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
> Assisted-by: Claude:claude-fable-5 shellcheck
> Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
This isn't a bug, but the second paragraph has some lines that look
unfinished mid-paragraph ("place: CFLAGS and LDFLAGS are" at 29
columns, then "pre-split order;" at 16 columns), as if the text was
edited but not rewrapped. Would it help to reflow those lines?
The third paragraph walks through which variables moved and which
stayed ("BPF_GCC, TEST_KMODS and the knobs the runner never reads...
also stay - except HOST_INCLUDE_DIR..."), restating what the diff shows.
The key detail - that BPF_GCC and TEST_KMODS must be defined before
../lib.mk - is there, but it's somewhat buried in the inventory. Would
trimming the list and keeping just the reason make this clearer?
> diff --git a/tools/testing/selftests/bpf/Makefile.buildvars b/tools/testing/selftests/bpf/Makefile.buildvars
> new file mode 100644
> index 0000000000000..dc0be9ee72bc0
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/Makefile.buildvars
> @@ -0,0 +1,184 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Shared toolchain, path and flag definitions for the BPF selftests
> +# build, included by both Makefile and Makefile.runner. Definitions
> +# follow the order they had in the Makefile before the split.
> +
> +TOOLSDIR := $(abspath ../../..)
[ ... ]
> +# Before the split these definitions sat above the ../lib.mk include:
> +# they appended to the flags inherited from the environment, and
> +# lib.mk's additions (USERCFLAGS/USERLDFLAGS among them) came last.
> +# This file is parsed after lib.mk at the top level and in its place
> +# in the runner sub-makes, so the same order is rebuilt here. The
> +# includer snapshots the inherited flags in INHERITED_CFLAGS and
This isn't a bug, but the header and several comments are written from
the patch's point of view rather than as documentation of the current
state. The header says definitions "follow the order they had in the
Makefile before the split", and this block starts with "Before the
split these definitions sat above the ../lib.mk include". A reader
arriving later has no "before" to compare against.
The header also says this file is "included by both Makefile and
Makefile.runner", but Makefile.runner doesn't exist until the next
commit. If someone lands here during a bisect, that sentence is
inaccurate.
Would these comments read better stated as the current invariant ("lib.mk
appends to CFLAGS/LDFLAGS; this file's additions must come first, so
the includer snapshots them in INHERITED_*"), and should the header
mention Makefile.runner only once it exists?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32662817569
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars
2026-08-23 19:42 ` [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars Mykola Lysenko
2026-08-23 20:53 ` bot+bpf-ci
@ 2026-08-25 6:45 ` Eduard Zingerman
1 sibling, 0 replies; 19+ messages in thread
From: Eduard Zingerman @ 2026-08-25 6:45 UTC (permalink / raw)
To: Mykola Lysenko, bpf
Cc: ast, daniel, andrii, martin.lau, song, yonghong.song, jolsa,
memxor
On Sun, 2026-08-23 at 12:42 -0700, Mykola Lysenko wrote:
...
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 8ac6c8844d4a..432897613b90 100644
...
> @@ -185,7 +97,21 @@ override define CLEAN
> $(Q)$(MAKE) docs-clean
> endef
>
> +# ../lib.mk appends to the flags inherited from the environment;
> +# Makefile.buildvars rebuilds CFLAGS and LDFLAGS around these snapshots
> +# so that its own additions precede lib.mk's, as they did when they
> +# were defined above the include.
> +INHERITED_CFLAGS := $(CFLAGS)
> +INHERITED_LDFLAGS := $(LDFLAGS)
> include ../lib.mk
> +include Makefile.buildvars
Let's avoid INHERITED_CFLAGS dance.
First, it is okay to change the CFLAGS definition order here,
lib.mk adds the following options:
-Wno-address-of-packed-member
-Wno-gnu-variable-sized-type-not-at-end
-D_GNU_SOURCE=
-I$(top_srcdir)/tools/testing/selftests
$(USERCFLAGS)
Before the patch these are appended *after* the definitions you have
in Makefile.buildvars. Making them go *before* shouldn't break anything:
- include files in -I$(top_srcdir)/tools/testing/selftests do not conflict
with selftests;
- USERCFLAGS is documented as "additional", "extend", so there is no documented
guarantee that these should override other options. I think that the only one
we care about is `-static` and this one should be fine in either position.
Second, if one wants to preserve the {C,LD}FLAGS definition order,
the following should be possible:
CFLAGS += $(COMMON_CFLAGS) $(PCAP_CFLAGS) $(CLANG_WARN_CFLAGS)
LDFLAGS += $(SAN_LDFLAGS)
include ../lib.mk
include Makefile.buildvars
Making use of recursive definitions for {COMMON,PCAP,CALNG_WARN}_CFLAGS
that are coming from Makefile.buildvars. These would be expanded only
after include Makefile.buildvars.
But I think it's fine to go for the first option.
Aside from this the patch lgtm.
...
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make
2026-08-23 19:42 [PATCH bpf-next v7 0/9] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
` (7 preceding siblings ...)
2026-08-23 19:42 ` [PATCH bpf-next v7 8/9] selftests/bpf: move shared build definitions into Makefile.buildvars Mykola Lysenko
@ 2026-08-23 19:42 ` Mykola Lysenko
2026-08-23 21:05 ` bot+bpf-ci
2026-08-25 23:55 ` Eduard Zingerman
8 siblings, 2 replies; 19+ messages in thread
From: Mykola Lysenko @ 2026-08-23 19:42 UTC (permalink / raw)
To: bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko
Replace the DEFINE_TEST_RUNNER/DEFINE_TEST_RUNNER_RULES double-expansion
machinery - whose rules never appear in the source as written, are
invisible to make's own debugging facilities, and are easy to break
for one flavor while testing another - with Makefile.runner: one
sub-make invocation per test runner
instance (test_progs, test_progs-no_alu32, test_progs-cpuv4,
test_progs-bpf_gcc, test_maps), each in its own single-flavor namespace
written in plain make - no define/eval layer, no per-flavor guards,
no accumulating vpath directives.
The main Makefile keeps everything that exists once - tool sub-builds,
vmlinux.h, signing keys, tests.h generation, standalone binaries and
the kselftest lib.mk contract - and delegates to the runner through
explicit per-instance rules.
The rules for one flavor's BPF objects and skeletons live in
Makefile.skel, instantiated by the main Makefile for the default
flavor and by each runner sub-make that builds BPF objects. lib.mk's
install rule copies the default flavor's BPF objects - the files the
flat copy of every flavor's objects resolved to before. No file is
built twice in one build: the main Makefile produces the default
flavor's artifacts before the unflavored test_progs sub-make runs,
and each flavored runner writes its own subdirectory plus its binary
in $(OUTPUT) (the bpftool
link in $(OUTPUT) is refreshed by both unflavored sub-makes, as
before).
The runner instances link userspace objects the main Makefile
builds once; the
flavored instances link the shared objects instead of compiling
their own identical copies.
This also fixes a latent parallel-build race: the runner objects
including libbpf's internal headers now order against the bpftool
sub-build that installs them into $(INCLUDE_DIR).
Smaller behaviour changes that come with the move, for the record:
the skeleton recipes' build-log lines take the msg helper's format
and stream, the shared userspace objects log as CC rather than
EXT-OBJ/LIB-OBJ, and TEST-HDR lines lose their runner tag; the signed
light-skeleton rule lists the key and certificate it uses as
prerequisites; the extras copy skips an empty file list and, in
permissive mode, does not wait for files whose build was skipped;
$(OUTPUT)/test_maps waits for the same shared prerequisites as the
other runners; the bare-name convenience targets for the
linked-skeleton constituents (make linked_funcs1.bpf.o) are gone; the
.d include no longer special-cases the clean, docs-clean and
emit_tests goals,
which a runner sub-make never runs; and the test objects' first-build
ordering lists only the generated headers the runner itself consumes,
the rest being built by the main Makefile before any runner starts.
The runner sub-makes receive CC and CLANG as resolved by lib.mk on
their command line: Makefile.buildvars probes clang's capabilities
with $(CLANG), and a runner has to reach the same verdict as the top
level when LLVM=<suffix or path> selects a non-default toolchain.
The unflavored in-tree instance skips the extras copy as before; the
runner compares the realpath of $(OUTPUT) with $(CURDIR), make's
physical working directory, so a tree reached through a symlink
still counts as in-tree. The userspace objects depend on the
generated tests.h of the runner that includes them only
(test_progs.o on prog_tests/tests.h, test_maps.o on
map_tests/tests.h); before, every extra object of a runner depended
on that runner's tests.h. The other headers those objects depended
on - flow_dissector_load.h, ip_check_defrag_frags.h, the libarena
skeletons - are included by none of them and are dropped.
Co-developed-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Assisted-by: Claude:claude-fable-5 shellcheck
Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
---
tools/testing/selftests/bpf/Makefile | 475 +++++-------------
.../testing/selftests/bpf/Makefile.buildvars | 12 +
tools/testing/selftests/bpf/Makefile.runner | 199 ++++++++
tools/testing/selftests/bpf/Makefile.skel | 141 ++++++
4 files changed, 478 insertions(+), 349 deletions(-)
create mode 100644 tools/testing/selftests/bpf/Makefile.runner
create mode 100644 tools/testing/selftests/bpf/Makefile.skel
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 432897613b90..9b9905610070 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -12,9 +12,6 @@ SKIP_LLVM ?=
SKIP_LIBBFD ?=
SKIP_CRYPTO ?=
-# Some utility functions use LLVM libraries
-jit_disasm_helpers.c-CFLAGS = $(LLVM_CFLAGS)
-
# Check whether bpf cpu=v4 is supported or not by clang
ifneq ($(shell $(CLANG) --target=bpf -mcpu=help 2>&1 | grep 'v4'),)
CLANG_CPUV4 := 1
@@ -31,16 +28,6 @@ TEST_INST_SUBDIRS := no_alu32
ifneq ($(BPF_GCC),)
TEST_GEN_PROGS += test_progs-bpf_gcc
TEST_INST_SUBDIRS += bpf_gcc
-
-# The following tests contain C code that, although technically legal,
-# triggers GCC warnings that cannot be disabled: declaration of
-# anonymous struct types in function parameter lists.
-progs/btf_dump_test_case_bitfields.c-bpf_gcc-CFLAGS := -Wno-error
-progs/btf_dump_test_case_namespacing.c-bpf_gcc-CFLAGS := -Wno-error
-progs/btf_dump_test_case_packing.c-bpf_gcc-CFLAGS := -Wno-error
-progs/btf_dump_test_case_padding.c-bpf_gcc-CFLAGS := -Wno-error
-progs/btf_dump_test_case_syntax.c-bpf_gcc-CFLAGS := -Wno-error
-
endif
ifneq ($(CLANG_CPUV4),)
@@ -156,6 +143,9 @@ ifeq ($(feature-llvm),1)
endif
endif
+# Some utility functions use LLVM libraries
+$(OUTPUT)/jit_disasm_helpers.o: CFLAGS += $(LLVM_CFLAGS)
+
VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
$(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
../../../../vmlinux \
@@ -174,7 +164,7 @@ $(notdir $(TEST_GEN_PROGS) $(TEST_KMODS) \
$(TEST_GEN_PROGS_EXTENDED)): %: $(OUTPUT)/% ;
# sort removes libbpf duplicates when not cross-building
-MAKE_DIRS := $(sort $(BUILD_DIR)/libbpf $(HOST_BUILD_DIR)/libbpf \
+MAKE_DIRS := $(sort $(OUTPUT) $(BUILD_DIR)/libbpf $(HOST_BUILD_DIR)/libbpf \
$(BUILD_DIR)/bpftool $(HOST_BUILD_DIR)/bpftool \
$(HOST_BUILD_DIR)/resolve_btfids \
$(INCLUDE_DIR))
@@ -260,9 +250,31 @@ $(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
$(OUTPUT)/test_tag: $(TESTING_HELPERS)
$(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS) flow_dissector_load.h
-$(OUTPUT)/test_maps: $(TESTING_HELPERS)
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
-$(OUTPUT)/xsk.o: $(BPFOBJ)
+
+# Defined ahead of the first rule that lists it as a prerequisite.
+VERIFY_SIG_HDR := verification_cert.h
+
+# The userspace objects the runner instances link (RUNNER_OBJS, see
+# Makefile.buildvars) are built here, once, so that no runner sub-make
+# ever writes a file this Makefile also builds.
+#
+# $(TRUNNER_BPFTOOL) is a prerequisite because its sub-make is what
+# installs libbpf's internal headers (bpf/hashmap.h, bpf/libbpf_internal.h)
+# into $(INCLUDE_DIR) - the cross-compiled bpftool's when cross-compiling;
+# without it, trace_helpers.c races the install and can silently pick up
+# the source-tree copies instead.
+RUNNER_OBJS := $(sort $(RUNNER_OBJS-test_progs) $(RUNNER_OBJS-test_maps)\
+ $(RUNNER_LIB_OBJS-test_progs))
+$(RUNNER_OBJS): $(VERIFY_SIG_HDR) $(BPFOBJ) $(TRUNNER_BPFTOOL)
+$(OUTPUT)/test_progs.o: prog_tests/tests.h
+$(OUTPUT)/test_maps.o: map_tests/tests.h
+
+# find_bit.c is the only runner source outside this directory,
+# so it needs a rule of its own.
+$(OUTPUT)/find_bit.o: $(TOOLSDIR)/lib/find_bit.c
+ $(call msg,CC,,$@)
+ $(Q)$(CC) $(CFLAGS) -c $< $(LDLIBS) -o $@
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
@@ -331,7 +343,7 @@ endif
# vmlinux.h is first dumped to a temporary file and then compared to
# the previous version. This helps to avoid unnecessary re-builds of
-# $(TRUNNER_BPF_OBJS)
+# BPF objects.
$(INCLUDE_DIR)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
ifeq ($(VMLINUX_H),)
$(call msg,GEN,,$@)
@@ -356,274 +368,6 @@ $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
HOSTPKG_CONFIG='$(PKG_CONFIG)' \
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
-# Build BPF object using Clang
-# $1 - input .c file
-# $2 - output .o file
-# $3 - CFLAGS
-# $4 - binary name
-define CLANG_BPF_BUILD_RULE
- $(call msg,CLNG-BPF,$4,$2)
- $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v3 -o $2 $(call skip_on_fail,BPF)
-endef
-# Similar to CLANG_BPF_BUILD_RULE, but with disabled alu32
-define CLANG_NOALU32_BPF_BUILD_RULE
- $(call msg,CLNG-BPF,$4,$2)
- $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v2 -o $2 $(call skip_on_fail,BPF)
-endef
-# Similar to CLANG_BPF_BUILD_RULE, but with cpu-v4
-define CLANG_CPUV4_BPF_BUILD_RULE
- $(call msg,CLNG-BPF,$4,$2)
- $(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v4 -o $2 $(call skip_on_fail,BPF)
-endef
-# Build BPF object using GCC
-define GCC_BPF_BUILD_RULE
- $(call msg,GCC-BPF,$4,$2)
- $(Q)$(BPF_GCC) $3 -DBPF_NO_PRESERVE_ACCESS_INDEX -Wno-attributes -O2 -c $1 -o $2 $(call skip_on_fail,BPF)
-endef
-
-SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
-
-LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
- linked_vars.skel.h linked_maps.skel.h \
- test_subskeleton.skel.h test_subskeleton_lib.skel.h \
- test_usdt.skel.h tracing_multi.skel.h \
- tracing_multi_module.skel.h \
- tracing_multi_intersect.skel.h \
- tracing_multi_session.skel.h
-
-LSKELS := fexit_sleep.c trace_printk.c trace_vprintk.c map_ptr_kern.c \
- core_kern.c core_kern_overflow.c test_ringbuf.c \
- test_ringbuf_n.c test_ringbuf_map_key.c test_ringbuf_write.c \
- test_ringbuf_overwrite.c
-
-LSKELS_SIGNED := fentry_test.c fexit_test.c atomics.c
-
-# Generate both light skeleton and libbpf skeleton for these
-LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \
- kfunc_call_test_subprog.c test_global_percpu_data.c
-SKEL_BLACKLIST += $$(LSKELS) $$(LSKELS_SIGNED)
-
-test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.bpf.o
-linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
-linked_vars.skel.h-deps := linked_vars1.bpf.o linked_vars2.bpf.o
-linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
-# In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
-# but that's created as a side-effect of the skel.h generation.
-test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
-test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o
-test_usdt.skel.h-deps := test_usdt.bpf.o test_usdt_multispec.bpf.o
-tracing_multi.skel.h-deps := tracing_multi_attach.bpf.o tracing_multi_check.bpf.o
-tracing_multi_module.skel.h-deps := tracing_multi_attach_module.bpf.o tracing_multi_check.bpf.o
-tracing_multi_intersect.skel.h-deps := tracing_multi_intersect_attach.bpf.o tracing_multi_check.bpf.o
-tracing_multi_session.skel.h-deps := tracing_multi_session_attach.bpf.o tracing_multi_check.bpf.o
-
-LINKED_BPF_OBJS := $(foreach skel,$(LINKED_SKELS),$($(skel)-deps))
-LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.c,$(LINKED_BPF_OBJS))
-
-HEADERS_FOR_BPF_OBJS := $(wildcard $(BPFDIR)/*.bpf.h) \
- $(wildcard $(CURDIR)/libarena/include/*.[ch]) \
- $(addprefix $(BPFDIR)/, bpf_core_read.h \
- bpf_endian.h \
- bpf_helpers.h \
- bpf_tracing.h)
-
-# Set up extra TRUNNER_XXX "temporary" variables in the environment (relies on
-# $eval()) and pass control to DEFINE_TEST_RUNNER_RULES.
-# Parameters:
-# $1 - test runner base binary name (e.g., test_progs)
-# $2 - test runner extra "flavor" (e.g., no_alu32, cpuv4, bpf_gcc, etc)
-define DEFINE_TEST_RUNNER
-
-TRUNNER_OUTPUT := $(OUTPUT)$(if $2,/)$2
-TRUNNER_BINARY := $1$(if $2,-)$2
-TRUNNER_TEST_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.test.o, \
- $$(notdir $$(wildcard $(TRUNNER_TESTS_DIR)/*.c)))
-TRUNNER_EXTRA_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \
- $$(filter %.c,$(TRUNNER_EXTRA_SOURCES)))
-TRUNNER_LIB_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \
- $$(filter %.c,$(TRUNNER_LIB_SOURCES)))
-TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES))
-TRUNNER_TESTS_HDR := $(TRUNNER_TESTS_DIR)/tests.h
-TRUNNER_BPF_SRCS := $$(notdir $$(wildcard $(TRUNNER_BPF_PROGS_DIR)/*.c))
-TRUNNER_BPF_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.bpf.o, $$(TRUNNER_BPF_SRCS))
-TRUNNER_BPF_SKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.skel.h, \
- $$(filter-out $(SKEL_BLACKLIST) $(LINKED_BPF_SRCS),\
- $$(TRUNNER_BPF_SRCS)))
-TRUNNER_BPF_LSKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.lskel.h, $$(LSKELS) $$(LSKELS_EXTRA))
-TRUNNER_BPF_SKELS_LINKED := $$(addprefix $$(TRUNNER_OUTPUT)/,$(LINKED_SKELS))
-TRUNNER_BPF_LSKELS_SIGNED := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.lskel.h, $$(LSKELS_SIGNED))
-TEST_GEN_FILES += $$(TRUNNER_BPF_OBJS)
-
-# Evaluate rules now with extra TRUNNER_XXX variables above already defined
-$$(eval $$(call DEFINE_TEST_RUNNER_RULES,$1,$2))
-
-endef
-
-# Using TRUNNER_XXX variables, provided by callers of DEFINE_TEST_RUNNER and
-# set up by DEFINE_TEST_RUNNER itself, create test runner build rules with:
-# $1 - test runner base binary name (e.g., test_progs)
-# $2 - test runner extra "flavor" (e.g., no_alu32, cpuv4, bpf_gcc, etc)
-define DEFINE_TEST_RUNNER_RULES
-
-# Permissive build behaviour (skip-on-failure compile, partial-link) only
-# applies to test_progs and its flavors; runners that use strong cross-object
-# references (e.g. test_maps) keep strict semantics even when permissive.
-# The check is inlined per-runner so $1 is substituted at $(call) time and
-# the result is baked into each rule's recipe.
-
-ifeq ($($(TRUNNER_OUTPUT)-dir),)
-$(TRUNNER_OUTPUT)-dir := y
-$(TRUNNER_OUTPUT):
- $$(call msg,MKDIR,,$$@)
- $(Q)mkdir -p $$@
-endif
-
-# ensure we set up BPF objects generation rule just once for a given
-# input/output directory combination
-ifeq ($($(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs),)
-$(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs := y
-$(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o: \
- $(TRUNNER_BPF_PROGS_DIR)/%.c \
- $(TRUNNER_BPF_PROGS_DIR)/*.h \
- $$(INCLUDE_DIR)/vmlinux.h \
- $(HEADERS_FOR_BPF_OBJS) \
- | $(TRUNNER_OUTPUT) $$(BPFOBJ)
- $$(call $(TRUNNER_BPF_BUILD_RULE),$$<,$$@, \
- $(TRUNNER_BPF_CFLAGS) \
- $$($$<-CFLAGS) \
- $$($$<-$2-CFLAGS),$(TRUNNER_BINARY))
-
-$(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
- $(Q)$$(call skip_if_missing,SKEL,$$<,$$(@:.skel.h=.subskel.h)) \
- printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
- BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh \
- --name $$(notdir $$(<:.bpf.o=)) \
- --skel $$@ --subskel $$(@:.skel.h=.subskel.h) $$< $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h))
-
-$(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
- $(Q)$$(call skip_if_missing,SKEL,$$<) \
- printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
- BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh \
- --name $$(notdir $$(<:.bpf.o=_lskel)) --lskel \
- --skel $$@ $$< $$(call skip_on_fail,SKEL)
-
-$(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
- $(Q)$$(call skip_if_missing,SKEL,$$<) \
- printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY) (signed)] $$(notdir $$@)' 1>&2; \
- BPFTOOL=$$(BPFTOOL) PRIVATE_KEY=$(PRIVATE_KEY) \
- VERIFICATION_CERT=$(VERIFICATION_CERT) \
- ./gen_bpf_skel.sh --sign \
- --name $$(notdir $$(<:.bpf.o=_lskel)) \
- --skel $$@ $$< $$(call skip_on_fail,SKEL)
-
-$(LINKED_BPF_OBJS): %: $(TRUNNER_OUTPUT)/%
-
-# .SECONDEXPANSION here allows to correctly expand %-deps variables as prerequisites
-.SECONDEXPANSION:
-$(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_OUTPUT)/%: $$$$(%-deps) $(BPFTOOL) gen_bpf_skel.sh | $(TRUNNER_OUTPUT)
- $(Q)$$(call skip_if_missing,SKEL,$$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)),$$(@:.skel.h=.subskel.h)) \
- printf ' %-12s %s\n' 'LINK-BPF' '[$(TRUNNER_BINARY)] $$(notdir $$(@:.skel.h=.bpf.o))' 1>&2; \
- printf ' %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
- BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh \
- --name $$(notdir $$(@:.skel.h=)) \
- --skel $$@ --subskel $$(@:.skel.h=.subskel.h) \
- $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)) $$(call skip_on_fail,SKEL,$$(@:.skel.h=.subskel.h))
-
-# When the compiler generates a %.d file, only skel basenames (not
-# full paths) are specified as prerequisites for corresponding %.o
-# file. vpath directives below instruct make to search for skel files
-# in TRUNNER_OUTPUT, if they are not present in the working directory.
-vpath %.skel.h $(TRUNNER_OUTPUT)
-vpath %.lskel.h $(TRUNNER_OUTPUT)
-vpath %.subskel.h $(TRUNNER_OUTPUT)
-
-endif
-
-# ensure we set up tests.h header generation rule just once
-ifeq ($($(TRUNNER_TESTS_DIR)-tests-hdr),)
-$(TRUNNER_TESTS_DIR)-tests-hdr := y
-$(TRUNNER_TESTS_HDR): $(TRUNNER_TESTS_DIR)/*.c
- $$(call msg,TEST-HDR,$(TRUNNER_BINARY),$$@)
- $$(shell (echo '/* Generated header, do not edit */'; \
- sed -n -E 's/^void (serial_)?test_([a-zA-Z0-9_]+)\((void)?\).*/DEFINE_TEST(\2)/p' \
- $(TRUNNER_TESTS_DIR)/*.c | sort ; \
- ) > $$@)
-endif
-
-$(TRUNNER_OUTPUT)/resolve_btfids.test.o: $(RESOLVE_BTFIDS) $(TRUNNER_OUTPUT)/btf_data.bpf.o
-$(TRUNNER_OUTPUT)/resolve_btfids.test.o: private TEST_NEEDS_BTFIDS = 1
-
-# compile individual test files
-# Note: we cd into output directory to ensure embedded BPF object is found
-$(TRUNNER_TEST_OBJS): $(TRUNNER_OUTPUT)/%.test.o: \
- $(TRUNNER_TESTS_DIR)/%.c \
- | $(TRUNNER_OUTPUT)/%.test.d
- $$(call msg,TEST-OBJ,$(TRUNNER_BINARY),$$@)
- $(Q)(cd $$(@D) && $$(CC) -I. $$(CFLAGS) -MMD -MT $$@ -c $(CURDIR)/$$< $$(LDLIBS) -o $$(@F)) $(if $(filter test_progs%,$1),$$(call skip_on_fail,TEST))
- $$(if $$(TEST_NEEDS_BTFIDS), \
- $(Q)if [ -f $$@ ]; then \
- $(if $(filter 1,$(V)),true,printf ' %-8s%s %s\n' "BTFIDS" " [$(TRUNNER_BINARY)]" "$$(notdir $$@)"); \
- $(RESOLVE_BTFIDS) --btf $(TRUNNER_OUTPUT)/btf_data.bpf.o $$@; \
- $(RESOLVE_BTFIDS) --patch_btfids $$@.BTF_ids $$@; \
- fi)
-
-$(TRUNNER_TEST_OBJS:.o=.d): $(TRUNNER_OUTPUT)/%.test.d: \
- $(TRUNNER_TESTS_DIR)/%.c \
- $(TRUNNER_EXTRA_HDRS) \
- $$(BPFOBJ) | $(TRUNNER_OUTPUT) \
- $(TRUNNER_BPF_SKELS) \
- $(TRUNNER_BPF_LSKELS) \
- $(TRUNNER_BPF_LSKELS_SIGNED) \
- $(TRUNNER_BPF_SKELS_LINKED)
-
-ifeq ($(filter clean docs-clean emit_tests,$(MAKECMDGOALS)),)
-include $(wildcard $(TRUNNER_TEST_OBJS:.o=.d))
-endif
-
-# add per extra obj CFGLAGS definitions
-$(foreach N,$(patsubst $(TRUNNER_OUTPUT)/%.o,%,$(TRUNNER_EXTRA_OBJS)), \
- $(eval $(TRUNNER_OUTPUT)/$(N).o: CFLAGS += $($(N).c-CFLAGS)))
-
-$(TRUNNER_EXTRA_OBJS): $(TRUNNER_OUTPUT)/%.o: \
- %.c \
- $(TRUNNER_EXTRA_HDRS) \
- $(VERIFY_SIG_HDR) \
- $(TRUNNER_TESTS_HDR) \
- $$(BPFOBJ) | $(TRUNNER_OUTPUT)
- $$(call msg,EXT-OBJ,$(TRUNNER_BINARY),$$@)
- $(Q)$$(CC) $$(CFLAGS) -c $$< $$(LDLIBS) -o $$@
-
-$(TRUNNER_LIB_OBJS): $(TRUNNER_OUTPUT)/%.o:$(TOOLSDIR)/lib/%.c
- $$(call msg,LIB-OBJ,$(TRUNNER_BINARY),$$@)
- $(Q)$$(CC) $$(CFLAGS) -c $$< $$(LDLIBS) -o $$@
-
-# non-flavored in-srctree builds receive special treatment, in particular, we
-# do not need to copy extra resources (see e.g. test_btf_dump_case())
-$(TRUNNER_BINARY)-extras: $(TRUNNER_EXTRA_FILES) | $(TRUNNER_OUTPUT)
-ifneq ($2:$(OUTPUT),:$(shell pwd))
- $$(call msg,EXT-COPY,$(TRUNNER_BINARY),$(TRUNNER_EXTRA_FILES))
- $(Q)rsync -aq $(if $(PERMISSIVE),--ignore-missing-args) $$^ $(TRUNNER_OUTPUT)/
-endif
-
-# some X.test.o files have runtime dependencies on Y.bpf.o files
-$(OUTPUT)/$(TRUNNER_BINARY): | $(TRUNNER_BPF_OBJS)
-
-$(OUTPUT)/$(TRUNNER_BINARY): $(if $(filter test_progs%,$1),$(if $(PERMISSIVE),$$(wildcard $(TRUNNER_TEST_OBJS)),$(TRUNNER_TEST_OBJS)),$(TRUNNER_TEST_OBJS)) \
- $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ) \
- $(TRUNNER_LIB_OBJS) \
- $(TRUNNER_BPFTOOL) \
- $(OUTPUT)/veristat \
- | $(TRUNNER_BINARY)-extras \
- $(if $(filter test_progs%,$1),$(if $(PERMISSIVE),$(TRUNNER_TEST_OBJS)))
- $$(call msg,BINARY,,$$@)
- $(Q)$$(CC) $$(CFLAGS) $(if $(filter test_progs%,$1),$(if $(PERMISSIVE),$$(filter %.a %.o,$$(wildcard $(TRUNNER_TEST_OBJS)) $$(filter-out $(TRUNNER_TEST_OBJS),$$^)),$$(filter %.a %.o,$$^)),$$(filter %.a %.o,$$^)) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@
- $(Q)ln -sf $(if $2,..,.)/tools/build/bpftool/$(USE_BOOTSTRAP)bpftool \
- $(OUTPUT)/$(if $2,$2/)bpftool
-
-endef
-
-VERIFY_SIG_HDR := verification_cert.h
-
# One genkey run produces both files. A plain two-target rule is not
# grouped - if both files are stale make would run genkey twice, under
# -j concurrently, and the openssl invocations race; the pattern form
@@ -672,76 +416,109 @@ $(LIBARENA_ASAN_SKEL): $(INCLUDE_DIR)/vmlinux.h $(BPFOBJ) $(LIBARENA_BPF_DEPS)
+$(MAKE) -C libarena libarena_asan.skel.h $(LIBARENA_MAKE_ARGS)
endif
-# Define test_progs test runner.
-TRUNNER_TESTS_DIR := prog_tests
-TRUNNER_BPF_PROGS_DIR := progs
-TRUNNER_EXTRA_SOURCES := test_progs.c \
- cgroup_helpers.c \
- trace_helpers.c \
- network_helpers.c \
- testing_helpers.c \
- btf_helpers.c \
- cap_helpers.c \
- unpriv_helpers.c \
- sysctl_helpers.c \
- netlink_helpers.c \
- jit_disasm_helpers.c \
- io_helpers.c \
- test_loader.c \
- xsk.c \
- disasm.c \
- disasm_helpers.c \
- json_writer.c \
- $(VERIFY_SIG_HDR) \
- flow_dissector_load.h \
- ip_check_defrag_frags.h \
- bpftool_helpers.c \
- usdt_1.c usdt_2.c \
- $(LIBARENA_SKEL) \
- $(LIBARENA_ASAN_SKEL)
-TRUNNER_LIB_SOURCES := find_bit.c
-TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read \
- $(OUTPUT)/liburandom_read.so \
- $(OUTPUT)/xdp_synproxy \
- $(OUTPUT)/sign-file \
- $(OUTPUT)/uprobe_multi \
- $(TEST_KMOD_TARGETS) \
- ima_setup.sh \
- $(VERIFY_SIG_SETUP) \
- $(wildcard progs/btf_dump_test_case_*.c) \
- $(wildcard progs/*.bpf.o)
-TRUNNER_BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE
-TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS) -DENABLE_ATOMICS_TESTS
-$(eval $(call DEFINE_TEST_RUNNER,test_progs))
-
-# Define test_progs-no_alu32 test runner.
-TRUNNER_BPF_BUILD_RULE := CLANG_NOALU32_BPF_BUILD_RULE
-TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS)
-$(eval $(call DEFINE_TEST_RUNNER,test_progs,no_alu32))
-
-# Define test_progs-cpuv4 test runner.
+# Generated test list headers
+
+define gen_tests_hdr
+ $(call msg,TEST-HDR,,$@)
+ $(Q)(echo '/* Generated header, do not edit */'; \
+ sed -n -E 's/^void (serial_)?test_([a-zA-Z0-9_]+)\((void)?\).*/DEFINE_TEST(\2)/p' \
+ $(@D)/*.c | sort) > $@
+endef
+
+prog_tests/tests.h: $(wildcard prog_tests/*.c)
+ $(gen_tests_hdr)
+
+map_tests/tests.h: $(wildcard map_tests/*.c)
+ $(gen_tests_hdr)
+
+# Test runner instances, one sub-make each (see Makefile.runner).
+
+# The LLVM feature-probe results and TEST_KMODS are exported
+# to the runner sub-makes. CC is passed explicitly instead: exporting it
+# would also leak lib.mk's CC into the libbpf sub-build, which computes
+# its own. ('export NAME' on an undefined
+# variable creates an empty one, so these stay below the definitions.)
+export LLVM_LDLIBS LLVM_LDFLAGS TEST_KMODS
+export INHERITED_CFLAGS INHERITED_LDFLAGS
+
+RUNNER_MAKE := $(MAKE) -f Makefile.runner OUTPUT=$(OUTPUT) CC='$(CC)' \
+ CLANG='$(CLANG)'
+
+# Everything a runner instance references but does not know how to build.
+RUNNER_PREREQS := $(INCLUDE_DIR)/vmlinux.h $(BPFOBJ) $(BPFTOOL) \
+ $(TRUNNER_BPFTOOL) $(RESOLVE_BTFIDS) \
+ $(OUTPUT)/veristat \
+ $(VERIFY_SIG_HDR) $(PRIVATE_KEY) $(VERIFICATION_CERT) \
+ $(LIBARENA_SKEL) $(LIBARENA_ASAN_SKEL) \
+ prog_tests/tests.h map_tests/tests.h \
+ $(RUNNER_OBJS) \
+ $(OUTPUT)/urandom_read $(OUTPUT)/liburandom_read.so \
+ $(OUTPUT)/xdp_synproxy $(OUTPUT)/sign-file \
+ $(OUTPUT)/uprobe_multi $(TEST_KMOD_TARGETS)
+
+# The main Makefile cannot tell whether $(OUTPUT)/test_progs is stale -
+# only the runner sub-make knows its full dependency graph. FORCE makes
+# the delegating rules below always run; their dependents still rebuild
+# on mtime only.
+FORCE:
+
+# The default flavor's BPF objects and skeletons are consumed here as
+# well as inside the runner sub-makes: bench, xskxceiver, xdp_* and
+# test_cpp depend on individual skeletons, and lib.mk's
+# install rule copies the BPF objects. Instantiate the shared rules
+# (Makefile.skel) for the default flavor, so those consumers depend on
+# exactly the files they use; the unflavored runners' delegation rules
+# below list the whole set as prerequisites, so those sub-makes find the
+# files this Makefile owns up to date.
+RDIR := $(OUTPUT)
+FLAVOR :=
+BINARY := test_progs
+BPF_CC := $(CLANG)
+BPF_CC_MSG := CLNG-BPF
+BPF_SYS_INCLUDES := $(CLANG_SYS_INCLUDES)
+BPF_CC_FLAGS := -O2 $(BPF_TARGET_ENDIAN) -mcpu=v3
+BPF_DEFINES := -DENABLE_ATOMICS_TESTS
+include Makefile.skel
+
+DEFAULT_RUNNER_ARGS := RUNNER=test_progs FLAVOR= TESTS_DIR=prog_tests \
+ BPF_CC='$(BPF_CC)' BPF_CC_MSG=$(BPF_CC_MSG) \
+ BPF_SYS_INCLUDES='$(BPF_SYS_INCLUDES)' \
+ BPF_CC_FLAGS='$(BPF_CC_FLAGS)' BPF_DEFINES=$(BPF_DEFINES)
+
+$(OUTPUT)/test_progs: $(RUNNER_PREREQS) $(BPF_OBJS) $(ALL_SKELS) FORCE
+ +$(Q)$(RUNNER_MAKE) $(DEFAULT_RUNNER_ARGS)
+
+$(OUTPUT)/test_progs-no_alu32: $(RUNNER_PREREQS) FORCE
+ +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR=no_alu32 TESTS_DIR=prog_tests \
+ BPF_CC='$(CLANG)' BPF_CC_MSG=CLNG-BPF BPF_SYS_INCLUDES='$(CLANG_SYS_INCLUDES)' \
+ BPF_CC_FLAGS='-O2 $(BPF_TARGET_ENDIAN) -mcpu=v2'
+
ifneq ($(CLANG_CPUV4),)
-TRUNNER_BPF_BUILD_RULE := CLANG_CPUV4_BPF_BUILD_RULE
-TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS) -DENABLE_ATOMICS_TESTS
-$(eval $(call DEFINE_TEST_RUNNER,test_progs,cpuv4))
+$(OUTPUT)/test_progs-cpuv4: $(RUNNER_PREREQS) FORCE
+ +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR=cpuv4 TESTS_DIR=prog_tests \
+ BPF_CC='$(CLANG)' BPF_CC_MSG=CLNG-BPF BPF_SYS_INCLUDES='$(CLANG_SYS_INCLUDES)' \
+ BPF_CC_FLAGS='-O2 $(BPF_TARGET_ENDIAN) -mcpu=v4' \
+ BPF_DEFINES=-DENABLE_ATOMICS_TESTS
endif
-# Define test_progs BPF-GCC-flavored test runner.
ifneq ($(BPF_GCC),)
-TRUNNER_BPF_BUILD_RULE := GCC_BPF_BUILD_RULE
-TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(call get_sys_includes,gcc,)
-$(eval $(call DEFINE_TEST_RUNNER,test_progs,bpf_gcc))
+# Sys includes come from the *host* gcc, not $(BPF_GCC), as the rule
+# this replaces had it.
+GCC_SYS_INCLUDES := $(call get_sys_includes,gcc,)
+
+$(OUTPUT)/test_progs-bpf_gcc: $(RUNNER_PREREQS) FORCE
+ +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR=bpf_gcc TESTS_DIR=prog_tests \
+ BPF_CC='$(BPF_GCC)' BPF_CC_MSG=GCC-BPF \
+ BPF_SYS_INCLUDES='$(GCC_SYS_INCLUDES)' \
+ BPF_CC_FLAGS='-DBPF_NO_PRESERVE_ACCESS_INDEX -Wno-attributes -O2'
endif
-# Define test_maps test runner.
-TRUNNER_TESTS_DIR := map_tests
-TRUNNER_BPF_PROGS_DIR := progs
-TRUNNER_EXTRA_SOURCES := test_maps.c
-TRUNNER_LIB_SOURCES :=
-TRUNNER_EXTRA_FILES :=
-TRUNNER_BPF_BUILD_RULE := $$(error no BPF objects should be built)
-TRUNNER_BPF_CFLAGS :=
-$(eval $(call DEFINE_TEST_RUNNER,test_maps))
+# test_maps compiles map_tests/*.c against the default flavor's skeletons
+$(OUTPUT)/test_maps: $(RUNNER_PREREQS) $(BPF_OBJS) \
+ $(ALL_SKELS) FORCE
+ +$(Q)$(RUNNER_MAKE) RUNNER=test_maps FLAVOR= TESTS_DIR=map_tests
+
+TEST_GEN_FILES += $(BPF_OBJS)
# Define test_verifier test runner.
# It is much simpler than test_maps/test_progs and sufficiently different from
diff --git a/tools/testing/selftests/bpf/Makefile.buildvars b/tools/testing/selftests/bpf/Makefile.buildvars
index dc0be9ee72bc..5c6c147d03c7 100644
--- a/tools/testing/selftests/bpf/Makefile.buildvars
+++ b/tools/testing/selftests/bpf/Makefile.buildvars
@@ -182,3 +182,15 @@ ifneq ($(CLANG_HAS_ARENA_ASAN),)
LIBARENA_ASAN_SKEL := libarena/libarena_asan.skel.h
CFLAGS += -DHAS_BPF_ARENA_ASAN
endif
+
+RUNNER_OBJS-test_progs := $(addprefix $(OUTPUT)/, \
+ test_progs.o cgroup_helpers.o trace_helpers.o \
+ network_helpers.o testing_helpers.o btf_helpers.o \
+ cap_helpers.o unpriv_helpers.o sysctl_helpers.o \
+ netlink_helpers.o jit_disasm_helpers.o io_helpers.o \
+ test_loader.o xsk.o disasm.o disasm_helpers.o \
+ json_writer.o bpftool_helpers.o usdt_1.o usdt_2.o)
+RUNNER_OBJS-test_maps := $(addprefix $(OUTPUT)/, \
+ test_maps.o testing_helpers.o)
+
+RUNNER_LIB_OBJS-test_progs := $(OUTPUT)/find_bit.o
diff --git a/tools/testing/selftests/bpf/Makefile.runner b/tools/testing/selftests/bpf/Makefile.runner
new file mode 100644
index 000000000000..7361ff7de330
--- /dev/null
+++ b/tools/testing/selftests/bpf/Makefile.runner
@@ -0,0 +1,199 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Build one BPF test-runner instance: test_progs, one of its flavors
+# (no_alu32, cpuv4, bpf_gcc), or test_maps.
+#
+# Each instance is an independent sub-make - the flavored ones with their
+# own output directory, the unflavored ones sharing $(OUTPUT) with the
+# main Makefile - so everything here is written in plain make: no
+# define/eval layer, no per-flavor guards. This file is always
+# invoked by the main Makefile, never directly: all shared
+# prerequisites (libbpf, bpftool,
+# resolve_btfids, vmlinux.h, veristat, userspace objects, signing key,
+# libarena skeletons, extra binaries and - for the
+# unflavored instances - the default flavor's BPF objects and
+# skeletons) are built by the main Makefile *before* this one runs and
+# are referenced below as plain files.
+#
+# Parameters, passed on the sub-make command line:
+# OUTPUT the selftests output directory, as lib.mk resolved it
+# RUNNER base binary name: test_progs | test_maps
+# FLAVOR flavor suffix: empty | no_alu32 | cpuv4 | bpf_gcc
+# TESTS_DIR directory with the test sources: prog_tests | map_tests
+# BPF_CC compiler for progs/*.c BPF objects ($(CLANG) or
+# $(BPF_GCC)); empty for test_maps, which builds none
+# BPF_CC_MSG build-log tag: CLNG-BPF | GCC-BPF
+# BPF_CC_FLAGS
+# compiler-specific flags (-O2, target/-mcpu or gcc knobs)
+# BPF_SYS_INCLUDES
+# system include flags matching BPF_CC
+# BPF_DEFINES extra defines for BPF objects (e.g. -DENABLE_ATOMICS_TESTS)
+# CC, CLANG C compiler and clang (as resolved by lib.mk in the main
+# Makefile; clang also drives the feature probes in
+# Makefile.buildvars)
+#
+# From the environment, exported by the main Makefile:
+# LLVM_LDLIBS/LLVM_LDFLAGS
+# results of the top-level LLVM feature probe
+# TEST_KMODS the kernel test modules to copy into a flavor directory
+# INHERITED_CFLAGS/INHERITED_LDFLAGS
+# the flags the main Makefile inherited from its own
+# environment (see Makefile.buildvars)
+
+include ../../../build/Build.include
+include ../../../scripts/Makefile.arch
+include ../../../scripts/Makefile.include
+
+# Same message helpers as ../lib.mk, which only the top level includes.
+ifeq ($(V),1)
+Q =
+msg =
+else
+Q = @
+msg = @printf ' %-8s%s %s%s\n' "$(1)" "$(if $(2), [$(2)])" "$(notdir $(3))" "$(if $(4), $(4))";
+MAKEFLAGS += --no-print-directory
+endif
+
+# The top Makefile hands down the flags it inherited from the
+# environment in INHERITED_CFLAGS/INHERITED_LDFLAGS; start from those
+# rather than from its assembled CFLAGS/LDFLAGS, which make exports
+# alongside whenever they came from the environment.
+CFLAGS := $(INHERITED_CFLAGS)
+LDFLAGS := $(INHERITED_LDFLAGS)
+
+include Makefile.buildvars
+
+# Keep in sync with the CFLAGS/LDFLAGS additions in ../lib.mk, in its
+# order (the selftests include path is spelled from srctree here; lib.mk
+# spells it from its own directory).
+ifneq ($(LLVM),)
+CFLAGS += -Wno-address-of-packed-member
+CFLAGS += -Wno-gnu-variable-sized-type-not-at-end
+endif
+CFLAGS += -D_GNU_SOURCE=
+CFLAGS += -I$(srctree)/tools/testing/selftests
+CFLAGS += $(USERCFLAGS)
+LDFLAGS += $(USERLDFLAGS)
+
+BINARY := $(RUNNER)$(if $(FLAVOR),-$(FLAVOR))
+RDIR := $(OUTPUT)$(if $(FLAVOR),/$(FLAVOR))
+
+all: $(OUTPUT)/$(BINARY)
+.PHONY: all
+
+# Delete partially updated (corrupted) files on error
+.DELETE_ON_ERROR:
+
+# No built-in rules: every file built here has an explicit rule, and the
+# objects that come from the main Makefile have to be an error when
+# missing rather than a silent rebuild by the built-in %.o recipes.
+MAKEFLAGS += -r
+
+# Permissive build behaviour (skip-on-failure compile, partial-link) only
+# applies to test_progs and its flavors; runners that use strong cross-object
+# references (e.g. test_maps) keep strict semantics even when permissive.
+PERMISSIVE_TESTS := $(if $(filter test_progs,$(RUNNER)),$(PERMISSIVE))
+
+$(RDIR):
+ $(call msg,MKDIR,,$@)
+ $(Q)mkdir -p $@
+
+# ---------------------------------------------------------------------
+# Per-runner sources
+# ---------------------------------------------------------------------
+
+ifeq ($(RUNNER),test_progs)
+GENERATED_HDRS := $(LIBARENA_SKEL) $(LIBARENA_ASAN_SKEL)
+EXTRA_FILES := $(OUTPUT)/urandom_read \
+ $(OUTPUT)/liburandom_read.so \
+ $(OUTPUT)/xdp_synproxy \
+ $(OUTPUT)/sign-file \
+ $(OUTPUT)/uprobe_multi \
+ $(addprefix $(OUTPUT)/,$(TEST_KMODS)) \
+ ima_setup.sh \
+ $(VERIFY_SIG_SETUP) \
+ $(wildcard progs/btf_dump_test_case_*.c) \
+ $(wildcard progs/*.bpf.o)
+endif
+
+TEST_SRCS := $(notdir $(wildcard $(TESTS_DIR)/*.c))
+TEST_OBJS := $(patsubst %.c,$(RDIR)/%.test.o,$(TEST_SRCS))
+TEST_DEPS := $(TEST_OBJS:.o=.d)
+
+# ---------------------------------------------------------------------
+# BPF objects and skeletons - rules shared with the main Makefile
+# ---------------------------------------------------------------------
+
+include Makefile.skel
+
+# When the compiler generates a %.d file, only skel basenames (not
+# full paths) are specified as prerequisites for corresponding %.o
+# file. vpath directives below instruct make to search for skel files
+# in $(RDIR), if they are not present in the working directory.
+vpath %.skel.h $(RDIR)
+vpath %.lskel.h $(RDIR)
+vpath %.subskel.h $(RDIR)
+
+# ---------------------------------------------------------------------
+# Test objects and runner binary
+# ---------------------------------------------------------------------
+
+$(RDIR)/resolve_btfids.test.o: $(RESOLVE_BTFIDS) $(RDIR)/btf_data.bpf.o
+$(RDIR)/resolve_btfids.test.o: private TEST_NEEDS_BTFIDS = 1
+
+# compile individual test files
+# Note: we cd into output directory to ensure embedded BPF object is found
+# The %.test.d dependency files are a side effect of the -MMD below; the
+# separate no-recipe rule for them orders the first compilation after
+# skeleton generation and re-orders test object compilation when headers
+# change.
+$(TEST_OBJS): $(RDIR)/%.test.o: $(TESTS_DIR)/%.c | $(RDIR)/%.test.d
+ $(call msg,TEST-OBJ,$(BINARY),$@)
+ $(Q)(cd $(@D) && $(CC) -I. $(CFLAGS) -MMD -MT $@ -c $(CURDIR)/$< $(LDLIBS) -o $(@F)) \
+ $(if $(PERMISSIVE_TESTS),$(call skip_on_fail,TEST))
+ $(if $(TEST_NEEDS_BTFIDS), \
+ $(Q)if [ -f $@ ]; then \
+ $(if $(filter 1,$(V)),true,printf ' %-8s%s %s\n' "BTFIDS" " [$(BINARY)]" "$(notdir $@)"); \
+ $(RESOLVE_BTFIDS) --btf $(RDIR)/btf_data.bpf.o $@; \
+ $(RESOLVE_BTFIDS) --patch_btfids $@.BTF_ids $@; \
+ fi)
+
+$(TEST_DEPS): $(RDIR)/%.test.d: $(TESTS_DIR)/%.c $(GENERATED_HDRS) $(BPFOBJ) \
+ | $(RDIR) $(ALL_SKELS)
+
+include $(wildcard $(TEST_DEPS))
+
+# non-flavored in-srctree builds receive special treatment, in particular, we
+# do not need to copy extra resources (see e.g. test_btf_dump_case())
+.PHONY: extras
+extras: $(if $(PERMISSIVE),$(wildcard $(EXTRA_FILES)),$(EXTRA_FILES)) | $(RDIR)
+ifneq ($(FLAVOR):$(realpath $(OUTPUT)),:$(CURDIR))
+ifneq ($(strip $(EXTRA_FILES)),)
+ $(call msg,EXT-COPY,$(BINARY),$(EXTRA_FILES))
+ $(Q)rsync -aq $(if $(PERMISSIVE),--ignore-missing-args) $(EXTRA_FILES) $(RDIR)/
+endif
+endif
+
+# some X.test.o files have runtime dependencies on Y.bpf.o files
+# In permissive mode, link whatever test objects were successfully built
+# (their compilation may have been skipped): the objects existing at
+# parse time are normal prerequisites - so editing a test source still
+# relinks the runner - while the full set stays order-only to drive the
+# build attempts, and the wildcard in the recipe picks up the survivors
+# at link time.
+# Prerequisite order is also link order (test objects, runner objects,
+# libbpf, lib objects).
+$(OUTPUT)/$(BINARY): $(if $(PERMISSIVE_TESTS),$(wildcard $(TEST_OBJS)),$(TEST_OBJS)) \
+ $(RUNNER_OBJS-$(RUNNER)) $(BPFOBJ) \
+ $(RUNNER_LIB_OBJS-$(RUNNER)) \
+ $(TRUNNER_BPFTOOL) $(OUTPUT)/veristat \
+ | extras $(BPF_OBJS) \
+ $(if $(PERMISSIVE_TESTS),$(TEST_OBJS))
+ $(call msg,BINARY,,$@)
+ $(Q)$(CC) $(CFLAGS) \
+ $(if $(PERMISSIVE_TESTS),$(wildcard $(TEST_OBJS)) \
+ $(filter-out $(TEST_OBJS),$(filter %.a %.o,$^)),\
+ $(filter %.a %.o,$^)) \
+ $(LDLIBS) $(LLVM_LDLIBS) $(LDFLAGS) $(LLVM_LDFLAGS) -o $@
+ $(Q)ln -sf $(if $(FLAVOR),..,.)/tools/build/bpftool/$(USE_BOOTSTRAP)bpftool \
+ $(RDIR)/bpftool
diff --git a/tools/testing/selftests/bpf/Makefile.skel b/tools/testing/selftests/bpf/Makefile.skel
new file mode 100644
index 000000000000..a871ea76817d
--- /dev/null
+++ b/tools/testing/selftests/bpf/Makefile.skel
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: GPL-2.0
+# Rules to build the BPF objects and skeletons of one build flavor,
+# shared by the main Makefile (which instantiates them for the default
+# flavor, so that bench, xskxceiver, xdp_* and test_cpp can depend on
+# the exact skeletons they consume) and by Makefile.runner (which
+# instantiates them for each runner instance that builds BPF objects:
+# the flavored ones in their own output directories, the unflavored
+# test_progs one in $(OUTPUT), where it finds them already built).
+#
+# Parameters (variables defined by the includer):
+# RDIR output directory of this flavor
+# FLAVOR flavor name, empty for the default
+# BINARY runner binary name, for build-log messages
+# BPF_CC BPF compiler
+# BPF_CC_MSG build-log tag (CLNG-BPF/GCC-BPF)
+# BPF_CC_FLAGS per-flavor compiler flags
+# BPF_SYS_INCLUDES system include flags for $(BPF_CC)
+# BPF_DEFINES extra defines (-DENABLE_ATOMICS_TESTS)
+#
+# The default flavor's rules are instantiated identically by the main
+# Makefile and by the unflavored test_progs sub-make; the main Makefile
+# lists every skeleton and BPF object as a prerequisite of the unflavored
+# runners' delegation rules, so the files are always fresh by the time
+# that sub-make re-evaluates them.
+
+# ---------------------------------------------------------------------
+# BPF objects and skeletons
+# ---------------------------------------------------------------------
+
+ifneq ($(BPF_CC),)
+
+BPF_SRCS := $(notdir $(wildcard progs/*.c))
+BPF_OBJS := $(patsubst %.c,$(RDIR)/%.bpf.o,$(BPF_SRCS))
+
+SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
+
+LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
+ linked_vars.skel.h linked_maps.skel.h \
+ test_subskeleton.skel.h test_subskeleton_lib.skel.h \
+ test_usdt.skel.h tracing_multi.skel.h \
+ tracing_multi_module.skel.h \
+ tracing_multi_intersect.skel.h \
+ tracing_multi_session.skel.h
+
+LSKELS := fexit_sleep.c trace_printk.c trace_vprintk.c map_ptr_kern.c \
+ core_kern.c core_kern_overflow.c test_ringbuf.c \
+ test_ringbuf_n.c test_ringbuf_map_key.c test_ringbuf_write.c \
+ test_ringbuf_overwrite.c
+
+LSKELS_SIGNED := fentry_test.c fexit_test.c atomics.c
+
+# Generate both light skeleton and libbpf skeleton for these
+LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test.c \
+ kfunc_call_test_subprog.c test_global_percpu_data.c
+SKEL_BLACKLIST += $(LSKELS) $(LSKELS_SIGNED)
+
+test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.bpf.o
+linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
+linked_vars.skel.h-deps := linked_vars1.bpf.o linked_vars2.bpf.o
+linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
+# In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
+# but that's created as a side-effect of the skel.h generation.
+test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
+test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o
+test_usdt.skel.h-deps := test_usdt.bpf.o test_usdt_multispec.bpf.o
+tracing_multi.skel.h-deps := tracing_multi_attach.bpf.o tracing_multi_check.bpf.o
+tracing_multi_module.skel.h-deps := tracing_multi_attach_module.bpf.o tracing_multi_check.bpf.o
+tracing_multi_intersect.skel.h-deps := tracing_multi_intersect_attach.bpf.o tracing_multi_check.bpf.o
+tracing_multi_session.skel.h-deps := tracing_multi_session_attach.bpf.o tracing_multi_check.bpf.o
+
+LINKED_BPF_OBJS := $(foreach skel,$(LINKED_SKELS),$($(skel)-deps))
+LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.c,$(LINKED_BPF_OBJS))
+
+SKELS := $(patsubst %.c,$(RDIR)/%.skel.h, \
+ $(filter-out $(SKEL_BLACKLIST) $(LINKED_BPF_SRCS),$(BPF_SRCS)))
+LSKELS_H := $(patsubst %.c,$(RDIR)/%.lskel.h,$(LSKELS) $(LSKELS_EXTRA))
+LSKELS_SIGNED_H := $(patsubst %.c,$(RDIR)/%.lskel.h,$(LSKELS_SIGNED))
+LINKED_SKELS_H := $(addprefix $(RDIR)/,$(LINKED_SKELS))
+ALL_SKELS := $(SKELS) $(LSKELS_H) $(LSKELS_SIGNED_H) $(LINKED_SKELS_H)
+
+HEADERS_FOR_BPF_OBJS := $(wildcard $(BPFDIR)/*.bpf.h) \
+ $(wildcard $(CURDIR)/libarena/include/*.[ch]) \
+ $(addprefix $(BPFDIR)/, bpf_core_read.h \
+ bpf_endian.h \
+ bpf_helpers.h \
+ bpf_tracing.h)
+
+# The following tests contain C code that, although technically legal,
+# triggers GCC warnings that cannot be disabled: declaration of
+# anonymous struct types in function parameter lists.
+progs/btf_dump_test_case_bitfields.c-bpf_gcc-CFLAGS := -Wno-error
+progs/btf_dump_test_case_namespacing.c-bpf_gcc-CFLAGS := -Wno-error
+progs/btf_dump_test_case_packing.c-bpf_gcc-CFLAGS := -Wno-error
+progs/btf_dump_test_case_padding.c-bpf_gcc-CFLAGS := -Wno-error
+progs/btf_dump_test_case_syntax.c-bpf_gcc-CFLAGS := -Wno-error
+
+$(BPF_OBJS): $(RDIR)/%.bpf.o: progs/%.c progs/*.h \
+ $(INCLUDE_DIR)/vmlinux.h $(HEADERS_FOR_BPF_OBJS) \
+ | $(RDIR) $(BPFOBJ)
+ $(call msg,$(BPF_CC_MSG),$(BINARY),$@)
+ $(Q)$(BPF_CC) $(BPF_CFLAGS) $(BPF_SYS_INCLUDES) $(BPF_DEFINES) \
+ $($<-CFLAGS) $($<-$(FLAVOR)-CFLAGS) \
+ $(BPF_CC_FLAGS) -c $< -o $@ $(call skip_on_fail,BPF)
+
+GEN_SKEL := ./gen_bpf_skel.sh
+
+$(SKELS): $(RDIR)/%.skel.h: $(RDIR)/%.bpf.o $(BPFTOOL) $(GEN_SKEL) | $(RDIR)
+ $(Q)$(call skip_if_missing,SKEL,$<,$(@:.skel.h=.subskel.h)) \
+ printf ' %-8s%s %s\n' 'GEN-SKEL' ' [$(BINARY)]' '$(notdir $@)'; \
+ BPFTOOL=$(BPFTOOL) $(GEN_SKEL) --name $* \
+ --skel $@ --subskel $(@:.skel.h=.subskel.h) $< \
+ $(call skip_on_fail,SKEL,$(@:.skel.h=.subskel.h))
+
+$(LSKELS_H): $(RDIR)/%.lskel.h: $(RDIR)/%.bpf.o $(BPFTOOL) $(GEN_SKEL) | $(RDIR)
+ $(Q)$(call skip_if_missing,SKEL,$<) \
+ printf ' %-8s%s %s\n' 'GEN-SKEL' ' [$(BINARY)]' '$(notdir $@)'; \
+ BPFTOOL=$(BPFTOOL) $(GEN_SKEL) --name $*_lskel --lskel \
+ --skel $@ $< $(call skip_on_fail,SKEL)
+
+$(LSKELS_SIGNED_H): $(RDIR)/%.lskel.h: $(RDIR)/%.bpf.o $(BPFTOOL) \
+ $(GEN_SKEL) $(PRIVATE_KEY) $(VERIFICATION_CERT) | $(RDIR)
+ $(Q)$(call skip_if_missing,SKEL,$<) \
+ printf ' %-8s%s %s\n' 'GEN-SKEL' ' [$(BINARY) (signed)]' '$(notdir $@)'; \
+ BPFTOOL=$(BPFTOOL) PRIVATE_KEY=$(PRIVATE_KEY) \
+ VERIFICATION_CERT=$(VERIFICATION_CERT) \
+ $(GEN_SKEL) --sign --name $*_lskel \
+ --skel $@ $< $(call skip_on_fail,SKEL)
+
+# .SECONDEXPANSION here allows to correctly expand %-deps variables as prerequisites
+.SECONDEXPANSION:
+$(LINKED_SKELS_H): $(RDIR)/%.skel.h: $$(addprefix $(RDIR)/,$$($$*.skel.h-deps)) \
+ $(BPFTOOL) $(GEN_SKEL) | $(RDIR)
+ $(Q)$(call skip_if_missing,SKEL,$(addprefix $(RDIR)/,$($*.skel.h-deps)),$(@:.skel.h=.subskel.h)) \
+ printf ' %-8s%s %s\n' 'LINK-BPF' ' [$(BINARY)]' '$(notdir $(@:.skel.h=.bpf.o))'; \
+ printf ' %-8s%s %s\n' 'GEN-SKEL' ' [$(BINARY)]' '$(notdir $@)'; \
+ BPFTOOL=$(BPFTOOL) $(GEN_SKEL) --name $* \
+ --skel $@ --subskel $(@:.skel.h=.subskel.h) \
+ $(addprefix $(RDIR)/,$($*.skel.h-deps)) \
+ $(call skip_on_fail,SKEL,$(@:.skel.h=.subskel.h))
+
+endif # BPF_CC
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make
2026-08-23 19:42 ` [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make Mykola Lysenko
@ 2026-08-23 21:05 ` bot+bpf-ci
2026-08-25 23:55 ` Eduard Zingerman
1 sibling, 0 replies; 19+ messages in thread
From: bot+bpf-ci @ 2026-08-23 21:05 UTC (permalink / raw)
To: nickolay.lysenko, bpf
Cc: ast, daniel, andrii, eddyz87, martin.lau, song, yonghong.song,
jolsa, memxor, nickolay.lysenko, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 12208 bytes --]
> Replace the DEFINE_TEST_RUNNER/DEFINE_TEST_RUNNER_RULES double-expansion
> machinery - whose rules never appear in the source as written, are
> invisible to make's own debugging facilities, and are easy to break
> for one flavor while testing another - with Makefile.runner: one
> sub-make invocation per test runner
> instance (test_progs, test_progs-no_alu32, test_progs-cpuv4,
> test_progs-bpf_gcc, test_maps), each in its own single-flavor namespace
> written in plain make - no define/eval layer, no per-flavor guards,
> no accumulating vpath directives.
> The main Makefile keeps everything that exists once - tool sub-builds,
> vmlinux.h, signing keys, tests.h generation, standalone binaries and
> the kselftest lib.mk contract - and delegates to the runner through
> explicit per-instance rules.
> The rules for one flavor's BPF objects and skeletons live in
> Makefile.skel, instantiated by the main Makefile for the default
> flavor and by each runner sub-make that builds BPF objects. lib.mk's
> install rule copies the default flavor's BPF objects - the files the
> flat copy of every flavor's objects resolved to before. No file is
> built twice in one build: the main Makefile produces the default
> flavor's artifacts before the unflavored test_progs sub-make runs,
> and each flavored runner writes its own subdirectory plus its binary
> in $(OUTPUT) (the bpftool
> link in $(OUTPUT) is refreshed by both unflavored sub-makes, as
> before).
> The runner instances link userspace objects the main Makefile
> builds once; the
> flavored instances link the shared objects instead of compiling
> their own identical copies.
This isn't a bug, but the wrapping looks unusual here. Several lines
break after only a few words in the middle of a sentence (e.g., "with
Makefile.runner: one / sub-make invocation per test runner / instance"
and "and each flavored runner writes its own subdirectory plus its
binary / in $(OUTPUT) (the bpftool / link in $(OUTPUT) is refreshed").
Could the changelog be reflowed to a consistent width? Kernel changelogs
are conventionally wrapped at around 72-75 columns with blank lines
between paragraphs.
> Smaller behaviour changes that come with the move, for the record:
> the skeleton recipes' build-log lines take the msg helper's format
> and stream, the shared userspace objects log as CC rather than
> EXT-OBJ/LIB-OBJ, and TEST-HDR lines lose their runner tag; the signed
> light-skeleton rule lists the key and certificate it uses as
> prerequisites; the extras copy skips an empty file list and, in
> permissive mode, does not wait for files whose build was skipped;
> $(OUTPUT)/test_maps waits for the same shared prerequisites as the
> other runners; the bare-name convenience targets for the
> linked-skeleton constituents (make linked_funcs1.bpf.o) are gone; the
> .d include no longer special-cases the clean, docs-clean and
> emit_tests goals,
> which a runner sub-make never runs; and the test objects' first-build
> ordering lists only the generated headers the runner itself consumes,
> the rest being built by the main Makefile before any runner starts.
This isn't a bug, but the behaviour changes paragraph is written as one
sentence with roughly ten semicolon-separated clauses spanning about 20
lines. At least two of these are user-visible interface changes (the
bare-name convenience targets like "make linked_funcs1.bpf.o" are gone,
and the .d include no longer special-cases clean/docs-clean/emit_tests)
rather than cosmetic log changes.
Could this be turned into a bulleted list with the interface-affecting
changes called out separately?
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
[ ... ]
> @@ -672,76 +416,109 @@
> +$(MAKE) -C libarena libarena_asan.skel.h $(LIBARENA_MAKE_ARGS)
> endif
>
> -# Define test_progs test runner.
> -TRUNNER_TESTS_DIR := prog_tests
> -TRUNNER_BPF_PROGS_DIR := progs
> -TRUNNER_EXTRA_SOURCES := test_progs.c \
> - cgroup_helpers.c \
> - trace_helpers.c \
> - network_helpers.c \
> - testing_helpers.c \
> - btf_helpers.c \
> - cap_helpers.c \
> - unpriv_helpers.c \
> - sysctl_helpers.c \
> - netlink_helpers.c \
> - jit_disasm_helpers.c \
> - io_helpers.c \
> - test_loader.c \
> - xsk.c \
> - disasm.c \
> - disasm_helpers.c \
> - json_writer.c \
> - $(VERIFY_SIG_HDR) \
> - flow_dissector_load.h \
> - ip_check_defrag_frags.h \
> - bpftool_helpers.c \
> - usdt_1.c usdt_2.c \
> - $(LIBARENA_SKEL) \
> - $(LIBARENA_ASAN_SKEL)
> -TRUNNER_LIB_SOURCES := find_bit.c
> -TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read \
> - $(OUTPUT)/liburandom_read.so \
> - $(OUTPUT)/xdp_synproxy \
> - $(OUTPUT)/sign-file \
> - $(OUTPUT)/uprobe_multi \
> - $(TEST_KMOD_TARGETS) \
> - ima_setup.sh \
> - $(VERIFY_SIG_SETUP) \
> - $(wildcard progs/btf_dump_test_case_*.c) \
> - $(wildcard progs/*.bpf.o)
> -TRUNNER_BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE
> -TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS) -DENABLE_ATOMICS_TESTS
> -$(eval $(call DEFINE_TEST_RUNNER,test_progs))
> +# Generated test list headers
> +
> +define gen_tests_hdr
> + $(call msg,TEST-HDR,,$@)
> + $(Q)(echo '/* Generated header, do not edit */'; \
> + sed -n -E 's/^void (serial_)?test_([a-zA-Z0-9_]+)\((void)?\).*/DEFINE_TEST(\2)/p' \
> + $(@D)/*.c | sort) > $@
> +endef
> +
> +prog_tests/tests.h: $(wildcard prog_tests/*.c)
> + $(gen_tests_hdr)
> +
> +map_tests/tests.h: $(wildcard map_tests/*.c)
> + $(gen_tests_hdr)
> +
> +# Test runner instances, one sub-make each (see Makefile.runner).
>
> -# Define test_progs-no_alu32 test runner.
> -TRUNNER_BPF_BUILD_RULE := CLANG_NOALU32_BPF_BUILD_RULE
> -TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS)
> -$(eval $(call DEFINE_TEST_RUNNER,test_progs,no_alu32))
> +# The LLVM feature-probe results and TEST_KMODS are exported
> +# to the runner sub-makes. CC is passed explicitly instead: exporting it
> +# would also leak lib.mk's CC into the libbpf sub-build, which computes
> +# its own. ('export NAME' on an undefined
> +# variable creates an empty one, so these stay below the definitions.)
> +export LLVM_LDLIBS LLVM_LDFLAGS TEST_KMODS
> +export INHERITED_CFLAGS INHERITED_LDFLAGS
>
> -# Define test_progs-cpuv4 test runner.
> +RUNNER_MAKE := $(MAKE) -f Makefile.runner OUTPUT=$(OUTPUT) CC='$(CC)' \
> + CLANG='$(CLANG)'
> +
> +# Everything a runner instance references but does not know how to build.
> +RUNNER_PREREQS := $(INCLUDE_DIR)/vmlinux.h $(BPFOBJ) $(BPFTOOL) \
> + $(TRUNNER_BPFTOOL) $(RESOLVE_BTFIDS) \
> + $(OUTPUT)/veristat \
> + $(VERIFY_SIG_HDR) $(PRIVATE_KEY) $(VERIFICATION_CERT) \
> + $(LIBARENA_SKEL) $(LIBARENA_ASAN_SKEL) \
> + prog_tests/tests.h map_tests/tests.h \
> + $(RUNNER_OBJS) \
> + $(OUTPUT)/urandom_read $(OUTPUT)/liburandom_read.so \
> + $(OUTPUT)/xdp_synproxy $(OUTPUT)/sign-file \
> + $(OUTPUT)/uprobe_multi $(TEST_KMOD_TARGETS)
> +
> +# The main Makefile cannot tell whether $(OUTPUT)/test_progs is stale -
> +# only the runner sub-make knows its full dependency graph. FORCE makes
> +# the delegating rules below always run; their dependents still rebuild
> +# on mtime only.
> +FORCE:
> +
> +# The default flavor's BPF objects and skeletons are consumed here as
> +# well as inside the runner sub-makes: bench, xskxceiver, xdp_* and
> +# test_cpp depend on individual skeletons, and lib.mk's
> +# install rule copies the BPF objects. Instantiate the shared rules
> +# (Makefile.skel) for the default flavor, so those consumers depend on
> +# exactly the files they use; the unflavored runners' delegation rules
> +# below list the whole set as prerequisites, so those sub-makes find the
> +# files this Makefile owns up to date.
> +RDIR := $(OUTPUT)
> +FLAVOR :=
> +BINARY := test_progs
> +BPF_CC := $(CLANG)
> +BPF_CC_MSG := CLNG-BPF
> +BPF_SYS_INCLUDES := $(CLANG_SYS_INCLUDES)
> +BPF_CC_FLAGS := -O2 $(BPF_TARGET_ENDIAN) -mcpu=v3
> +BPF_DEFINES := -DENABLE_ATOMICS_TESTS
> +include Makefile.skel
> +
> +DEFAULT_RUNNER_ARGS := RUNNER=test_progs FLAVOR= TESTS_DIR=prog_tests \
> + BPF_CC='$(BPF_CC)' BPF_CC_MSG=$(BPF_CC_MSG) \
> + BPF_SYS_INCLUDES='$(BPF_SYS_INCLUDES)' \
> + BPF_CC_FLAGS='$(BPF_CC_FLAGS)' BPF_DEFINES=$(BPF_DEFINES)
> +
> +$(OUTPUT)/test_progs: $(RUNNER_PREREQS) $(BPF_OBJS) $(ALL_SKELS) FORCE
> + +$(Q)$(RUNNER_MAKE) $(DEFAULT_RUNNER_ARGS)
> +
> +$(OUTPUT)/test_progs-no_alu32: $(RUNNER_PREREQS) FORCE
> + +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR=no_alu32 TESTS_DIR=prog_tests \
> + BPF_CC='$(CLANG)' BPF_CC_MSG=CLNG-BPF BPF_SYS_INCLUDES='$(CLANG_SYS_INCLUDES)' \
> + BPF_CC_FLAGS='-O2 $(BPF_TARGET_ENDIAN) -mcpu=v2'
> +
> ifneq ($(CLANG_CPUV4),)
> -TRUNNER_BPF_BUILD_RULE := CLANG_CPUV4_BPF_BUILD_RULE
> -TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(CLANG_CFLAGS) -DENABLE_ATOMICS_TESTS
> -$(eval $(call DEFINE_TEST_RUNNER,test_progs,cpuv4))
> +$(OUTPUT)/test_progs-cpuv4: $(RUNNER_PREREQS) FORCE
> + +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR=cpuv4 TESTS_DIR=prog_tests \
> + BPF_CC='$(CLANG)' BPF_CC_MSG=CLNG-BPF BPF_SYS_INCLUDES='$(CLANG_SYS_INCLUDES)' \
> + BPF_CC_FLAGS='-O2 $(BPF_TARGET_ENDIAN) -mcpu=v4' \
> + BPF_DEFINES=-DENABLE_ATOMICS_TESTS
> endif
This isn't a bug, but since DEFAULT_RUNNER_ARGS already factors the
clang argument list, would a shared CLANG_RUNNER_ARGS (with just -mcpu=
and BPF_DEFINES varying per flavor) read better than repeating
BPF_CC/BPF_CC_MSG/BPF_SYS_INCLUDES in each of the three clang flavor
recipes?
> diff --git a/tools/testing/selftests/bpf/Makefile.runner b/tools/testing/selftests/bpf/Makefile.runner
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/Makefile.runner
> @@ -0,0 +1,199 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Build one BPF test-runner instance: test_progs, one of its flavors
> +# (no_alu32, cpuv4, bpf_gcc), or test_maps.
[ ... ]
> +# Keep in sync with the CFLAGS/LDFLAGS additions in ../lib.mk, in its
> +# order (the selftests include path is spelled from srctree here; lib.mk
> +# spells it from its own directory).
> +ifneq ($(LLVM),)
> +CFLAGS += -Wno-address-of-packed-member
> +CFLAGS += -Wno-gnu-variable-sized-type-not-at-end
> +endif
> +CFLAGS += -D_GNU_SOURCE=
> +CFLAGS += -I$(srctree)/tools/testing/selftests
> +CFLAGS += $(USERCFLAGS)
> +LDFLAGS += $(USERLDFLAGS)
The runner rebuilds the CFLAGS that ../lib.mk used to add, but spells
the selftests include path from $(srctree) instead of lib.mk's
$(top_srcdir). These are not equivalent.
lib.mk derives its path from a realpath, so it is always absolute:
tools/testing/selftests/lib.mk:61 top_srcdir = $(selfdir)/../../..
tools/testing/selftests/lib.mk:203 CFLAGS += -I${top_srcdir}/tools/testing/selftests
$(srctree) is exported by the kernel top-level Makefile and is relative
for common cases: '.' for an in-tree build and '..' for a build in a
subdirectory of the source tree. Makefile.buildvars' fallback only fires
when srctree is empty, so it does not normalize a relative value.
The test-object recipe compiles with the working directory changed to
the output directory:
$(Q)(cd $(@D) && $(CC) -I. $(CFLAGS) -MMD -MT $@ -c $(CURDIR)/$< $(LDLIBS) -o $(@F))
so a relative -I is resolved against $(RDIR), not against the source
tree, and the flag silently names a non-existent directory when the bpf
selftests are built through the kernel top level.
The only include in prog_tests/ or map_tests/ that needs that directory
is prog_tests/test_xsk.h's #include "../kselftest.h", and it is
satisfied earlier by COMMON_CFLAGS' -I$(CURDIR), so this does not break
today. Using an absolute spelling here would keep the runner's
compilation environment identical to the top level's in every
configuration. Was the relative-srctree case considered?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32662817569
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make
2026-08-23 19:42 ` [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make Mykola Lysenko
2026-08-23 21:05 ` bot+bpf-ci
@ 2026-08-25 23:55 ` Eduard Zingerman
2026-08-26 4:58 ` Eduard Zingerman
1 sibling, 1 reply; 19+ messages in thread
From: Eduard Zingerman @ 2026-08-25 23:55 UTC (permalink / raw)
To: Mykola Lysenko, bpf
Cc: ast, daniel, andrii, martin.lau, song, yonghong.song, jolsa,
memxor
On Sun, 2026-08-23 at 12:42 -0700, Mykola Lysenko wrote:
...
> The runner sub-makes receive CC and CLANG as resolved by lib.mk on
> their command line: Makefile.buildvars probes clang's capabilities
> with $(CLANG), and a runner has to reach the same verdict as the top
> level when LLVM=<suffix or path> selects a non-default toolchain.
> The unflavored in-tree instance skips the extras copy as before; the
> runner compares the realpath of $(OUTPUT) with $(CURDIR), make's
> physical working directory, so a tree reached through a symlink
> still counts as in-tree. The userspace objects depend on the
> generated tests.h of the runner that includes them only
> (test_progs.o on prog_tests/tests.h, test_maps.o on
> map_tests/tests.h); before, every extra object of a runner depended
> on that runner's tests.h. The other headers those objects depended
> on - flow_dissector_load.h, ip_check_defrag_frags.h, the libarena
> skeletons - are included by none of them and are dropped.
>
> Co-developed-by: Eduard Zingerman <eddyz87@gmail.com>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> Assisted-by: Claude:claude-fable-5 shellcheck
> Signed-off-by: Mykola Lysenko <nickolay.lysenko@gmail.com>
> ---
As a general note, please keep commit messages less verbose.
E.g. if a message spans several pages, I switch to reading patch
directly.
> tools/testing/selftests/bpf/Makefile | 475 +++++-------------
> .../testing/selftests/bpf/Makefile.buildvars | 12 +
> tools/testing/selftests/bpf/Makefile.runner | 199 ++++++++
> tools/testing/selftests/bpf/Makefile.skel | 141 ++++++
> 4 files changed, 478 insertions(+), 349 deletions(-)
> create mode 100644 tools/testing/selftests/bpf/Makefile.runner
> create mode 100644 tools/testing/selftests/bpf/Makefile.skel
>
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 432897613b90..9b9905610070 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
...
> @@ -260,9 +250,31 @@ $(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
> $(OUTPUT)/test_tag: $(TESTING_HELPERS)
> $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
> $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS) flow_dissector_load.h
> -$(OUTPUT)/test_maps: $(TESTING_HELPERS)
> $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
> -$(OUTPUT)/xsk.o: $(BPFOBJ)
> +
> +# Defined ahead of the first rule that lists it as a prerequisite.
> +VERIFY_SIG_HDR := verification_cert.h
> +
> +# The userspace objects the runner instances link (RUNNER_OBJS, see
> +# Makefile.buildvars) are built here, once, so that no runner sub-make
> +# ever writes a file this Makefile also builds.
> +#
> +# $(TRUNNER_BPFTOOL) is a prerequisite because its sub-make is what
> +# installs libbpf's internal headers (bpf/hashmap.h, bpf/libbpf_internal.h)
> +# into $(INCLUDE_DIR) - the cross-compiled bpftool's when cross-compiling;
> +# without it, trace_helpers.c races the install and can silently pick up
> +# the source-tree copies instead.
Nit: I was a bit confused by this comment. Let's compress the last paragraph as:
Helper C files include headers installed to $(INCLUDE_DIR)
by the $(TRUNNER_BPFTOOL) and $(BPFOBJ) targets.
> +RUNNER_OBJS := $(sort $(RUNNER_OBJS-test_progs) $(RUNNER_OBJS-test_maps)\
> + $(RUNNER_LIB_OBJS-test_progs))
> +$(RUNNER_OBJS): $(VERIFY_SIG_HDR) $(BPFOBJ) $(TRUNNER_BPFTOOL)
> +$(OUTPUT)/test_progs.o: prog_tests/tests.h
> +$(OUTPUT)/test_maps.o: map_tests/tests.h
> +
> +# find_bit.c is the only runner source outside this directory,
> +# so it needs a rule of its own.
> +$(OUTPUT)/find_bit.o: $(TOOLSDIR)/lib/find_bit.c
> + $(call msg,CC,,$@)
> + $(Q)$(CC) $(CFLAGS) -c $< $(LDLIBS) -o $@
>
> $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
> $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
> @@ -331,7 +343,7 @@ endif
...
> +DEFAULT_RUNNER_ARGS := RUNNER=test_progs FLAVOR= TESTS_DIR=prog_tests \
> + BPF_CC='$(BPF_CC)' BPF_CC_MSG=$(BPF_CC_MSG) \
> + BPF_SYS_INCLUDES='$(BPF_SYS_INCLUDES)' \
> + BPF_CC_FLAGS='$(BPF_CC_FLAGS)' BPF_DEFINES=$(BPF_DEFINES)
I'd try to join BPF_SYS_INCLUDES and BPF_DEFINES as BPF_CC_FLAGS,
but we can leave it as follow-up.
> +$(OUTPUT)/test_progs: $(RUNNER_PREREQS) $(BPF_OBJS) $(ALL_SKELS) FORCE
> + +$(Q)$(RUNNER_MAKE) $(DEFAULT_RUNNER_ARGS)
> +
> +$(OUTPUT)/test_progs-no_alu32: $(RUNNER_PREREQS) FORCE
> + +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR=no_alu32 TESTS_DIR=prog_tests \
> + BPF_CC='$(CLANG)' BPF_CC_MSG=CLNG-BPF BPF_SYS_INCLUDES='$(CLANG_SYS_INCLUDES)' \
> + BPF_CC_FLAGS='-O2 $(BPF_TARGET_ENDIAN) -mcpu=v2'
...
> diff --git a/tools/testing/selftests/bpf/Makefile.buildvars b/tools/testing/selftests/bpf/Makefile.buildvars
> index dc0be9ee72bc..5c6c147d03c7 100644
> --- a/tools/testing/selftests/bpf/Makefile.buildvars
> +++ b/tools/testing/selftests/bpf/Makefile.buildvars
> @@ -182,3 +182,15 @@ ifneq ($(CLANG_HAS_ARENA_ASAN),)
> LIBARENA_ASAN_SKEL := libarena/libarena_asan.skel.h
> CFLAGS += -DHAS_BPF_ARENA_ASAN
> endif
> +
> +RUNNER_OBJS-test_progs := $(addprefix $(OUTPUT)/, \
> + test_progs.o cgroup_helpers.o trace_helpers.o \
> + network_helpers.o testing_helpers.o btf_helpers.o \
> + cap_helpers.o unpriv_helpers.o sysctl_helpers.o \
> + netlink_helpers.o jit_disasm_helpers.o io_helpers.o \
> + test_loader.o xsk.o disasm.o disasm_helpers.o \
> + json_writer.o bpftool_helpers.o usdt_1.o usdt_2.o)
> +RUNNER_OBJS-test_maps := $(addprefix $(OUTPUT)/, \
> + test_maps.o testing_helpers.o)
> +
> +RUNNER_LIB_OBJS-test_progs := $(OUTPUT)/find_bit.o
Let's merge RUNNER_LIB_OBJS-test_progs into RUNNER_OBJS-test_progs
and drop RUNNER_LIB_OBJS variable.
...
I tested this patch-set for:
- clean build within selftests directory, ok
- minimal rebuild after progs/*.c is touched, ok
- minimal rebuild after prog_tests/*.c is touched, ok
- test_progs, test_verifier, test_progs-cpuv4, test_maps
all work
- build with O= specified, something goes sideways:
the build completes but the tests can't be executed.
For example:
$ make -j O=~/work/tmp/tests-build
In the vm:
# cd /home/eddy/work/tmp/test-build
# ./test_verifier
Failed to load bpf_testmod.ko into the kernel: -8
# ./test_progs -a verifier_and
./test_progs: error while loading shared libraries: libLLVM.so.18.1: cannot open shared object file: No such file or directory
Note the following oddity:
[root@testhost bpf]# ldd ./test_progs
linux-vdso.so.1 (0x00007f8bf85d5000)
libelf.so.1 => /lib64/libelf.so.1 (0x00007f8bf01cd000)
libz.so.1 => /lib64/libz.so.1 (0x00007f8bf01aa000)
libm.so.6 => /lib64/libm.so.6 (0x00007f8bf00bc000)
libzstd.so.1 => /lib64/libzstd.so.1 (0x00007f8befff8000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f8befc00000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f8beffca000)
libc.so.6 => /lib64/libc.so.6 (0x00007f8befa0e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8bf85d7000)
[root@testhost bpf]# cd -
/home/eddy/work/tmp/test-build
[root@testhost test-build]# ldd ./test_progs
linux-vdso.so.1 (0x00007fd8fe342000)
libelf.so.1 => /lib64/libelf.so.1 (0x00007fd8fe319000)
libz.so.1 => /lib64/libz.so.1 (0x00007fd8fe2f6000)
libpcap.so.1 => /lib64/libpcap.so.1 (0x00007fd8fe2a9000)
libLLVM.so.18.1 => not found
libc.so.6 => /lib64/libc.so.6 (0x00007fd8fe0b7000)
libzstd.so.1 => /lib64/libzstd.so.1 (0x00007fd8fdff1000)
libibverbs.so.1 => /lib64/libibverbs.so.1 (0x00007fd8fdfd1000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd8fe344000)
libnl-route-3.so.200 => /lib64/libnl-route-3.so.200 (0x00007fd8fdf3c000)
libnl-3.so.200 => /lib64/libnl-3.so.200 (0x00007fd8fdf1a000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd8fdeee000)
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH bpf-next v7 9/9] selftests/bpf: build each test runner instance in its own sub-make
2026-08-25 23:55 ` Eduard Zingerman
@ 2026-08-26 4:58 ` Eduard Zingerman
0 siblings, 0 replies; 19+ messages in thread
From: Eduard Zingerman @ 2026-08-26 4:58 UTC (permalink / raw)
To: Mykola Lysenko, bpf
Cc: ast, daniel, andrii, martin.lau, song, yonghong.song, jolsa,
memxor
On Tue, 2026-08-25 at 16:55 -0700, Eduard Zingerman wrote:
...
> I tested this patch-set for:
> - clean build within selftests directory, ok
> - minimal rebuild after progs/*.c is touched, ok
> - minimal rebuild after prog_tests/*.c is touched, ok
> - test_progs, test_verifier, test_progs-cpuv4, test_maps
> all work
> - build with O= specified, something goes sideways:
> the build completes but the tests can't be executed.
>
> For example:
>
> $ make -j O=~/work/tmp/tests-build
>
> In the vm:
>
> # cd /home/eddy/work/tmp/test-build
> # ./test_verifier
> Failed to load bpf_testmod.ko into the kernel: -8
>
> # ./test_progs -a verifier_and
> ./test_progs: error while loading shared libraries: libLLVM.so.18.1: cannot open shared object file: No such file or directory
>
> Note the following oddity:
>
> [root@testhost bpf]# ldd ./test_progs
> linux-vdso.so.1 (0x00007f8bf85d5000)
> libelf.so.1 => /lib64/libelf.so.1 (0x00007f8bf01cd000)
> libz.so.1 => /lib64/libz.so.1 (0x00007f8bf01aa000)
> libm.so.6 => /lib64/libm.so.6 (0x00007f8bf00bc000)
> libzstd.so.1 => /lib64/libzstd.so.1 (0x00007f8befff8000)
> libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f8befc00000)
> libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f8beffca000)
> libc.so.6 => /lib64/libc.so.6 (0x00007f8befa0e000)
> /lib64/ld-linux-x86-64.so.2 (0x00007f8bf85d7000)
> [root@testhost bpf]# cd -
> /home/eddy/work/tmp/test-build
> [root@testhost test-build]# ldd ./test_progs
> linux-vdso.so.1 (0x00007fd8fe342000)
> libelf.so.1 => /lib64/libelf.so.1 (0x00007fd8fe319000)
> libz.so.1 => /lib64/libz.so.1 (0x00007fd8fe2f6000)
> libpcap.so.1 => /lib64/libpcap.so.1 (0x00007fd8fe2a9000)
> libLLVM.so.18.1 => not found
> libc.so.6 => /lib64/libc.so.6 (0x00007fd8fe0b7000)
> libzstd.so.1 => /lib64/libzstd.so.1 (0x00007fd8fdff1000)
> libibverbs.so.1 => /lib64/libibverbs.so.1 (0x00007fd8fdfd1000)
> /lib64/ld-linux-x86-64.so.2 (0x00007fd8fe344000)
> libnl-route-3.so.200 => /lib64/libnl-route-3.so.200 (0x00007fd8fdf3c000)
> libnl-3.so.200 => /lib64/libnl-3.so.200 (0x00007fd8fdf1a000)
> libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd8fdeee000)
Redid the testing with O= and the above issue is gone.
Probably an error somewhere between the chain and keyboard.
Sorry for the noise, O= works as expected.
^ permalink raw reply [flat|nested] 19+ messages in thread