Re: [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures

bot+bpf-ci
2026-04-15T21:43:27Z

[-- Attachment #1: Type: text/plain, Size: 3493 bytes --]

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 5c4cdf1dafc8..a305d13409e4 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile

[ ... ]

> @@ -598,47 +602,77 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o:
>
> $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
> - $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
> - $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$<
> - $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o)
> - $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)
> - $(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
> - $(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@
> - $(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h)
> - $(Q)rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
> + $(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then \
> + printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
> + exit 0; \
> + fi;) \

When the .bpf.o prerequisite is missing during an incremental
permissive build, this exits 0 without removing $@ (.skel.h).
If a stale .skel.h remains from a previous successful build,
downstream targets will silently compile against it.

The commit message says "remove failed outputs so downstream rules
can detect absence" -- would adding $(RM) $$@ before exit 0 match
that intent?

> + 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) $(if $(PERMISSIVE),|| { \
> + $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
> + printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
> + }); \
> + rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)

When PERMISSIVE is not set (strict mode, the default), the $(if)
block expands to nothing and this recipe becomes a single shell
command ending with:

... > $$(@:.skel.h=.subskel.h) ; \
rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)

If bpftool or diff fails anywhere in the && chain, the shell skips
to the semicolon and runs rm -f, which always returns 0. Make then
sees exit code 0 from the recipe and continues the build as though
skeleton generation succeeded.

The original code used separate $(Q)-prefixed recipe lines, where
make saw each command's exit code individually and would abort on
failure.

The same pattern appears in the TRUNNER_BPF_LSKELS,
TRUNNER_BPF_LSKELS_SIGNED, and TRUNNER_BPF_SKELS_LINKED rules.

One possible fix would be to capture the exit status before the
cleanup, for example:

... > subskel.h ; rc=$$?; \
rm -f linked1.o linked2.o linked3.o; \
exit $$rc

https://lore.kernel.org/bpf/20260415211532.A56BEC19424@smtp.kernel.org/

---
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/24478691588