Re: [RFC PATCH bpf-next v5 8/8] selftests/bpf: build each test runner instance in its own sub-make
Mykola Lysenko <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <CAMtxOX0PJUEv_05aQ_AQmseREAUMeESCK1NC1Sq0hcDsffo5cw@mail.gmail.com> |
On Thu, Aug 6, 2026 at 11:30 AM Eduard Zingerman <[email protected]> wrote: > > On Thu, 2026-08-06 at 01:02 -0700, Eduard Zingerman wrote: > > ... > > > > +# The default flavor's skeletons are also inputs of bench, test_maps, > > > +# xskxceiver, xdp_* and test_cpp; "default-skels" builds just those > > > +# without the test_progs test objects and binary. > > > +.PHONY: default-skels > > > +default-skels: $(RUNNER_PREREQS) > > > + +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR= 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=v3' \ > > > + BPF_DEFINES=-DENABLE_ATOMICS_TESTS skels > > > + > > > +$(OUTPUT)/test_progs: $(RUNNER_PREREQS) default-skels FORCE > > > + +$(Q)$(RUNNER_MAKE) RUNNER=test_progs FLAVOR= 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=v3' \ > > > + BPF_DEFINES=-DENABLE_ATOMICS_TESTS > > > > Is there a way to reduce copy-paste between default-skels and > > test_progs? Why does test_progs depend on default-skels? > > Overall, I don't like the default-skels dependency for `bench` and company. > Previously these depended only on a subset of skel.h/bpf.o files. > But idk if that could be avoided. One option is to extract Makefile.skel > with the rules necessary to build bpf object files, and include it from > Makefile.runner and from the main makefile. Making `bench` and others > depend on the exact set of skels they want. But I'm not sure I like this > option either. > > Please think a bit about this thing, maybe you can come up with > something. I prototyped your Makefile.skel option and I think it is the right call - it comes out simpler than what it replaces, not more complex. The observation that convinced me: it is the same move as your RUNNER_OBJS change, applied to the BPF artifacts. The main Makefile owns everything shared (now including the default flavor's BPF objects and skeletons, via the included rule file instantiated with the default parameters), and a runner instance owns only what is private to it (the flavored artifacts, the test objects, the binary). With the main Makefile able to build any individual skeleton: - bench, xskxceiver, xdp_*, test_cpp and the install list go back to depending on exactly the files they consume - the stock per-target dependency lines, unchanged; - default-skels disappears, and with it the delegation rules and the test_progs-depends-on-default-skels serialization trick you asked about this morning (so the DEFAULT_RUNNER_ARGS deduplication and the two pattern rules from your first mail dissolve rather than get adopted); - every output path has exactly one owner again: the main Makefile writes $(OUTPUT)'s BPF artifacts, each flavored runner writes only its own directory. The unflavored sub-makes include the same rule file, and since the delegating rules list the full artifact set as prerequisites, a runner sub-make always finds them fresh - same file, same rules, so there is no two-lists invariant to maintain. Cold "make bench" builds 19 BPF objects and 19 skeletons with this, versus the full default-flavor pass (982 objects, 1,792 skeleton headers) with default-skels - that was the regression you called out. While folding it in, the file split settled one step further: Makefile.skel is self-contained - the hand-maintained skeleton metadata (the light-skeleton demand lists, LINKED_SKELS with its -deps map, the skeleton blacklist, the BPF-object header list, the per-source flag overrides) sits right next to the derivations and rules that read it, and since both the main Makefile and Makefile.runner include the file, both instantiations read the same data with no second copy to keep in sync. Makefile.buildvars keeps only definitions genuinely shared between files (toolchain, paths, flags, the permissive-mode helpers, the runner link lists). The cost is a fourth makefile and ~20 lines of parameter plumbing in the top Makefile; Makefile.runner shrinks by the extracted section. Functional checks on the prototype: no-op builds stay no-ops, a full build settles, touching one bench prog rebuilds exactly its skeleton, bench object and the binary, and touching a shared prog rebuilds object, signed lskel, test objects and relinks test_progs. The folded version passes the same full A/B as the rest of the series: BPF objects, skeletons and artifact lists match the current Makefile's output modulo the two changes already accounted for (the moved header's recorded paths, the flavored duplicate .o removal). This is folded into v6. > > ...