Add shared Rust library build and feature detection support across tools/ and implement the zlib-rs feature check: - Add tools/build/Makefile.rust with helpers to locate Cargo crate sources in distro (/usr/share/cargo/registry) or user Cargo registries, compile .rlib and .a targets with rustc, and resolve C compiler/linker flags via %-cflags and %-libs targets. - Support resolving zlib-rs via LIBZ_RS_DIR, pkg-config (libz-rs-sys-cdylib, zlib-rs, z_rs), or building libz_rs.a (along with libzlib_rs.rlib and liblibc.rlib) into $(OUTPUT)libz_rs/. - Add tools/build/feature/test-zlib-rs.c verifying ZLIB_VER_SUBREVISION == 15 (0xf) and linking against inflateInit(). - Extend tools/build/Build.include and tools/build/Makefile.build with cfgs-to-flags, rlibs-to-externs, per-target RUST_FLAGS/RUST_ENVS, and $(OUTPUT)lib%.rlib: %.rs pattern rules. - Add RUST_TARGET_FLAGS_ cross-compilation triples to tools/scripts/Makefile.arch and the feature_rust_lib helper macro to tools/scripts/Makefile.include. Signed-off-by: Ian Rogers --- tools/build/Build.include | 14 ++- tools/build/Makefile.build | 13 ++- tools/build/Makefile.feature | 9 +- tools/build/Makefile.rust | 149 +++++++++++++++++++++++++++++ tools/build/feature/.gitignore | 1 + tools/build/feature/Makefile | 9 +- tools/build/feature/test-zlib-rs.c | 19 ++++ tools/scripts/Makefile.arch | 14 +++ tools/scripts/Makefile.include | 10 ++ 9 files changed, 229 insertions(+), 9 deletions(-) create mode 100644 tools/build/Makefile.rust create mode 100644 tools/build/feature/test-zlib-rs.c diff --git a/tools/build/Build.include b/tools/build/Build.include index cd0baa7a168d..45b61c31fd4c 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include @@ -100,12 +100,18 @@ cxx_flags = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXX ### # Rust flags to be used on rule definition, includes: +# - cfgs-to-flags helper to turn cfg tokens into --cfg='...' flags +# - rlibs-to-externs helper to map .rlib prerequisites to --extern = # - global $(RUST_FLAGS) -# - per target Rust flags -# - per object Rust flags -rust_flags_1 = $(RUST_FLAGS) $(RUST_FLAGS_$(basetarget).o) $(RUST_FLAGS_$(obj)) -rust_flags_2 = $(filter-out $(RUST_FLAGS_REMOVE_$(basetarget).o), $(rust_flags_1)) +# - per target Rust flags ($(RUST_FLAGS_)) and envs ($(RUST_ENVS_)) +# - per object Rust flags ($(RUST_FLAGS_)) and envs ($(RUST_ENVS_)) +cfgs-to-flags = $(patsubst %,--cfg='%',$1) +rlibs-to-externs = $(foreach rlib,$(filter %.rlib,$1),--extern $(patsubst lib%.rlib,%,$(notdir $(rlib)))=$(rlib)) + +rust_flags_1 = $(RUST_FLAGS) $(RUST_FLAGS_$(basetarget).o) $(RUST_FLAGS_$(notdir $@)) $(RUST_FLAGS_$(obj)) +rust_flags_2 = $(filter-out $(RUST_FLAGS_REMOVE_$(basetarget).o) $(RUST_FLAGS_REMOVE_$(notdir $@)), $(rust_flags_1)) rust_flags = $(filter-out $(RUST_FLAGS_REMOVE_$(obj)), $(rust_flags_2)) +rust_envs = $(RUST_ENVS_$(notdir $@)) $(RUST_ENVS_$(obj)) ### ## HOSTCC C flags diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index ad69efdd4e85..50c3eb57d34b 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build @@ -79,12 +79,15 @@ quiet_cmd_host_ld_multi = HOSTLD $@ xargs $(HOSTLD) -r -o $@,rm -f $@; $(HOSTAR) rcs $@) rust_common_cmd = \ - $(RUSTC) $(rust_flags) \ - --crate-type staticlib -L $(objtree)/rust/ \ + $(rust_envs) $(RUSTC) $(rust_flags) \ + -L $(objtree)/rust/ $(call rlibs-to-externs,$^) \ --emit=dep-info=$(depfile),link +quiet_cmd_rustc_rlib_rs = $(RUSTC) $(quiet_modtag) $@ + cmd_rustc_rlib_rs = $(rust_common_cmd) --crate-type rlib --crate-name $(patsubst lib%.rlib,%,$(notdir $@)) -o $@ $< + quiet_cmd_rustc_a_rs = $(RUSTC) $(quiet_modtag) $@ - cmd_rustc_a_rs = $(rust_common_cmd) -o $@ -g $< $(cmd_objtool) + cmd_rustc_a_rs = $(rust_common_cmd) --crate-type staticlib -o $@ -g $< $(cmd_objtool) ifneq ($(filter $(obj),$(hostprogs)),) host = host_ @@ -117,6 +120,10 @@ $(OUTPUT)%.s: %.c FORCE # it's recommended to build a static rust library, when a foreight (to rust) # linker is used. +$(OUTPUT)lib%.rlib: %.rs FORCE + $(call rule_mkdir) + $(call if_changed_dep,rustc_rlib_rs) + $(OUTPUT)%.a: %.rs FORCE $(call rule_mkdir) $(call if_changed_dep,rustc_a_rs) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 4d37d11f674c..c372600ae9e4 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -5,10 +5,11 @@ ifneq ($(OUTPUT),) OUTPUT_FEATURES = $(OUTPUT)feature/ $(shell mkdir -p $(OUTPUT_FEATURES)) endif +RUST_OUTPUT ?= $(abspath $(or $(OUTPUT),$(CURDIR)))/ feature_check = $(eval $(feature_check_code)) define feature_check_code - feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CC="$(CC)" CXX="$(CXX)" CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) + feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) RUST_OUTPUT="$(RUST_OUTPUT)" CC="$(CC)" CXX="$(CXX)" RUSTC="$(RUSTC)" $(if $(PKG_CONFIG),PKG_CONFIG="$(PKG_CONFIG)") CFLAGS="$(CLANG_CROSS_FLAGS) $(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" CXXFLAGS="$(CLANG_CROSS_FLAGS) $(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" RUST_FLAGS="$(RUST_FLAGS)" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) endef feature_set = $(eval $(feature_set_code)) @@ -128,6 +129,8 @@ FEATURE_TESTS_EXTRA := \ libdebuginfod \ clang-bpf-co-re \ bpftool-skeletons \ + zlib-rs \ + rust \ libunwind \ libunwind-debug-frame \ $(foreach arch,$(LIBUNWIND_ARCHS),libunwind-$(arch) libunwind-debug-frame-$(arch)) @@ -149,6 +152,7 @@ FEATURE_DISPLAY ?= \ libcapstone \ llvm-perf \ zlib \ + zlib-rs \ lzma \ bpf \ libaio \ @@ -216,6 +220,9 @@ ifeq ($(feature-all), 1) $(call feature_check,compile-x32) $(call feature_check,bionic) $(call feature_check,babeltrace2-ctf-writer) + ifneq ($(filter zlib-rs,$(FEATURE_TESTS)),) + $(call feature_check,zlib-rs) + endif $(call feature_check,libunwind) $(call feature_check,libunwind-debug-frame) $(foreach arch,$(LIBUNWIND_ARCHS),$(call feature_check,libunwind-$(arch))) diff --git a/tools/build/Makefile.rust b/tools/build/Makefile.rust new file mode 100644 index 000000000000..cd9e0915b929 --- /dev/null +++ b/tools/build/Makefile.rust @@ -0,0 +1,149 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Shared rules and helpers for discovering and building Rust libraries +# (either from pre-installed packages/pkg-config or from local Cargo crate +# sources) for tools/ builds and feature detection. + +ifeq ($(pound),) +include $(dir $(lastword $(MAKEFILE_LIST)))../scripts/Makefile.include +endif + +ifeq ($(PKG_CONFIG),) + ifneq (, $(shell which $(CROSS_COMPILE)pkg-config 2>/dev/null)) + PKG_CONFIG := $(CROSS_COMPILE)pkg-config + else + PKG_CONFIG := pkg-config + + ifdef CROSS_COMPILE + ifeq ($(PKG_CONFIG_LIBDIR)$(PKG_CONFIG_PATH)$(PKG_CONFIG_SYSROOT_DIR),) + CROSS_ARCH = $(notdir $(CROSS_COMPILE:%-=%)) + PKG_CONFIG_LIBDIR := /usr/local/$(CROSS_ARCH)/lib/pkgconfig/ + PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/local/lib/$(CROSS_ARCH)/pkgconfig/ + PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/lib/$(CROSS_ARCH)/pkgconfig/ + PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/local/share/pkgconfig/ + PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/share/pkgconfig/ + export PKG_CONFIG_LIBDIR + endif + endif + endif +endif + +ifeq ($(findstring -static,${LDFLAGS}),-static) + ifeq ($(findstring --static,$(PKG_CONFIG)),) + PKG_CONFIG += --static + endif +endif + +# Search both distro-packaged Cargo registries (e.g. Debian/Ubuntu +# /usr/share/cargo/registry from librust-*-dev packages) and user Cargo +# registries ($CARGO_HOME/registry/src/* or ~/.cargo/registry/src/*). +# Require a digit after "-" so prefixes like "libc-" do not match +# unrelated crates such as "libc-print-*", and use version sorting (sort -V) +# on the "-" directory basename when multiple versions exist. +CARGO_REGISTRY_DIR ?= /usr/share/cargo/registry $(wildcard $(or $(CARGO_HOME),$(HOME)/.cargo)/registry/src/*) +cargo_crate_dirs = $(strip $(foreach dir,$(CARGO_REGISTRY_DIR),$(wildcard $(dir)/$(1)-[0-9]*))) +cargo_crate_dir = $(if $(word 2,$(call cargo_crate_dirs,$(1))),$(shell printf '%s\n' $(call cargo_crate_dirs,$(1)) | awk -F/ '{print $$NF, $$0}' | sort -k1,1V | tail -n1 | cut -d' ' -f2-),$(call cargo_crate_dirs,$(1))) + +# Extract CARGO_PKG_VERSION* environment variables expected by crates using +# env!("CARGO_PKG_VERSION*") from the "-" directory name. +define cargo_pkg_envs +CARGO_PKG_VERSION=$(patsubst $(1)-%,%,$(notdir $(2))) \ +CARGO_PKG_VERSION_MAJOR=$(word 1,$(subst ., ,$(patsubst $(1)-%,%,$(notdir $(2))))) \ +CARGO_PKG_VERSION_MINOR=$(word 2,$(subst ., ,$(patsubst $(1)-%,%,$(notdir $(2))))) +endef + +# Convert a whitespace-separated list of cfg tokens into --cfg='...' flags. +cfgs-to-flags = $(patsubst %,--cfg='%',$1) + +# Map .rlib prerequisites to explicit --extern = flags. +# Passing explicit paths avoids -L ambiguity with sysroot crates (e.g. E0464 +# when both sysroot and local liblibc.rlib exist). +rlibs-to-externs = $(foreach rlib,$(filter %.rlib,$1),--extern $(patsubst lib%.rlib,%,$(notdir $(rlib)))=$(rlib)) +rustc_common_flags := -C opt-level=3 -C relocation-model=pic + +cmd_rustc_rlib = \ + $(rustc_target_envs) $(RUSTC) $(RUST_FLAGS) $(rustc_common_flags) $(rustc_target_flags) \ + $(call rlibs-to-externs,$^) --crate-type rlib --crate-name $(patsubst lib%.rlib,%,$(notdir $@)) \ + -o $@ $(filter %.rs,$^) > $(@:.rlib=.make.output) 2>&1 + +cmd_rustc_staticlib = \ + $(rustc_target_envs) $(RUSTC) $(RUST_FLAGS) $(rustc_common_flags) $(rustc_target_flags) \ + $(call rlibs-to-externs,$^) --crate-type staticlib --crate-name $(patsubst lib%.a,%,$(notdir $@)) \ + -o $@ $(filter %.rs,$^) > $(@:.a=.make.output) 2>&1 + +# Helper targets invoked by $(call feature_rust_lib,) to query the +# resolved compiler and linker flags for a Rust library feature. +%-cflags: + @echo $(FEATURE_CFLAGS-$*) + +%-libs: + @echo $(FEATURE_LIBS-$*) + +# Place compiled Rust library artifacts in their own subdirectory under the +# build output root (e.g. $(OUTPUT)libz_rs/, alongside libapi/, libbpf/, etc.) +# rather than inside $(OUTPUT)feature/. +RUST_OUTPUT ?= $(patsubst %/feature/,%/,$(OUTPUT)) +LIBZ_RS_OUTPUT ?= $(RUST_OUTPUT)libz_rs/ + +$(LIBZ_RS_OUTPUT): + $(Q)mkdir -p $@ + +# Build chain for libz_rs.a from Cargo crate sources: +# libc (liblibc.rlib) -> zlib-rs (libzlib_rs.rlib) -> libz-rs-sys (libz_rs.a) +LIBC_RS_DIR ?= $(call cargo_crate_dir,libc) +libc-cfgs := feature="default" feature="std" +libc-flags := --edition=2021 $(call cfgs-to-flags,$(libc-cfgs)) + +$(LIBZ_RS_OUTPUT)liblibc.rlib: private rustc_target_flags = $(libc-flags) +$(LIBZ_RS_OUTPUT)liblibc.rlib: $(wildcard $(LIBC_RS_DIR)/src/lib.rs) | $(LIBZ_RS_OUTPUT) + @$(if $<,$(cmd_rustc_rlib),false) + +ZLIB_RS_DIR ?= $(call cargo_crate_dir,zlib-rs) +zlib_rs-cfgs := feature="__internal-api" feature="c-allocator" feature="rust-allocator" feature="std" +zlib_rs-flags := --edition=2021 $(call cfgs-to-flags,$(zlib_rs-cfgs)) + +$(LIBZ_RS_OUTPUT)libzlib_rs.rlib: private rustc_target_flags = $(zlib_rs-flags) +$(LIBZ_RS_OUTPUT)libzlib_rs.rlib: $(wildcard $(ZLIB_RS_DIR)/src/lib.rs) | $(LIBZ_RS_OUTPUT) + @$(if $<,$(cmd_rustc_rlib),false) + +# Enable export-symbols, c-allocator, std, and gz so libz_rs.a exports the +# full standard zlib C ABI (inflate*, deflate*, gz*, etc.) without symbol +# prefixing. +LIBZ_RS_SYS_DIR ?= $(call cargo_crate_dir,libz-rs-sys) +libz_rs_sys-cfgs := feature="export-symbols" feature="c-allocator" feature="std" feature="gz" +libz_rs_sys-flags := --edition=2021 $(call cfgs-to-flags,$(libz_rs_sys-cfgs)) +libz_rs_sys-envs := $(call cargo_pkg_envs,libz-rs-sys,$(LIBZ_RS_SYS_DIR)) + +$(LIBZ_RS_OUTPUT)libz_rs.a: private rustc_target_envs = $(libz_rs_sys-envs) +$(LIBZ_RS_OUTPUT)libz_rs.a: private rustc_target_flags = $(libz_rs_sys-flags) +$(LIBZ_RS_OUTPUT)libz_rs.a: $(wildcard $(LIBZ_RS_SYS_DIR)/src/lib.rs) $(LIBZ_RS_OUTPUT)libzlib_rs.rlib $(LIBZ_RS_OUTPUT)liblibc.rlib | $(LIBZ_RS_OUTPUT) + @$(if $(filter %.rs,$^),$(cmd_rustc_staticlib),false) + +# Resolve zlib-rs flags and libraries in priority order: +# 1. Explicit LIBZ_RS_DIR=/path/to/prefix override +# 2. pkg-config (libz-rs-sys-cdylib, zlib-rs, or z_rs) +# 3. Local Cargo crate sources built into $(LIBZ_RS_OUTPUT)libz_rs.a +ifdef LIBZ_RS_DIR + FEATURE_CFLAGS-zlib-rs := -I$(LIBZ_RS_DIR)/include + FEATURE_LIBS-zlib-rs := -L$(LIBZ_RS_DIR)/lib -lz_rs +endif + +ifeq ($(FEATURE_LIBS-zlib-rs),) + ZLIB_RS_PC := $(shell $(PKG_CONFIG) --exists libz-rs-sys-cdylib 2>/dev/null && echo libz-rs-sys-cdylib || \ + ($(PKG_CONFIG) --exists zlib-rs 2>/dev/null && echo zlib-rs) || \ + ($(PKG_CONFIG) --exists z_rs 2>/dev/null && echo z_rs)) + ifneq ($(ZLIB_RS_PC),) + FEATURE_CFLAGS-zlib-rs := $(shell $(PKG_CONFIG) --cflags $(ZLIB_RS_PC) 2>/dev/null) + FEATURE_LIBS-zlib-rs := $(shell $(PKG_CONFIG) --libs $(ZLIB_RS_PC) 2>/dev/null) + endif +endif + +ifeq ($(FEATURE_LIBS-zlib-rs),) + ifneq ($(and $(ZLIB_RS_DIR),$(LIBZ_RS_SYS_DIR),$(LIBC_RS_DIR)),) + FEATURE_CFLAGS-zlib-rs := -I$(LIBZ_RS_SYS_DIR)/include + FEATURE_STATIC-zlib-rs := $(LIBZ_RS_OUTPUT)libz_rs.a + FEATURE_LIBS-zlib-rs := $(FEATURE_STATIC-zlib-rs) + endif +endif + +zlib-rs-libs: $(FEATURE_STATIC-zlib-rs) diff --git a/tools/build/feature/.gitignore b/tools/build/feature/.gitignore index 15fcd34acdb9..2fb933f84bd0 100644 --- a/tools/build/feature/.gitignore +++ b/tools/build/feature/.gitignore @@ -2,3 +2,4 @@ *.d *.bin *.output +libz_rs/ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 10340a537224..ff41e3d3569a 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -50,6 +50,7 @@ FILES= \ test-compile-32.bin \ test-compile-x32.bin \ test-zlib.bin \ + test-zlib-rs.bin \ test-lzma.bin \ test-bpf.bin \ test-libbpf.bin \ @@ -301,6 +302,11 @@ $(OUTPUT)test-compile-x32.bin: $(OUTPUT)test-zlib.bin: $(BUILD) -lz +include ../Makefile.rust + +$(OUTPUT)test-zlib-rs.bin: $(FEATURE_STATIC-zlib-rs) + $(BUILD) $(FEATURE_CFLAGS-zlib-rs) $(FEATURE_LIBS-zlib-rs) -lpthread -ldl -lm + $(OUTPUT)test-lzma.bin: $(BUILD) -llzma @@ -374,4 +380,5 @@ $(OUTPUT)test-rust.bin: ############################### clean: - rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output) + rm -f $(FILES) $(OUTPUT)*.d $(OUTPUT)*.make.output + rm -rf $(LIBZ_RS_OUTPUT) diff --git a/tools/build/feature/test-zlib-rs.c b/tools/build/feature/test-zlib-rs.c new file mode 100644 index 000000000000..b8729c5135bb --- /dev/null +++ b/tools/build/feature/test-zlib-rs.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +/* + * libz-rs-sys's bundled zlib.h defines ZLIB_VER_SUBREVISION to 15 (0xf) to + * distinguish itself from standard C zlib (which defines it to 0). Verify + * we are including the zlib-rs header and can link against its zlib C ABI. + */ +#if !defined(ZLIB_VER_SUBREVISION) || ZLIB_VER_SUBREVISION != 15 +#error "Not zlib-rs header" +#endif + +int main(void) +{ + z_stream zs; + + inflateInit(&zs); + return 0; +} diff --git a/tools/scripts/Makefile.arch b/tools/scripts/Makefile.arch index ed5f008d400e..d5f25f3be555 100644 --- a/tools/scripts/Makefile.arch +++ b/tools/scripts/Makefile.arch @@ -50,3 +50,17 @@ ifeq ($(LP64), 1) else IS_64_BIT := 0 endif + +# Map kernel ARCH to rustc --target triples when cross-compiling tools/. +ifneq ($(CROSS_COMPILE),) + RUST_TARGET_FLAGS_arm := arm-unknown-linux-gnueabi + RUST_TARGET_FLAGS_arm64 := aarch64-unknown-linux-gnu + RUST_TARGET_FLAGS_loongarch := loongarch64-unknown-linux-gnu + RUST_TARGET_FLAGS_m68k := m68k-unknown-linux-gnu + RUST_TARGET_FLAGS_mips := mipsel-unknown-linux-gnu + RUST_TARGET_FLAGS_powerpc := powerpc64le-unknown-linux-gnu + RUST_TARGET_FLAGS_riscv := riscv64gc-unknown-linux-gnu + RUST_TARGET_FLAGS_s390 := s390x-unknown-linux-gnu + RUST_TARGET_FLAGS_x86 := x86_64-unknown-linux-gnu + RUST_TARGET_FLAGS_x86_64 := x86_64-unknown-linux-gnu +endif diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 378387f62960..72394d245d5d 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -111,6 +111,16 @@ SYSTEM_BPFTOOL ?= bpftool RUSTC ?= rustc +# Query tools/build/Makefile.rust for a Rust library feature's CFLAGS and LIBS +# (building any required staticlib such as libz_rs.a under $(RUST_OUTPUT)), and +# populate FEATURE_CFLAGS- and FEATURE_LIBS-. +define feature_rust_lib_code + FEATURE_RUST_OUTPUT := $$(if $$(RUST_OUTPUT),$$(RUST_OUTPUT),$$(abspath $$(or $$(OUTPUT),$$(CURDIR)))/) + FEATURE_CFLAGS-$(1) := $$(shell $$(MAKE) -s --no-print-directory -f $$(srctree)/tools/build/Makefile.rust $$(if $$(PKG_CONFIG),PKG_CONFIG="$$(PKG_CONFIG)") LDFLAGS="$$(LDFLAGS)" $(1)-cflags) + FEATURE_LIBS-$(1) := $$(shell $$(MAKE) -s --no-print-directory -f $$(srctree)/tools/build/Makefile.rust RUST_OUTPUT="$$(FEATURE_RUST_OUTPUT)" $$(if $$(PKG_CONFIG),PKG_CONFIG="$$(PKG_CONFIG)") RUSTC="$$(RUSTC)" RUST_FLAGS="$$(RUST_FLAGS)" LDFLAGS="$$(LDFLAGS)" $(1)-libs) +endef +feature_rust_lib = $(eval $(feature_rust_lib_code)) + ifeq ($(CC_NO_CLANG), 1) EXTRA_WARNINGS += -Wstrict-aliasing=3 -- 2.56.0.313.g2479322e68-goog Detect and prefer zlib-rs over C zlib in the perf build unless disabled with NO_ZLIB_RS=1 (or NO_ZLIB=1 / NO_RUST=1): - Move Rust compiler detection ahead of zlib detection in tools/perf/Makefile.config and use feature_check + feature_rust_lib for zlib-rs, setting both HAVE_ZLIB_SUPPORT and HAVE_ZLIB_RS_SUPPORT when zlib-rs is used and falling back to C zlib (-lz) otherwise. - Build and clean libz_rs.a in $(OUTPUT)libz_rs/, pass ZLIB_CFLAGS when building static libbpf, and share RUST_OUTPUT with the host bootstrap bpftool build in tools/perf/bpf_skel.mak. - Expose 'zlib-rs' in 'perf check feature' / 'perf version --build-options' and document it in perf-check.txt. - Add zlib-rs package mappings to tools/perf/scripts/install-build-deps.sh and NO_ZLIB / NO_ZLIB_RS build tests to tools/perf/tests/make. Signed-off-by: Ian Rogers --- tools/perf/.gitignore | 1 + tools/perf/Documentation/perf-check.txt | 1 + tools/perf/Makefile.config | 89 ++++++++++++++---------- tools/perf/Makefile.perf | 32 ++++++++- tools/perf/bpf_skel.mak | 8 ++- tools/perf/builtin-check.c | 1 + tools/perf/scripts/install-build-deps.sh | 6 ++ tools/perf/tests/make | 9 +++ 8 files changed, 105 insertions(+), 42 deletions(-) diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 3b968c5158b8..8a5df9c9e8ae 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -55,6 +55,7 @@ libbpf/ libperf/ libsubcmd/ libsymbol/ +libz_rs/ fixdep Documentation/doc.dep python_ext_build/ diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt index 1406a41c5d09..dda75b1d9cbd 100644 --- a/tools/perf/Documentation/perf-check.txt +++ b/tools/perf/Documentation/perf-check.txt @@ -66,6 +66,7 @@ feature:: numa_num_possible_cpus / HAVE_LIBNUMA_SUPPORT python-module / HAVE_PYTHON_MODULE_SUPPORT zlib / HAVE_ZLIB_SUPPORT + zlib-rs / HAVE_ZLIB_RS_SUPPORT zstd / HAVE_ZSTD_SUPPORT OPTIONS diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index b4764f69f47f..4313fca53aa7 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -532,13 +532,57 @@ ifdef CORESIGHT endif endif -ifndef NO_ZLIB - ifeq ($(feature-zlib), 1) - CFLAGS += -DHAVE_ZLIB_SUPPORT - EXTLIBS += -lz - $(call detected,CONFIG_ZLIB) +ifndef NO_RUST + $(call feature_check,rust) + ifneq ($(feature-rust), 1) + $(warning Rust is not found. Test workloads with rust are disabled.) + NO_RUST := 1 else - NO_ZLIB := 1 + NO_RUST := 0 + CFLAGS += -DHAVE_RUST_SUPPORT + $(call detected,CONFIG_RUST_SUPPORT) + endif + + ifneq ($(CROSS_COMPILE),) + ifeq ($(RUST_TARGET_FLAGS_$(ARCH)),) + $(error Unknown rust cross compilation architecture $(ARCH)) + endif + + RUST_FLAGS += --target=$(RUST_TARGET_FLAGS_$(ARCH)) + endif +endif + +# Building zlib-rs from Cargo crate sources requires a working rustc. +ifneq ($(NO_RUST), 0) + NO_ZLIB_RS := 1 +endif + +# Prefer zlib-rs over C zlib when available, unless disabled via NO_ZLIB=1 or +# NO_ZLIB_RS=1. Both provide the standard zlib C API (HAVE_ZLIB_SUPPORT), while +# HAVE_ZLIB_RS_SUPPORT records that zlib-rs is the implementation in use. +ifndef NO_ZLIB + ifndef NO_ZLIB_RS + $(call feature_check,zlib-rs) + ifeq ($(feature-zlib-rs), 1) + ZLIB_RS := 1 + $(call feature_rust_lib,zlib-rs) + ZLIB_CFLAGS := $(FEATURE_CFLAGS-zlib-rs) + ZLIB_LIBS := $(FEATURE_LIBS-zlib-rs) + CFLAGS += -DHAVE_ZLIB_SUPPORT -DHAVE_ZLIB_RS_SUPPORT $(ZLIB_CFLAGS) + EXTLIBS += $(ZLIB_LIBS) + $(call detected,CONFIG_ZLIB) + $(call detected,CONFIG_ZLIB_RS) + endif + endif + ifndef ZLIB_RS + ifeq ($(feature-zlib), 1) + ZLIB_LIBS := -lz + CFLAGS += -DHAVE_ZLIB_SUPPORT + EXTLIBS += $(ZLIB_LIBS) + $(call detected,CONFIG_ZLIB) + else + NO_ZLIB := 1 + endif endif endif @@ -908,7 +952,7 @@ ifdef BUILD_NONDISTRO else ifeq ($(feature-libbfd-liberty), 1) EXTLIBS += -lbfd -lopcodes -liberty else ifeq ($(feature-libbfd-liberty-z), 1) - EXTLIBS += -lbfd -lopcodes -liberty -lz + EXTLIBS += -lbfd -lopcodes -liberty $(ZLIB_LIBS) endif CFLAGS += -DHAVE_LIBBFD_SUPPORT @@ -1132,37 +1176,6 @@ ifneq ($(NO_LIBTRACEEVENT),1) endif endif -ifndef NO_RUST - $(call feature_check,rust) - ifneq ($(feature-rust), 1) - $(warning Rust is not found. Test workloads with rust are disabled.) - NO_RUST := 1 - else - NO_RUST := 0 - CFLAGS += -DHAVE_RUST_SUPPORT - $(call detected,CONFIG_RUST_SUPPORT) - endif - - ifneq ($(CROSS_COMPILE),) - RUST_TARGET_FLAGS_arm := arm-unknown-linux-gnueabi - RUST_TARGET_FLAGS_arm64 := aarch64-unknown-linux-gnu - RUST_TARGET_FLAGS_loongarch := loongarch64-unknown-linux-gnu - RUST_TARGET_FLAGS_m68k := m68k-unknown-linux-gnu - RUST_TARGET_FLAGS_mips := mipsel-unknown-linux-gnu - RUST_TARGET_FLAGS_powerpc := powerpc64le-unknown-linux-gnu - RUST_TARGET_FLAGS_riscv := riscv64gc-unknown-linux-gnu - RUST_TARGET_FLAGS_s390 := s390x-unknown-linux-gnu - RUST_TARGET_FLAGS_x86 := x86_64-unknown-linux-gnu - RUST_TARGET_FLAGS_x86_64 := x86_64-unknown-linux-gnu - - ifeq ($(RUST_TARGET_FLAGS_$(ARCH)),) - $(error Unknown rust cross compilation architecture $(ARCH)) - endif - - RUST_FLAGS += --target=$(RUST_TARGET_FLAGS_$(ARCH)) - endif -endif - # Among the variables below, these: # perfexecdir # libbpf_include_dir diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index b74b534e1153..baad492277df 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -75,6 +75,8 @@ include ../scripts/utilities.mak # # Define NO_ZLIB if you do not want to support compressed kernel modules # +# Define NO_ZLIB_RS if you do not want to use zlib-rs for zlib support +# # Define NO_BABELTRACE2 if you do not want babeltrace2-ctf-writer support # for CTF data format. # @@ -417,6 +419,15 @@ ifdef LIBBPF_STATIC CFLAGS += -I$(LIBBPF_OUTPUT)/include endif +ifneq ($(OUTPUT),) + LIBZ_RS_OUTPUT = $(abspath $(OUTPUT))/libz_rs +else + LIBZ_RS_OUTPUT = $(CURDIR)/libz_rs +endif +ifdef ZLIB_RS + LIBZ_RS = $(filter %/libz_rs.a,$(ZLIB_LIBS)) +endif + ifneq ($(OUTPUT),) LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd else @@ -741,6 +752,11 @@ ifdef LIBBPF_STATIC prepare: $(LIBBPF) endif +ifneq ($(LIBZ_RS),) +prepare: $(LIBZ_RS) +bpf-skel-prepare: $(LIBZ_RS) +endif + $(OUTPUT)%.o: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ @@ -808,12 +824,22 @@ $(LIBAPI)-clean: $(LIBBPF): FORCE | $(LIBBPF_OUTPUT) $(Q)$(MAKE) -C $(LIBBPF_DIR) FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) \ O= OUTPUT=$(LIBBPF_OUTPUT)/ DESTDIR=$(LIBBPF_DESTDIR) prefix= subdir= \ - EXTRA_CFLAGS="-fPIC" $@ install_headers + EXTRA_CFLAGS="-fPIC $(ZLIB_CFLAGS)" $@ install_headers $(LIBBPF)-clean: $(call QUIET_CLEAN, libbpf) $(Q)$(RM) -r -- $(LIBBPF_OUTPUT) +ifneq ($(LIBZ_RS),) +$(LIBZ_RS): | $(LIBZ_RS_OUTPUT) + $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.rust LIBZ_RS_OUTPUT=$(LIBZ_RS_OUTPUT)/ \ + RUSTC="$(RUSTC)" RUST_FLAGS="$(RUST_FLAGS)" $@ +endif + +libz-rs-clean: + $(call QUIET_CLEAN, libz_rs) + $(Q)$(RM) -r -- $(LIBZ_RS_OUTPUT) + $(LIBPERF): FORCE | $(LIBPERF_OUTPUT) $(Q)$(MAKE) -C $(LIBPERF_DIR) O=$(LIBPERF_OUTPUT) \ DESTDIR=$(LIBPERF_DESTDIR) prefix= subdir= \ @@ -1026,7 +1052,7 @@ python-clean: $(RM) $(OUTPUT)python/perf.pyi; \ fi -$(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): +$(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT) $(LIBZ_RS_OUTPUT): $(Q)$(MKDIR) -p $@ bpf-skel-clean: @@ -1050,7 +1076,7 @@ else # When an OUTPUT directory is present, clean up the copied pmu-events/arch endif clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean \ - arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean \ + libz-rs-clean arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean \ pmu-events-clean $(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive \ $(OUTPUT)perf-iostat $(LANG_BINDINGS) diff --git a/tools/perf/bpf_skel.mak b/tools/perf/bpf_skel.mak index f2559de39f96..d2ac4c4a7402 100644 --- a/tools/perf/bpf_skel.mak +++ b/tools/perf/bpf_skel.mak @@ -39,9 +39,15 @@ ifneq ($(WERROR),0) CLANG_OPTIONS += -Werror endif +# When not cross-compiling, share the top-level $(OUTPUT)libz_rs/ directory +# with the host bootstrap bpftool build so libz_rs.a is not compiled twice. +ifeq ($(CROSS_COMPILE),) +BPFTOOL_RUST_OUTPUT := RUST_OUTPUT=$(abspath $(or $(OUTPUT),.))/ +endif + $(BPFTOOL): $(Q)mkdir -p $(SKEL_TOOL_TMP_OUT) - $(Q)CFLAGS= $(MAKE) -C ../bpf/bpftool OUTPUT=$(SKEL_TOOL_TMP_OUT)/ bootstrap + $(Q)CFLAGS= $(MAKE) -C ../bpf/bpftool OUTPUT=$(SKEL_TOOL_TMP_OUT)/ $(BPFTOOL_RUST_OUTPUT) bootstrap # Paths to search for a kernel to generate vmlinux.h from. VMLINUX_BTF_ELF_PATHS ?= $(if $(O),$(O)/vmlinux) \ diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c index 1e43e097e7a7..fe1fc40561a9 100644 --- a/tools/perf/builtin-check.c +++ b/tools/perf/builtin-check.c @@ -59,6 +59,7 @@ struct feature_status supported_features[] = { FEATURE_STATUS("lzma", HAVE_LZMA_SUPPORT), FEATURE_STATUS("numa_num_possible_cpus", HAVE_LIBNUMA_SUPPORT), FEATURE_STATUS("zlib", HAVE_ZLIB_SUPPORT), + FEATURE_STATUS("zlib-rs", HAVE_ZLIB_RS_SUPPORT), FEATURE_STATUS("zstd", HAVE_ZSTD_SUPPORT), FEATURE_STATUS("rust", HAVE_RUST_SUPPORT), diff --git a/tools/perf/scripts/install-build-deps.sh b/tools/perf/scripts/install-build-deps.sh index 3e53c7bf0f85..605dd9073589 100755 --- a/tools/perf/scripts/install-build-deps.sh +++ b/tools/perf/scripts/install-build-deps.sh @@ -146,6 +146,9 @@ fedora_pkg_for() { zlib) echo "zlib-devel" ;; + zlib-rs) + echo "rust-libz-rs-sys-devel" + ;; lzma) echo "xz-devel" ;; @@ -305,6 +308,9 @@ debian_pkg_for() { zlib) echo "zlib1g-dev" ;; + zlib-rs) + echo "librust-libz-rs-sys-dev" + ;; lzma) echo "liblzma-dev" ;; diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 7524de522802..96567d9ea2a4 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -99,6 +99,8 @@ make_no_babeltrace2 := NO_BABELTRACE2=1 make_with_coresight := CORESIGHT=1 make_no_sdt := NO_SDT=1 make_no_libpfm4 := NO_LIBPFM4=1 +make_no_zlib := NO_ZLIB=1 +make_no_zlib_rs := NO_ZLIB_RS=1 make_with_gtk4 := GTK4=1 make_refcnt_check := EXTRA_CFLAGS="-DREFCNT_CHECKING=1" make_tags := tags @@ -193,6 +195,8 @@ run += make_no_sdt run += make_no_babeltrace2 run += make_with_coresight run += make_no_libpfm4 +run += make_no_zlib +run += make_no_zlib_rs run += make_refcnt_check run += make_help run += make_doc @@ -302,6 +306,11 @@ test_make_install_pdf_O := $(test_ok) test_make_libbpf_dynamic := ldd $(PERF_O)/perf | grep -q libbpf test_make_libbpf_dynamic_O := ldd $$TMP_O/perf | grep -q libbpf +test_make_no_zlib := test -x $(PERF_O)/perf && ! $(PERF_O)/perf check -q feature zlib && ! $(PERF_O)/perf check -q feature zlib-rs +test_make_no_zlib_O := test -x $$TMP_O/perf && ! $$TMP_O/perf check -q feature zlib && ! $$TMP_O/perf check -q feature zlib-rs +test_make_no_zlib_rs := test -x $(PERF_O)/perf && ! $(PERF_O)/perf check -q feature zlib-rs +test_make_no_zlib_rs_O := test -x $$TMP_O/perf && ! $$TMP_O/perf check -q feature zlib-rs + # Feature tests are allowed to fail, so a broken C++ compiler command line # doesn't fail the build, it just quietly turns off everything that needs a # C++ compiler. Check a feature that does, otherwise these tests would pass -- 2.56.0.313.g2479322e68-goog Add zlib-rs and zlib to FEATURE_TESTS and FEATURE_DISPLAY in tools/bpf/bpftool/Makefile and use feature_rust_lib to configure ZLIB_CFLAGS and ZLIB_LIBS when zlib-rs is detected, falling back to -lz. Signed-off-by: Ian Rogers --- tools/bpf/bpftool/.gitignore | 1 + tools/bpf/bpftool/Makefile | 56 ++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/.gitignore b/tools/bpf/bpftool/.gitignore index a736f64dc5dc..ea2222373634 100644 --- a/tools/bpf/bpftool/.gitignore +++ b/tools/bpf/bpftool/.gitignore @@ -6,5 +6,6 @@ bpftool*.8 FEATURE-DUMP.bpftool feature libbpf +libz_rs /*.skel.h /vmlinux.h diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index b0f7168e7943..a193cf89a034 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) include ../../scripts/Makefile.include +include ../../scripts/Makefile.arch ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(CURDIR))) @@ -16,6 +17,8 @@ else endif BOOTSTRAP_OUTPUT := $(_OUTPUT)bootstrap/ +LIBZ_RS_OUTPUT := $(_OUTPUT)libz_rs/ + LIBBPF_OUTPUT := $(_OUTPUT)libbpf/ LIBBPF_DESTDIR := $(LIBBPF_OUTPUT) LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)include @@ -38,7 +41,9 @@ $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT) $(LIBBPF_HDRS_DI $(LIBBPF): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_OUTPUT) $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_OUTPUT) \ - DESTDIR=$(LIBBPF_DESTDIR:/=) prefix= $(LIBBPF) install_headers + DESTDIR=$(LIBBPF_DESTDIR:/=) prefix= \ + $(if $(ZLIB_CFLAGS),EXTRA_CFLAGS="$(or $(EXTRA_CFLAGS),-g -O2) $(ZLIB_CFLAGS)") \ + $(LIBBPF) install_headers $(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_HDRS_DIR) $(call QUIET_INSTALL, $@) @@ -115,8 +120,20 @@ ifneq ($(SKIP_CRYPTO),1) CRYPTO_LIBS := -lcrypto endif +ifneq ($(CROSS_COMPILE),) + ifneq ($(MAKECMDGOALS),bootstrap) + ifneq ($(RUST_TARGET_FLAGS_$(ARCH)),) + RUST_FLAGS += --target=$(RUST_TARGET_FLAGS_$(ARCH)) + else + NO_ZLIB_RS := 1 + endif + else + NO_ZLIB_RS := 1 + endif +endif + ifeq ($(MAKECMDGOALS),bootstrap) -FEATURE_TESTS := libelf-zstd +FEATURE_TESTS := libelf-zstd $(if $(NO_ZLIB_RS),,zlib-rs) zlib FEATURE_DISPLAY := else FEATURE_TESTS := clang-bpf-co-re @@ -128,6 +145,10 @@ FEATURE_TESTS += libbfd-liberty-z FEATURE_TESTS += disassembler-four-args FEATURE_TESTS += disassembler-init-styled FEATURE_TESTS += libelf-zstd +ifeq ($(NO_ZLIB_RS),) +FEATURE_TESTS += zlib-rs +endif +FEATURE_TESTS += zlib FEATURE_DISPLAY := clang-bpf-co-re FEATURE_DISPLAY += llvm @@ -135,6 +156,10 @@ FEATURE_DISPLAY += libcap FEATURE_DISPLAY += libbfd FEATURE_DISPLAY += libbfd-liberty FEATURE_DISPLAY += libbfd-liberty-z +ifeq ($(NO_ZLIB_RS),) +FEATURE_DISPLAY += zlib-rs +endif +FEATURE_DISPLAY += zlib endif check_feat := 1 @@ -153,8 +178,27 @@ include $(FEATURES_DUMP) endif endif -LIBS = $(LIBBPF) -lelf $(CRYPTO_LIBS) -lz -LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf $(CRYPTO_LIBS) -lz +# Prefer zlib-rs over C zlib when detected. When cross-compiling, the host +# bootstrap bpftool still links against the host's -lz. +ifeq ($(feature-zlib-rs),1) + $(call feature_rust_lib,zlib-rs) + ZLIB_CFLAGS := $(FEATURE_CFLAGS-zlib-rs) + ZLIB_LIBS := $(FEATURE_LIBS-zlib-rs) + CFLAGS += $(ZLIB_CFLAGS) + ifeq ($(CROSS_COMPILE),) + HOST_CFLAGS += $(ZLIB_CFLAGS) + LIBBPF_BOOTSTRAP_CFLAGS += $(ZLIB_CFLAGS) + ZLIB_BOOTSTRAP_LIBS := $(ZLIB_LIBS) + else + ZLIB_BOOTSTRAP_LIBS := -lz + endif +else + ZLIB_LIBS := -lz + ZLIB_BOOTSTRAP_LIBS := -lz +endif + +LIBS = $(LIBBPF) -lelf $(CRYPTO_LIBS) $(ZLIB_LIBS) +LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf $(CRYPTO_LIBS) $(ZLIB_BOOTSTRAP_LIBS) ifeq ($(feature-libelf-zstd),1) LIBS += -lzstd @@ -200,7 +244,7 @@ else else ifeq ($(feature-libbfd-liberty),1) LIBS += -lbfd -ldl -lopcodes -liberty else ifeq ($(feature-libbfd-liberty-z),1) - LIBS += -lbfd -ldl -lopcodes -liberty -lz + LIBS += -lbfd -ldl -lopcodes -liberty $(ZLIB_LIBS) endif # If one of the above feature combinations is set, we support libbfd @@ -304,7 +348,7 @@ clean: $(LIBBPF)-clean $(LIBBPF_BOOTSTRAP)-clean feature-detect-clean $(call QUIET_CLEAN, bpftool) $(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d $(Q)$(RM) -- $(OUTPUT)*.skel.h $(OUTPUT)vmlinux.h - $(Q)$(RM) -r -- $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) + $(Q)$(RM) -r -- $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBZ_RS_OUTPUT) $(call QUIET_CLEAN, core-gen) $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpftool $(Q)$(RM) -r -- $(OUTPUT)feature/ -- 2.56.0.313.g2479322e68-goog