From: Mykola Lysenko <nickolay.lysenko@gmail.com>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
eddyz87@gmail.com, martin.lau@linux.dev, song@kernel.org,
yonghong.song@linux.dev, jolsa@kernel.org, memxor@gmail.com,
Mykola Lysenko <nickolay.lysenko@gmail.com>
Subject: [RFC PATCH bpf-next 1/3] selftests/bpf: extract BPF skeleton generation into a helper script
Date: Tue, 21 Jul 2026 10:49:07 -0700 [thread overview]
Message-ID: <20260721174909.8044-2-nickolay.lysenko@gmail.com> (raw)
In-Reply-To: <20260721174909.8044-1-nickolay.lysenko@gmail.com>
The four skeleton generation recipes (regular, light, signed light and
linked) are near-identical five-step 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 flags (--lskel, --sign, --subskel, --infix). The
distinct linked/llinked intermediate infixes are kept: tests listed in
LSKELS_EXTRA generate both a .skel.h and a .lskel.h from the same
.bpf.o, and distinct intermediate names are what keeps parallel builds
from racing. The determinism check gets an escape hatch
(--no-determinism-check) but remains on by default; behavior is
unchanged.
Generated skeletons are byte-identical to the previous recipes' output.
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 | 87 +++++-------------
tools/testing/selftests/bpf/gen_bpf_skel.sh | 97 +++++++++++++++++++++
2 files changed, 119 insertions(+), 65 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 b642ee489..e3a27403c 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -631,81 +631,38 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o: \
$$($$<-$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;) \
- 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)
+ $(Q)BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh --tag '$(TRUNNER_BINARY)' \
+ --name $$(notdir $$(<:.bpf.o=)) --infix linked \
+ --skel $$@ --subskel $$(@:.skel.h=.subskel.h) $$< $(if $(PERMISSIVE),|| { \
+ $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
+ printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; })
$(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;) \
- 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)) > $$@ $(if $(PERMISSIVE),|| { \
- $$(RM) $$@; \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
- rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+ $(Q)BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh --tag '$(TRUNNER_BINARY)' \
+ --name $$(notdir $$(<:.bpf.o=_lskel)) --infix llinked --lskel \
+ --skel $$@ $$< $(if $(PERMISSIVE),|| { \
+ $$(RM) $$@; \
+ printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; })
$(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;) \
- 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)) > $$@ $(if $(PERMISSIVE),|| { \
- $$(RM) $$@; \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
- rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+ $(Q)BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh --tag '$(TRUNNER_BINARY) (signed)' \
+ --name $$(notdir $$(<:.bpf.o=_lskel)) --infix llinked \
+ --sign '$(LSKEL_SIGN)' \
+ --skel $$@ $$< $(if $(PERMISSIVE),|| { \
+ $$(RM) $$@; \
+ printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; })
$(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;) \
- 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) $(if $(PERMISSIVE),|| { \
- $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
- printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
- }) && \
- rm -f $$(@:.skel.h=.linked1.o) $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
+ $(Q)BPFTOOL=$$(BPFTOOL) ./gen_bpf_skel.sh --tag '$(TRUNNER_BINARY)' \
+ --name $$(notdir $$(@:.skel.h=)) --infix linked \
+ --skel $$@ --subskel $$(@:.skel.h=.subskel.h) \
+ $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)) $(if $(PERMISSIVE),|| { \
+ $$(RM) $$@ $$(@:.skel.h=.subskel.h); \
+ printf ' %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; })
# 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 000000000..0b237f639
--- /dev/null
+++ b/tools/testing/selftests/bpf/gen_bpf_skel.sh
@@ -0,0 +1,97 @@
+#!/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 'ARGS' extra "gen skeleton" args for signing (-S -k .. -i ..)
+# --tag TAG build-log tag, e.g. "test_progs-no_alu32"
+# --infix STR intermediate file infix (default: linked). Callers
+# generating both a .skel.h and a .lskel.h from the
+# same .bpf.o MUST use distinct infixes, or parallel
+# builds race on the intermediate files.
+# --no-determinism-check
+# link the inputs once instead of three times.
+# By default the object is re-linked twice more and
+# the 2nd and 3rd results compared, as a regression
+# test for the determinism of "bpftool gen object".
+#
+# 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 Makefile.buildvars).
+
+set -u
+
+bpftool=${BPFTOOL:-bpftool}
+name='' skel='' subskel='' tag='' sign_args='' infix=linked
+lskel=0 det_check=1
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --name) name=$2; shift 2 ;;
+ --skel) skel=$2; shift 2 ;;
+ --subskel) subskel=$2; shift 2 ;;
+ --tag) tag=$2; shift 2 ;;
+ --infix) infix=$2; shift 2 ;;
+ --sign) sign_args=$2; shift 2 ;;
+ --lskel) lskel=1; shift ;;
+ --no-determinism-check) det_check=0; 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
+
+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
+}
+
+if [ $# -gt 1 ]; then
+ printf ' %-12s %s\n' 'LINK-BPF' "${tag:+[$tag] }$(basename "$base").bpf.o" >&2
+fi
+printf ' %-12s %s\n' 'GEN-SKEL' "${tag:+[$tag] }$(basename "$skel")" >&2
+
+"$bpftool" gen object "$t1" "$@" || fail
+final=$t1
+if [ "$det_check" -eq 1 ]; then
+ "$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
+ final=$t3
+fi
+
+flags=
+[ "$lskel" -eq 1 ] && flags=-L
+# $sign_args intentionally unquoted: it is a list of bpftool arguments
+# shellcheck disable=SC2086
+"$bpftool" gen skeleton $sign_args $flags "$final" name "$name" > "$skel" || fail
+
+if [ -n "$subskel" ]; then
+ "$bpftool" gen subskeleton "$final" name "$name" > "$subskel" || fail
+fi
+
+rm -f "$t1" "$t2" "$t3"
+exit 0
--
2.43.0
next prev parent reply other threads:[~2026-07-21 17:49 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-21 17:49 [RFC PATCH bpf-next 0/3] selftests/bpf: restructure the Makefile as a layered build Mykola Lysenko
2026-07-21 17:49 ` Mykola Lysenko [this message]
2026-07-21 17:57 ` [RFC PATCH bpf-next 1/3] selftests/bpf: extract BPF skeleton generation into a helper script sashiko-bot
2026-07-21 19:43 ` Mykola Lysenko
2026-07-21 17:49 ` [RFC PATCH bpf-next 2/3] selftests/bpf: move shared build definitions into Makefile.buildvars Mykola Lysenko
2026-07-21 17:49 ` [RFC PATCH bpf-next 3/3] selftests/bpf: build each test runner instance in its own sub-make Mykola Lysenko
2026-07-21 17:58 ` sashiko-bot
2026-07-21 19:43 ` Mykola Lysenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260721174909.8044-2-nickolay.lysenko@gmail.com \
--to=nickolay.lysenko@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=jolsa@kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.