From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA45752B1C0 for ; Tue, 8 Sep 2026 23:56:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.50 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788911780; cv=none; b=rYd+z1FuKeoXnUCvSHGUE8O+dWjEa+3gvEyrymgH8BBdlzSMJOYLghcQEaxW/2dIfto6/zmIsudJ3GUfv8MVCx54n4Iue+PNUdapbAkyYdx/LdtvCeGymw6dUFXHesx9JUUwcam2giaRY1eTv3hJVvPkg4qj6ZeI+n3W0di/xs0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788911780; c=relaxed/simple; bh=si5BYHD1bgTq9wAEa6AMnCCukVlsdAfPGs0qEMKVd/c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QL6B3lggRoXRlL3WZ5DxjFI1YwDZzzgyLF0O9GpeTXFvAzYHL4NQjkvGLkC2FFhU9ZpPFj3rdwPCpgMJ4p5fvIBo1QPQS0VzfyhI8wLLviNuSnfwwXe6DbnJdB8rtXW2vx2zCu0N2buZBAp9s7oSpNNuYpBA9bTZSEjGqbKp4HA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=W3gYmVQx; arc=none smtp.client-ip=209.85.216.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="W3gYmVQx" Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-38759bcd877so5523629a91.2 for ; Tue, 08 Sep 2026 16:56:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788911777; x=1789516577; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=QBBeCRmmKGr22yzadVUWGqqdMcGSRhOtpXbO4fwPhxw=; b=W3gYmVQxr73Gz10pCbHo1og8G7nHQ58/oBtzSDwmz7uZysPjoNPbXF3AqB2sNChI6I 2VHkdNMw9MSEHKCQxVQPCbpMiTDK4oOFQCu1TuHqK7UiU31zV7nZx8lIf224OCK8fbV4 0dJCYFD5pp0vC8FJ+KpGUbhYZIRt9ygFzlXSFblVG/j/WBn6W25axcN2aZ1Pa3tkTcJy RfgfcLBUT58bfKs75mUaFl0Z5AjepznMBmxG41S8CJNUEu4aOQgDIAU2hH9/KV21Q1SN YylJy5jW+yOR/Y7gOxWc0GAqjVt2FW0GAF2AK1cBAgnu0S8kwRCLEUo+O7txEnYFkf+g IW0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788911777; x=1789516577; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=QBBeCRmmKGr22yzadVUWGqqdMcGSRhOtpXbO4fwPhxw=; b=UivPmaiDs06gpBnDxodzDDvz+L5tMiLTSHHEQVj+8V7fZ3q98ZLVX5UuK6PMY+LNFe 1ioHOtIOOM25SViVqoHjZmXw6h3WvbkNlJ4wUgzwozu5JhJGI+02xkm5afHGtlfiGXl0 6LgyZ6UIByx1SewXhEgKrhj4tsSIDP62SaUXMqzNO4q59xh2vy/fWsaBVElbG/VM9NSq ysy4uzym6AL3nZnDQ4v2W102mThT7PdLI+B2vMcD7L42wTWmgsNK+GwmeoowI/QRwsro LcJGhAUY1gmba35P0xWtL5V24n8Kth+qP6xmXZVUXiZ2AIAuULGjEj8N4QzMGBgOEeXo NpSw== X-Forwarded-Encrypted: i=1; AKwUvBwa6GKXAPlKE7qVXKh4u3CF8BC28nzEPvoybgn3mUqOzYJSFtVI92M0cAB/8GhyAdjWku5IeVqI@vger.kernel.org X-Gm-Message-State: AFuF++nnJ0jAxeqXP3Dw6p004LUeIDE2Rl2D1epb84c7jYc0RbcJsd64 KZ3R6fqNEBXKtpFFlEPxL5dz1kzdvplzNjg60bktLc/ltGFeBJ+MEz7N X-Gm-Gg: AYBFou39WVUGHsit3GinWL160M/GsNoxuQLKX1A8VhdOBAlPuk9JK37oN86o6lSpXko 5aBWy8iNKYE1aOJZKMquApw3guFcpJvThonD8JVWlN28K55N/Gd2S8yG618baLj2yYBkzW1jif+ V22r3FC56Ql0PikHruds0YlcTRuKiSvsaCS3NqB1GiCGL2248SZblunNfg3bxHQd7cXsrZB/0BI mWPwyPj/dZTK1fMCKsf4uLm6GlT1uNo4YBWU0lUYAMvyl/koPjc7ncF0J/NfE2K0hI6/B9NMkd+ 96XhUI+PG4n/571Tgi7Gv/O6fnlUC2+fZq4/jDnndzABkOThQ1kOlPlaqIztXZ9skyWPuu2DdJT mzKASjTyEPlRMwsXKGNi0Iq+e4vv6aDOw2hoql6pSgaq2+l/40gQhurQtVuD2nWYy/TSb2D2X/X xrGsoTyYkByDCuOcF5/BSvDx+OOsJ7K2YPoqKOFkQJLVBjcH+gq394KC0= X-Received: by 2002:a17:90a:fc47:b0:398:9c0c:7c72 with SMTP id 98e67ed59e1d1-39b2627fe24mr43834873a91.25.1788911776798; Tue, 08 Sep 2026 16:56:16 -0700 (PDT) Received: from localhost ([2a03:2880:9ff:64::]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3339b608409sm44492157eec.21.2026.09.08.16.56.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 16:56:16 -0700 (PDT) From: Ziyang Men To: Shuah Khan , Tejun Heo , Johannes Weiner , =?UTF-8?q?Michal=20Koutn=C3=BD?= , Jiri Kosina , Benjamin Tissoires , David Vernet , Eduard Zingerman Cc: Viktor Malik , Andrea Righi , Changwoo Min , Michal Hocko , Roman Gushchin , Shakeel Butt , Muchun Song , Andrew Morton , JP Kobryn , Mykola Lysenko , Nathan Chancellor , Ziyang Men , kernel-team@meta.com, linux-kselftest@vger.kernel.org, cgroups@vger.kernel.org, linux-input@vger.kernel.org, sched-ext@lists.linux.dev, linux-mm@kvack.org, bpf@vger.kernel.org, llvm@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v4 1/4] selftests: add shared lib.bpf.mk to build BPF progs and skeletons Date: Tue, 8 Sep 2026 16:55:49 -0700 Message-ID: <20260908235552.2610256-2-ziyang.meme@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260908235552.2610256-1-ziyang.meme@gmail.com> References: <20260908235552.2610256-1-ziyang.meme@gmail.com> Precedence: bulk X-Mailing-List: cgroups@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The libbpf + bpftool + vmlinux.h + BPF-object + skeleton build tool-chain is currently duplicated across tools/testing/selftests/{bpf,sched_ext, hid}/, each carrying ~100-140 lines of near-identical Makefile. As more subsystems grow BPF-based selftests, the duplication scales poorly. This patch adds tools/testing/selftests/lib.bpf.mk, a single includable fragment that provides the whole chain end-to-end. To use: set BPF_SRCS and OVERRIDE_TARGETS := 1 before including ../lib.mk (so lib.mk's default link rule is suppressed), then include ../lib.bpf.mk and list $(BPF_SKELS) and $(BPFOBJ) as prerequisites of the test binary, e.g.,: BPF_SRCS := progs/foo.bpf.c TEST_GEN_PROGS := foo_test OVERRIDE_TARGETS := 1 include ../lib.mk include ../lib.bpf.mk $(OUTPUT)/foo_test: foo_test.c $(BPF_SKELS) $(BPFOBJ) $(call bpf_link,$@,$<) This eases adding BPF-based selftests in other directories, such as cgroup. Suggested-by: Shakeel Butt Suggested-by: Eduard Zingerman Suggested-by: Mykola Lysenko Assisted-by: Claude:claude-opus-5 Signed-off-by: Ziyang Men --- tools/testing/selftests/lib.bpf.mk | 321 +++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 tools/testing/selftests/lib.bpf.mk diff --git a/tools/testing/selftests/lib.bpf.mk b/tools/testing/selftests/lib.bpf.mk new file mode 100644 index 000000000000..f27cd1889e7f --- /dev/null +++ b/tools/testing/selftests/lib.bpf.mk @@ -0,0 +1,321 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Build BPF programs and skeletons for selftests. +# +# Use it from a test Makefile like this: +# +# BPF_SRCS := foo.bpf.c bar.bpf.c +# TEST_GEN_PROGS := foo_test +# OVERRIDE_TARGETS := 1 # set before lib.mk +# include ../lib.mk +# include ../lib.bpf.mk +# +# $(OUTPUT)/foo_test: foo_test.c $(BPF_SKELS) $(BPFOBJ) +# $(call bpf_link,$@,$<) +# +# Depend on $(BPFOBJ) to relink the test when libbpf.a changes. +# +# Options to set before including lib.bpf.mk: +# BPF_PROG_EXT - source ending; default .bpf.c. Use .c for progs/foo.c. +# BPF_EXTRA_HDRS - more headers needed by the BPF objects. +# BPF_EXTRA_CFLAGS - more flags for compiling BPF programs. +# BPF_SKEL_EXT - skeleton header ending; default .skel.h. Must end in +# skel.h. +# BPF_GEN_SUBSKEL - also create a subskeleton header when set. +# BPF_OBJ_DIR - folder for BPF objects; default $(OUTPUT). +# BPF_SKEL_DIR - folder for skeleton headers; default $(OUTPUT). +# +# Set output directories that use $(OUTPUT) after including lib.mk. +# +# BPF_CFLAGS may be replaced after this include. Generated names use the source +# stem without its directory. +# +# Include lib.mk first. This file defines the BPF build variables and bpf_link, +# extends all, CFLAGS and EXTRA_CLEAN, and enables .DELETE_ON_ERROR. + +include $(top_srcdir)/tools/scripts/Makefile.arch # ARCH / SRCARCH / HOSTARCH + +# Remove partial files written directly to $@. +.DELETE_ON_ERROR: + +# Match the libbpf and bpftool host compiler to LLVM=. +ifneq ($(LLVM),) +HOSTCC ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX) +HOSTLD ?= $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX) +else +HOSTCC ?= gcc +HOSTLD ?= ld +endif +CLANG ?= clang + +ifneq ($(V),1) +lib_bpf_submake_extras := feature_display=0 +endif + +# Match selftests/bpf debug and release optimization. +OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0) + +# ---- files and tools ------------------------------------------------------ +# Use one full path. Different forms of the same -I path can change BTF order. +lib_bpf_tools_dir := $(abspath $(top_srcdir)/tools) +lib_bpf_dir := $(lib_bpf_tools_dir)/lib/bpf +lib_bpf_tools_include_dir := $(lib_bpf_tools_dir)/include +lib_bpf_bpftool_dir := $(lib_bpf_tools_dir)/bpf/bpftool +lib_bpf_api_dir := $(lib_bpf_tools_include_dir)/uapi +lib_bpf_sources := $(wildcard $(lib_bpf_dir)/*.[ch] \ + $(lib_bpf_dir)/Makefile) +lib_bpf_header_sources := $(filter %.h,$(lib_bpf_sources)) \ + $(lib_bpf_api_dir)/linux/bpf.h +# Keep these names for callers which add their own BPF flags or dependencies. +BPFDIR := $(lib_bpf_dir) +APIDIR := $(lib_bpf_api_dir) + +# Keep private build files under $(OUTPUT) for both in-tree and O= builds. +lib_bpf_scratch_dir := $(OUTPUT)/tools +lib_bpf_build_dir := $(lib_bpf_scratch_dir)/build +lib_bpf_include_dir := $(lib_bpf_scratch_dir)/include +# INCLUDE_DIR is also used by callers that replace BPF_CFLAGS. +INCLUDE_DIR := $(lib_bpf_include_dir) +BPFOBJ := $(lib_bpf_build_dir)/libbpf/libbpf.a + +# Cross builds use a separate native libbpf for bpftool. +ifneq ($(CROSS_COMPILE)$(filter-out $(HOSTARCH),$(SRCARCH)),) +lib_bpf_host_build_dir := $(lib_bpf_build_dir)/host +lib_bpf_host_scratch_dir := $(OUTPUT)/host-tools +else +lib_bpf_host_build_dir := $(lib_bpf_build_dir) +lib_bpf_host_scratch_dir := $(lib_bpf_scratch_dir) +endif +lib_bpf_host_obj := $(lib_bpf_host_build_dir)/libbpf/libbpf.a +DEFAULT_BPFTOOL := $(lib_bpf_host_scratch_dir)/sbin/bpftool +BPFTOOL ?= $(DEFAULT_BPFTOOL) + +# Reuse target USERCFLAGS only when bpftool shares the target libbpf. +ifeq ($(BPFOBJ),$(lib_bpf_host_obj)) +lib_bpf_host_user_cflags := $(USERCFLAGS) +endif + +# ---- find vmlinux BTF ----------------------------------------------------- +VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ + $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ + $(top_srcdir)/vmlinux \ + /sys/kernel/btf/vmlinux \ + /boot/vmlinux-$(shell uname -r) +VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) +# Delay missing-vmlinux errors so "make clean" still works. +lib_bpf_vmlinux_deps := $(if $(VMLINUX_H),$(VMLINUX_H),$(VMLINUX_BTF) $(BPFTOOL)) + +# ---- compiler flags ------------------------------------------------------- +# Find the normal system headers that Clang omits with --target=bpf. Put them +# last with -idirafter so they cannot replace project headers. +define lib_bpf_get_sys_includes +$(shell $(1) $(2) -v -E - &1 \ + | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') \ +$(shell $(1) $(2) -dM -E - &1 | \ + grep -q 'v3' && echo v3 || echo v2) + +# Accept anonymous struct and union members in vmlinux.h. +BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ + -I$(INCLUDE_DIR) -I$(APIDIR) \ + -std=gnu11 \ + -fno-strict-aliasing \ + -fms-extensions -Wno-microsoft-anon-tag \ + -Wno-compare-distinct-pointer-types \ + $(CLANG_SYS_INCLUDES) $(BPF_EXTRA_CFLAGS) + +# $1 = source, $2 = object. -MMD -MP tracks non-system headers. +define lib_bpf_build_rule + $(call msg,CLNG-BPF,,$2) + $(Q)$(CLANG) $(BPF_CFLAGS) -O2 --target=bpf -mcpu=$(lib_bpf_clang_cpu) \ + -MMD -MP -c $1 -o $2 +endef + +# ---- output folders ------------------------------------------------------- +BPF_OBJ_DIR ?= $(OUTPUT) +BPF_SKEL_DIR ?= $(OUTPUT) +# Reject empty directories before cleanup globs can reach the filesystem root. +ifeq ($(strip $(BPF_OBJ_DIR)),) +$(error lib.bpf.mk: BPF_OBJ_DIR is empty; set it after "include ../lib.mk") +endif +ifeq ($(strip $(BPF_SKEL_DIR)),) +$(error lib.bpf.mk: BPF_SKEL_DIR is empty; set it after "include ../lib.mk") +endif + +# ---- build folders -------------------------------------------------------- +lib_bpf_make_dirs := $(sort $(lib_bpf_build_dir)/libbpf \ + $(lib_bpf_host_build_dir)/libbpf \ + $(lib_bpf_host_build_dir)/bpftool \ + $(lib_bpf_include_dir) \ + $(filter-out $(OUTPUT),$(BPF_OBJ_DIR) $(BPF_SKEL_DIR))) +$(lib_bpf_make_dirs): + $(call msg,MKDIR,,$@) + $(Q)mkdir -p $@ + +# ---- target libbpf -------------------------------------------------------- +# Pass unexported toolchain settings and build PIC for PIE test binaries. +# libbpf consumes USERCFLAGS through EXTRA_CFLAGS. +$(BPFOBJ): $(lib_bpf_sources) $(lib_bpf_api_dir)/linux/bpf.h \ + | $(lib_bpf_build_dir)/libbpf + $(Q)$(MAKE) $(lib_bpf_submake_extras) -C $(lib_bpf_dir) \ + OUTPUT=$(lib_bpf_build_dir)/libbpf/ \ + ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(CC)" \ + EXTRA_CFLAGS='-g $(OPT_FLAGS) -fPIC $(EXTRA_CFLAGS) $(USERCFLAGS)' \ + DESTDIR=$(lib_bpf_scratch_dir) prefix= all install_headers + +# ---- host libbpf, only when the target differs ---------------------------- +ifneq ($(BPFOBJ),$(lib_bpf_host_obj)) +$(lib_bpf_host_obj): $(lib_bpf_sources) $(lib_bpf_api_dir)/linux/bpf.h \ + | $(lib_bpf_host_build_dir)/libbpf + $(Q)$(MAKE) $(lib_bpf_submake_extras) -C $(lib_bpf_dir) \ + ARCH= CROSS_COMPILE= \ + OUTPUT=$(lib_bpf_host_build_dir)/libbpf/ \ + CC="$(HOSTCC)" LD="$(HOSTLD)" \ + EXTRA_CFLAGS='-g $(OPT_FLAGS) $(EXTRA_CFLAGS)' \ + DESTDIR=$(lib_bpf_host_scratch_dir) prefix= all install_headers +endif + +# ---- host bpftool --------------------------------------------------------- +$(DEFAULT_BPFTOOL): $(wildcard $(lib_bpf_bpftool_dir)/*.[ch] \ + $(lib_bpf_bpftool_dir)/Makefile) \ + $(lib_bpf_host_obj) | $(lib_bpf_host_build_dir)/bpftool + $(Q)$(MAKE) $(lib_bpf_submake_extras) -C $(lib_bpf_bpftool_dir) \ + ARCH= CROSS_COMPILE= CC="$(HOSTCC)" LD="$(HOSTLD)" \ + EXTRA_CFLAGS='-g $(OPT_FLAGS) $(EXTRA_CFLAGS) $(lib_bpf_host_user_cflags)' \ + EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \ + OUTPUT=$(lib_bpf_host_build_dir)/bpftool/ \ + LIBBPF_OUTPUT=$(lib_bpf_host_build_dir)/libbpf/ \ + LIBBPF_DESTDIR=$(lib_bpf_host_scratch_dir)/ \ + prefix= DESTDIR=$(lib_bpf_host_scratch_dir)/ install-bin + +# ---- build vmlinux.h ------------------------------------------------------ +lib_bpf_vmlinux_h := $(INCLUDE_DIR)/vmlinux.h +lib_bpf_vmlinux_stamp := $(INCLUDE_DIR)/vmlinux.h.stamp + +# Preserve vmlinux.h's timestamp when its contents do not change. +ifeq ($(wildcard $(lib_bpf_vmlinux_h)),) +# Regenerate if the header is missing but its stamp remains. +.PHONY: $(lib_bpf_vmlinux_stamp) +endif + +# Use an order-only edge so the stamp's mtime does not propagate. +$(lib_bpf_vmlinux_h): | $(lib_bpf_vmlinux_stamp) ; + +$(lib_bpf_vmlinux_stamp): $(lib_bpf_vmlinux_deps) | $(INCLUDE_DIR) +ifeq ($(VMLINUX_H),) + $(call msg,GEN,,$(lib_bpf_vmlinux_h)) + $(Q)test -n "$(VMLINUX_BTF)" || { \ + echo "lib.bpf.mk: no vmlinux at any of \"$(VMLINUX_BTF_PATHS)\"" >&2; \ + exit 1; } + $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@.tmp +else + $(call msg,CP,,$(lib_bpf_vmlinux_h)) + $(Q)cp "$(VMLINUX_H)" $@.tmp +endif + $(Q)cmp -s $@.tmp $(lib_bpf_vmlinux_h) || mv $@.tmp $(lib_bpf_vmlinux_h) + $(Q)rm -f $@.tmp + $(Q)touch $@ + +# ---- BPF objects and skeletons -------------------------------------------- +BPF_PROG_EXT ?= .bpf.c +# Each source must end with BPF_PROG_EXT so Make can remove that ending. +lib_bpf_bad_srcs := $(filter-out %$(BPF_PROG_EXT),$(BPF_SRCS)) +ifneq ($(lib_bpf_bad_srcs),) +$(error lib.bpf.mk: BPF_SRCS entries must end in $(BPF_PROG_EXT): $(lib_bpf_bad_srcs)) +endif +lib_bpf_stems := $(patsubst %$(BPF_PROG_EXT),%,$(notdir $(BPF_SRCS))) +# The stem becomes the skeleton's C name; reject dots and hyphens. +lib_bpf_bad_stems := $(strip $(foreach s,$(lib_bpf_stems), \ + $(if $(findstring .,$(s))$(findstring -,$(s)),$(s)))) +ifneq ($(lib_bpf_bad_stems),) +$(error lib.bpf.mk: BPF_SRCS basenames must not contain '.' or '-': $(lib_bpf_bad_stems)) +endif +# Output names omit directories, so reject duplicate stems. +ifneq ($(words $(lib_bpf_stems)),$(words $(sort $(lib_bpf_stems)))) +$(error lib.bpf.mk: BPF_SRCS has colliding basenames: $(BPF_SRCS)) +endif +BPF_SKEL_EXT ?= .skel.h +lib_bpf_subskel_ext := $(patsubst %skel.h,%subskel.h,$(BPF_SKEL_EXT)) +# Keep skeleton suffixes distinct and cleanup globs narrow. +ifeq ($(lib_bpf_subskel_ext),$(BPF_SKEL_EXT)) +$(error lib.bpf.mk: BPF_SKEL_EXT must end in skel.h: $(BPF_SKEL_EXT)) +endif +BPF_OBJS := $(addprefix $(BPF_OBJ_DIR)/,$(addsuffix .bpf.o,$(lib_bpf_stems))) +BPF_SKELS := $(addprefix $(BPF_SKEL_DIR)/,$(addsuffix $(BPF_SKEL_EXT),$(lib_bpf_stems))) +ifneq ($(BPF_GEN_SUBSKEL),) +BPF_SUBSKELS := $(addprefix $(BPF_SKEL_DIR)/,$(addsuffix $(lib_bpf_subskel_ext),$(lib_bpf_stems))) +endif + +# Use per-source rules to avoid changing normal .c lookup. +# Track source headers before BPFOBJ installs their updated copies. +define lib_bpf_obj_rule +$(BPF_OBJ_DIR)/$(patsubst %$(BPF_PROG_EXT),%,$(notdir $(1))).bpf.o: $(1) \ + $(BPF_EXTRA_HDRS) $(lib_bpf_header_sources) \ + $(INCLUDE_DIR)/vmlinux.h | $(BPF_OBJ_DIR) $(BPFOBJ) + $$(call lib_bpf_build_rule,$$<,$$@) +endef +$(foreach src,$(BPF_SRCS),$(eval $(call lib_bpf_obj_rule,$(src)))) + +# Generate both headers together so either missing target rebuilds the pair. +lib_bpf_skel_targets := $(BPF_SKEL_DIR)/%$(BPF_SKEL_EXT) +ifneq ($(BPF_GEN_SUBSKEL),) +lib_bpf_skel_targets += $(BPF_SKEL_DIR)/%$(lib_bpf_subskel_ext) +endif + +# Link three times and require the final two objects to match. +$(lib_bpf_skel_targets): $(BPF_OBJ_DIR)/%.bpf.o $(BPFTOOL) | $(BPF_SKEL_DIR) + $(call msg,GEN-SKEL,,$(BPF_SKEL_DIR)/$*$(BPF_SKEL_EXT)) + $(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 $* > $(BPF_SKEL_DIR)/$*$(BPF_SKEL_EXT) +ifneq ($(BPF_GEN_SUBSKEL),) + $(Q)$(BPFTOOL) gen subskeleton $(<:.o=.linked3.o) name $* > $(BPF_SKEL_DIR)/$*$(lib_bpf_subskel_ext) +endif + $(Q)rm -f $(<:.o=.linked1.o) $(<:.o=.linked2.o) $(<:.o=.linked3.o) + +# Read the header dependencies written by -MMD. +-include $(BPF_OBJS:.o=.d) + +# ---- values for the test Makefile ----------------------------------------- +# Add the installed libbpf/vmlinux.h directory and the skeleton directory. +CFLAGS += -I$(INCLUDE_DIR) -I$(BPF_SKEL_DIR) + +# Add target zstd when found by the target pkg-config. +PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config +BPF_LDLIBS := $(BPFOBJ) -lelf -lz +ifneq ($(shell $(PKG_CONFIG) --exists libzstd 2>/dev/null && echo y),) +BPF_LDLIBS += -lzstd +endif + +# Add skeletons after lib.mk defines all. +all: $(BPF_SKELS) $(BPF_SUBSKELS) + +# The skeleton already embeds each BPF object in the test binary. To install the +# objects separately, add TEST_GEN_FILES += $(BPF_OBJS). + +# $1 = binary, $2 = test source. Use the same compile and link flags as lib.mk. +define bpf_link + $(call msg,BINARY,,$1) + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $2 \ + $(BPF_LDLIBS) $(LDLIBS) -o $1 +endef + +EXTRA_CLEAN += $(sort $(lib_bpf_scratch_dir) $(lib_bpf_host_scratch_dir)) \ + $(addprefix $(BPF_OBJ_DIR)/,*.bpf.o *.bpf.d *.linked*.o) \ + $(addprefix $(BPF_SKEL_DIR)/,*$(BPF_SKEL_EXT) *$(lib_bpf_subskel_ext)) -- 2.53.0-Meta