* [RFC PATCH v1 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test
2026-10-29 16:29 [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
@ 2026-10-29 16:29 ` Ian Rogers
2026-10-29 16:57 ` sashiko-bot
2026-10-29 16:29 ` [RFC PATCH v1 2/3] perf build: Prefer zlib-rs over zlib when available Ian Rogers
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Ian Rogers @ 2026-10-29 16:29 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Quentin Monnet, Miguel Ojeda,
Nathan Chancellor, Nicolas Schier, Nick Desaulniers,
Bill Wendling, Justin Stitt
Cc: linux-perf-users, bpf, rust-for-linux, linux-kbuild, llvm,
linux-kernel
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_<arch> 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 <irogers@google.com>
---
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 <crate>=<path>
# - 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_<target>)) and envs ($(RUST_ENVS_<target>))
+# - per object Rust flags ($(RUST_FLAGS_<obj>)) and envs ($(RUST_ENVS_<obj>))
+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 "<crate>-" so prefixes like "libc-" do not match
+# unrelated crates such as "libc-print-*", and use version sorting (sort -V)
+# on the "<crate>-<version>" 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 "<crate>-<version>" 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 <crate>=<path.rlib> 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,<name>) 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 <zlib.h>
+
+/*
+ * 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-<feat> and FEATURE_LIBS-<feat>.
+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
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [RFC PATCH v1 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test
2026-10-29 16:29 ` [RFC PATCH v1 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test Ian Rogers
@ 2026-10-29 16:57 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-29 16:57 UTC (permalink / raw)
To: Ian Rogers, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Quentin Monnet, Miguel Ojeda, Nathan Chancellor,
Nicolas Schier, Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: linux-perf-users, bpf, linux-kbuild, gary
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] tools build: sub-make PKG_CONFIG override blocks --static append
- [Medium] tools build: lib%.rlib pattern rule fails for subdirectory targets
- [Medium] tools build: missing rustc --target in Makefile.rust and early feature check
--
commit 15e2b90d3792008ff59190071c3b1973f7ab8c0b
Author: Ian Rogers <irogers@google.com>
tools build: Add Rust library build infrastructure and zlib-rs feature test
This patch adds shared Rust library build and feature detection infrastructure
under tools/build/ and tools/scripts/, along with a feature test for zlib-rs.
It supports locating Cargo crate sources or pkg-config packages, compiling
.rlib and .a targets with rustc, and resolving C compiler and linker flags.
> diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
> index ad69efdd4e85c..50c3eb57d34b8 100644
> --- a/tools/build/Makefile.build
> +++ b/tools/build/Makefile.build
[ ... ]
> @@ -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)
[Severity: Medium]
Will this pattern rule match .rlib targets located in subdirectories?
Later in tools/build/Makefile.build, targets in obj-y are prefixed with both
$(OUTPUT) and $(dir)/:
objprefix := $(subst ./,,$(OUTPUT)$(dir)/)
obj-y := $(addprefix $(objprefix),$(obj-y))
Other pattern rules in tools/build/Makefile.build place % immediately after
$(OUTPUT), such as $(OUTPUT)%.o: %.c FORCE and $(OUTPUT)%.a: %.rs FORCE, which
allows the stem % to match <subdir>/<name>.
Because $(OUTPUT)lib%.rlib places the literal prefix lib immediately after
$(OUTPUT), a target in a subdirectory expands to
$(OUTPUT)<subdir>/lib<name>.rlib. When $(OUTPUT) is non-empty, the pattern
contains a slash, so GNU Make matches against the full path and fails to match
$(OUTPUT)lib%.rlib whenever <subdir> is present. When $(OUTPUT) is empty,
directory-stripped matching sets the stem % to <name> without <subdir>/, so
the prerequisite %.rs looks for <name>.rs in the current directory rather than
in <subdir>/.
> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> index 4d37d11f674c5..c372600ae9e44 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
[ ... ]
> diff --git a/tools/build/Makefile.rust b/tools/build/Makefile.rust
> new file mode 100644
> index 0000000000000..cd9e0915b9298
> --- /dev/null
> +++ b/tools/build/Makefile.rust
> @@ -0,0 +1,149 @@
[ ... ]
> +ifeq ($(findstring -static,${LDFLAGS}),-static)
> + ifeq ($(findstring --static,$(PKG_CONFIG)),)
> + PKG_CONFIG += --static
> + endif
> +endif
[Severity: Medium]
When LDFLAGS contains -static, does PKG_CONFIG += --static take effect if the
caller passes PKG_CONFIG on the sub-make command line?
Both feature_check_code in tools/build/Makefile.feature and
feature_rust_lib_code in tools/scripts/Makefile.include pass
$(if $(PKG_CONFIG),PKG_CONFIG="$(PKG_CONFIG)") as a command-line argument to
$(MAKE). When invoked from Makefiles that initialize PKG_CONFIG (such as
tools/perf/Makefile.perf or tools/tracing/rtla/Makefile.rtla), PKG_CONFIG has
command-line origin in the sub-make.
In GNU Make, ordinary non-override += appends to a command-line variable are
ignored, so PKG_CONFIG += --static in both tools/build/Makefile.rust and
tools/build/feature/Makefile:
ifeq ($(findstring -static,${LDFLAGS}),-static)
PKG_CONFIG += --static
endif
is skipped during static builds, omitting transitive static libraries from
pkg-config queries. Should these use override PKG_CONFIG += --static?
[ ... ]
> +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
[ ... ]
> diff --git a/tools/scripts/Makefile.arch b/tools/scripts/Makefile.arch
> index ed5f008d400ed..d5f25f3be555f 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
[Severity: Medium]
How does RUST_TARGET_FLAGS_$(ARCH) get passed to rustc when tools/build/feature
or tools/build/Makefile.rust builds libz_rs.a during cross-compilation?
tools/scripts/Makefile.arch defines RUST_TARGET_FLAGS_<arch> when CROSS_COMPILE
is set, but neither Makefile.arch, Makefile.include, Makefile.feature, nor
Makefile.rust adds --target=$(RUST_TARGET_FLAGS_$(ARCH)) to RUST_FLAGS or
rustc_common_flags.
When feature_check runs for zlib-rs without --target in RUST_FLAGS (for
example, in tools/build/Makefile.feature when FEATURE_TESTS=all is evaluated
before a caller sets RUST_FLAGS, or in standalone feature checks),
cmd_rustc_rlib and cmd_rustc_staticlib in tools/build/Makefile.rust compile
liblibc.rlib, libzlib_rs.rlib, and libz_rs.a for the host architecture. Linking
test-zlib-rs.bin with the cross-compiler $(CC) then fails, and because the
rules in tools/build/Makefile.rust do not rebuild when RUST_FLAGS changes, the
host-architecture archives remain cached in $(LIBZ_RS_OUTPUT) for subsequent
invocations in the same build directory.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261029162958.3224280-1-irogers@google.com?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v1 2/3] perf build: Prefer zlib-rs over zlib when available
2026-10-29 16:29 [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
2026-10-29 16:29 ` [RFC PATCH v1 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test Ian Rogers
@ 2026-10-29 16:29 ` Ian Rogers
2026-10-29 16:50 ` sashiko-bot
2026-10-29 16:29 ` [RFC PATCH v1 3/3] bpftool: " Ian Rogers
2026-10-29 17:32 ` [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Miguel Ojeda
3 siblings, 1 reply; 9+ messages in thread
From: Ian Rogers @ 2026-10-29 16:29 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Quentin Monnet, Miguel Ojeda,
Nathan Chancellor, Nicolas Schier, Nick Desaulniers,
Bill Wendling, Justin Stitt
Cc: linux-perf-users, bpf, rust-for-linux, linux-kbuild, llvm,
linux-kernel
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 <irogers@google.com>
---
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
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [RFC PATCH v1 2/3] perf build: Prefer zlib-rs over zlib when available
2026-10-29 16:29 ` [RFC PATCH v1 2/3] perf build: Prefer zlib-rs over zlib when available Ian Rogers
@ 2026-10-29 16:50 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-29 16:50 UTC (permalink / raw)
To: Ian Rogers, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Quentin Monnet, Miguel Ojeda, Nathan Chancellor,
Nicolas Schier, Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: linux-perf-users, bpf, linux-kbuild, gary
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf build: RUST_FLAGS set after Makefile.feature breaks cross feature-dump
--
commit 71bfdd124d6b614e2d4b506eb746a963a59097da
Author: Ian Rogers <irogers@google.com>
perf build: Prefer zlib-rs over zlib when available
This commit updates the perf build system to detect and prefer zlib-rs over C
zlib unless disabled via NO_ZLIB_RS=1, NO_ZLIB=1, or NO_RUST=1. It moves Rust
compiler detection ahead of zlib detection in Makefile.config, builds
libz_rs.a in $(OUTPUT)libz_rs/, and exposes the zlib-rs feature in perf check.
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index b4764f69f47f4..4313fca53aa7c 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)
[Severity: Medium]
When cross-compiling with the feature-dump target (or FEATURE_TESTS=all),
does setting RUST_FLAGS here happen too late for tools/build/Makefile.feature?
In tools/perf/Makefile.perf, building the feature-dump target sets
FEATURE_TESTS := all before including Makefile.config:
tools/perf/Makefile.perf:
ifeq ($(config),1)
ifdef MAKECMDGOALS
ifeq ($(filter feature-dump,$(MAKECMDGOALS)),feature-dump)
FEATURE_TESTS := all
endif
endif
include Makefile.config
endif
Earlier in tools/perf/Makefile.config, tools/build/Makefile.feature is
included before the NO_RUST block:
tools/perf/Makefile.config:
ifeq ($(FEATURES_DUMP),)
FEATURE_DISPLAY_DEFERRED := 1
include $(srctree)/tools/build/Makefile.feature
else
include $(FEATURES_DUMP)
endif
When FEATURE_TESTS is set to all, Makefile.feature expands FEATURE_TESTS to
include FEATURE_TESTS_EXTRA (which contains zlib-rs) and runs
$(call feature_check,zlib-rs) while RUST_FLAGS still lacks
--target=$(RUST_TARGET_FLAGS_$(ARCH)).
That initial feature check invokes tools/build/Makefile.rust with an empty
RUST_FLAGS, compiling $(OUTPUT)libz_rs/libz_rs.a for the host architecture.
Linking test-zlib-rs.bin with the cross-compiler $(CC) against the host
libz_rs.a then fails and records feature-zlib-rs=0 in $(OUTPUT)FEATURE-DUMP.
Furthermore, when execution reaches the second $(call feature_check,zlib-rs)
above after RUST_FLAGS is populated, $(OUTPUT)libz_rs/libz_rs.a already
exists on disk from the host build, so Make considers it up-to-date and links
against the stale host archive again.
Should the CROSS_COMPILE configuration of RUST_FLAGS be moved above the
inclusion of tools/build/Makefile.feature alongside the CC and CLANG_FLAGS
cross-compilation setup?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261029162958.3224280-1-irogers@google.com?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v1 3/3] bpftool: Prefer zlib-rs over zlib when available
2026-10-29 16:29 [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
2026-10-29 16:29 ` [RFC PATCH v1 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test Ian Rogers
2026-10-29 16:29 ` [RFC PATCH v1 2/3] perf build: Prefer zlib-rs over zlib when available Ian Rogers
@ 2026-10-29 16:29 ` Ian Rogers
2026-10-29 17:06 ` sashiko-bot
2026-10-29 17:32 ` [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Miguel Ojeda
3 siblings, 1 reply; 9+ messages in thread
From: Ian Rogers @ 2026-10-29 16:29 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Quentin Monnet, Miguel Ojeda,
Nathan Chancellor, Nicolas Schier, Nick Desaulniers,
Bill Wendling, Justin Stitt
Cc: linux-perf-users, bpf, rust-for-linux, linux-kbuild, llvm,
linux-kernel
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 <irogers@google.com>
---
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
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [RFC PATCH v1 3/3] bpftool: Prefer zlib-rs over zlib when available
2026-10-29 16:29 ` [RFC PATCH v1 3/3] bpftool: " Ian Rogers
@ 2026-10-29 17:06 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-29 17:06 UTC (permalink / raw)
To: Ian Rogers, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Quentin Monnet, Miguel Ojeda, Nathan Chancellor,
Nicolas Schier, Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: linux-perf-users, bpf, linux-kbuild, gary
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] bpftool: link failure with pre-built libbpf.a when zlib-rs is used
--
commit 7a2cb794e37f624ded57767492091a08919fa52c
Author: Ian Rogers <irogers@google.com>
bpftool: Prefer zlib-rs over zlib when available
This commit updates the bpftool Makefile to detect and prefer zlib-rs over
C zlib, configuring ZLIB_CFLAGS and ZLIB_LIBS via feature_rust_lib and
falling back to -lz when zlib-rs is unavailable or when cross-compiling
bootstrap bpftool.
> diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
> index b0f7168e79432..a193cf89a0346 100644
> --- a/tools/bpf/bpftool/Makefile
> +++ b/tools/bpf/bpftool/Makefile
[ ... ]
> @@ -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
[ ... ]
> @@ -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)
[Severity: Medium]
Can this cause a link failure with an undefined reference to gzopen64 when
bpftool is built using a pre-built libbpf.a on a host where zlib-rs is
detected?
In tools/lib/bpf/Makefile, libbpf is compiled with:
override CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
When tools/lib/bpf/libbpf.c is compiled without ZLIB_CFLAGS, bpf_object__read_kconfig_file()
includes the system zlib.h with those macros defined, which remaps gzopen()
to gzopen64() and leaves an undefined reference to gzopen64 in libbpf.a.
In contrast, libz-rs-sys only exports gzopen and not gzopen64, which is why
the $(LIBBPF) and $(LIBBPF_BOOTSTRAP) rules here pass $(ZLIB_CFLAGS) so that
libbpf uses the bundled zlib.h from libz-rs-sys.
However, several Makefiles build libbpf.a directly via tools/lib/bpf/Makefile
without ZLIB_CFLAGS and then pass that pre-built archive directory to
bpftool via LIBBPF_OUTPUT or LIBBPF_BOOTSTRAP_OUTPUT, such as
tools/testing/selftests/bpf/Makefile:
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
ARCH= CROSS_COMPILE= CC="$(HOSTCC)" LD="$(HOSTLD)" \
EXTRA_CFLAGS='-g $(OPT_FLAGS) $(SAN_CFLAGS) $(EXTRA_CFLAGS)' \
EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(HOST_BUILD_DIR)/bpftool/ \
LIBBPF_OUTPUT=$(HOST_BUILD_DIR)/libbpf/
Similar patterns exist in tools/sched_ext/Makefile,
tools/testing/selftests/sched_ext/Makefile,
tools/testing/selftests/hid/Makefile, and drivers/hid/bpf/progs/Makefile.
Because $(LIBBPF) or $(LIBBPF_BOOTSTRAP) already exists and is up to date when
bpftool's Makefile runs, the $(LIBBPF) recipe with $(ZLIB_CFLAGS) is skipped,
while LIBS and LIBS_BOOTSTRAP replace -lz with $(ZLIB_LIBS) (libz_rs.a).
Wouldn't linking bpftool then fail with an unresolved gzopen64 symbol from the
pre-built libbpf.a?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261029162958.3224280-1-irogers@google.com?part=3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs
2026-10-29 16:29 [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
` (2 preceding siblings ...)
2026-10-29 16:29 ` [RFC PATCH v1 3/3] bpftool: " Ian Rogers
@ 2026-10-29 17:32 ` Miguel Ojeda
2026-10-29 18:23 ` Ian Rogers
3 siblings, 1 reply; 9+ messages in thread
From: Miguel Ojeda @ 2026-10-29 17:32 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Quentin Monnet, Miguel Ojeda, Nathan Chancellor,
Nicolas Schier, Nick Desaulniers, Bill Wendling, Justin Stitt,
linux-perf-users, bpf, rust-for-linux, linux-kbuild, llvm,
linux-kernel
On Thu, Oct 29, 2026 at 5:30 PM Ian Rogers <irogers@google.com> wrote:
>
> 1. **tools build: Add Rust library build infrastructure and zlib-rs feature test**:
> - Adds `tools/build/Makefile.rust` with helpers to locate Cargo crate
> sources in distro (`/usr/share/cargo/registry`) or local Cargo
> registries (`CARGO_HOME` / `~/.cargo`), map `.rlib` prerequisites to
When we were discussing whether to vendor crates for the normal build
or whether to fetch them locally from the registry a couple years ago,
we discussed approaches like this one, i.e. picking a version from the
registry by folder name etc.
But that doesn't work too well. For instance, the graph of
dependencies may change, there may be several versions available (and
the highest may not be the proper one to pick), there may be different
major versions available (i.e. not backwards compatible), they may
change the build scripts, etc. Even picking the highest major wouldn't
always be correct, from what I recall.
I also asked a few distributions how they felt about it, and they
indeed said that it wasn't a great idea without querying properly the
registry.
So one should really ask Cargo for the right information about the
local registry (i.e. offline). It has been a while, so Cargo (or maybe
`pkg-config` or whatever) may have better support for querying it
nowadays too -- I would suggest checking that first (e.g. `cargo
metadata`).
I think depending on Cargo for this, especially nowadays and for
`tools/`, should be fine (we were considering even back then and for
the normal build).
By the way, checking Cargo's cache sounds very strange to me: that
means the version that gets picked is even more "uncontrolled".
I hope that helps!
[ In the end, for normal kernel crates, we decided to vendor for other
reasons, e.g. we wanted to pin the versions, to customize sometimes,
and most importantly to avoid any possible user misconfiguration that
could lead to a subtly incorrect kernel. But for `tools/` it makes way
more sense, of course. ]
Cheers,
Miguel
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs
2026-10-29 17:32 ` [RFC PATCH v1 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Miguel Ojeda
@ 2026-10-29 18:23 ` Ian Rogers
0 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-10-29 18:23 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Quentin Monnet, Miguel Ojeda, Nathan Chancellor,
Nicolas Schier, Nick Desaulniers, Bill Wendling, Justin Stitt,
linux-perf-users, bpf, rust-for-linux, linux-kbuild, llvm,
linux-kernel
On Thu, Oct 29, 2026 at 10:32 AM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, Oct 29, 2026 at 5:30 PM Ian Rogers <irogers@google.com> wrote:
> >
> > 1. **tools build: Add Rust library build infrastructure and zlib-rs feature test**:
> > - Adds `tools/build/Makefile.rust` with helpers to locate Cargo crate
> > sources in distro (`/usr/share/cargo/registry`) or local Cargo
> > registries (`CARGO_HOME` / `~/.cargo`), map `.rlib` prerequisites to
>
> When we were discussing whether to vendor crates for the normal build
> or whether to fetch them locally from the registry a couple years ago,
> we discussed approaches like this one, i.e. picking a version from the
> registry by folder name etc.
>
> But that doesn't work too well. For instance, the graph of
> dependencies may change, there may be several versions available (and
> the highest may not be the proper one to pick), there may be different
> major versions available (i.e. not backwards compatible), they may
> change the build scripts, etc. Even picking the highest major wouldn't
> always be correct, from what I recall.
>
> I also asked a few distributions how they felt about it, and they
> indeed said that it wasn't a great idea without querying properly the
> registry.
>
> So one should really ask Cargo for the right information about the
> local registry (i.e. offline). It has been a while, so Cargo (or maybe
> `pkg-config` or whatever) may have better support for querying it
> nowadays too -- I would suggest checking that first (e.g. `cargo
> metadata`).
>
> I think depending on Cargo for this, especially nowadays and for
> `tools/`, should be fine (we were considering even back then and for
> the normal build).
>
> By the way, checking Cargo's cache sounds very strange to me: that
> means the version that gets picked is even more "uncontrolled".
>
> I hope that helps!
>
> [ In the end, for normal kernel crates, we decided to vendor for other
> reasons, e.g. we wanted to pin the versions, to customize sometimes,
> and most importantly to avoid any possible user misconfiguration that
> could lead to a subtly incorrect kernel. But for `tools/` it makes way
> more sense, of course. ]
Hi Miguel,
This is great feedback, and it's why I thought this was an RFC series,
rather than a full blown series intended for immediate merging. I
think the other obvious point of contention is preferring zlib-rs over
zlib. I'll incorporate your feedback into v2 along with addressing the
large amount of feedback Sashiko has given, which may become
irrelevant if we trust in Cargo more.
Thanks,
Ian
> Cheers,
> Miguel
^ permalink raw reply [flat|nested] 9+ messages in thread