* [RFC PATCH v3 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test
2026-11-05 18:09 [RFC PATCH v3 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
@ 2026-11-05 18:09 ` Ian Rogers
2026-11-05 18:53 ` bot+bpf-ci
2026-11-05 18:09 ` [RFC PATCH v3 2/3] perf build: Prefer zlib-rs over zlib when available Ian Rogers
2026-11-05 18:09 ` [RFC PATCH v3 3/3] bpftool: " Ian Rogers
2 siblings, 1 reply; 7+ messages in thread
From: Ian Rogers @ 2026-11-05 18:09 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter,
Quentin Monnet, Miguel Ojeda, Nathan Chancellor, Nicolas Schier
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Nick Desaulniers, Bill Wendling, Justin Stitt, 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 rules to resolve Rust library C
compiler and 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 into
$(OUTPUT)libz_rs/ from the system Cargo registry
(/usr/share/cargo/registry) using offline Cargo (cargo metadata and
cargo build --offline).
- Pass -Wl,--exclude-libs,libz_rs.a when linking libz_rs.a so symbols
pulled into the executable are marked HIDDEN and not exported into
.dynsym, preventing shared libraries linked against system libz.so.1
(such as libelf.so, libdw.so, and libcurl.so) from partially binding
some zlib calls to the executable's libz_rs.a and others to libz.so.1.
- Add tools/build/feature/test-zlib-rs.c verifying ZLIB_VER_SUBREVISION
== 15 (0xf) and linking against inflateInit().
- Add RUST_TARGET_FLAGS_<arch> cross-compilation triples and the
feature_rust_lib helper macro to tools/scripts/Makefile.include.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/build/Makefile.feature | 12 ++-
tools/build/Makefile.rust | 166 +++++++++++++++++++++++++++++
tools/build/feature/.gitignore | 1 +
tools/build/feature/Makefile | 11 +-
tools/build/feature/test-zlib-rs.c | 19 ++++
tools/scripts/Makefile.include | 25 +++++
6 files changed, 231 insertions(+), 3 deletions(-)
create mode 100644 tools/build/Makefile.rust
create mode 100644 tools/build/feature/test-zlib-rs.c
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 4d37d11f674c..ecf27626d493 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)" CARGO="$(CARGO)" 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,12 @@ 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
+ ifneq ($(filter rust,$(FEATURE_TESTS)),)
+ $(call feature_check,rust)
+ 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..952aac9fc4bf
--- /dev/null
+++ b/tools/build/Makefile.rust
@@ -0,0 +1,166 @@
+# 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 distro Cargo
+# registry sources via offline Cargo) for tools/ builds and feature detection.
+
+ifeq ($(pound),)
+include $(dir $(lastword $(MAKEFILE_LIST)))../scripts/Makefile.include
+endif
+
+ifneq ($(CROSS_COMPILE),)
+ ifeq ($(filter --target=%,$(RUST_FLAGS)),)
+ ifneq ($(RUST_TARGET_FLAGS_$(ARCH)),)
+ override RUST_FLAGS += --target=$(RUST_TARGET_FLAGS_$(ARCH))
+ endif
+ endif
+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)),)
+ override PKG_CONFIG += --static
+ endif
+endif
+
+# 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 ?= $(OUTPUT)
+LIBZ_RS_OUTPUT ?= $(RUST_OUTPUT)libz_rs/
+
+$(LIBZ_RS_OUTPUT):
+ $(Q)mkdir -p $@
+
+# Use the system Cargo registry (e.g. /usr/share/cargo/registry from
+# Debian/Ubuntu librust-*-dev or Fedora rust-*-devel packages) offline via
+# Cargo so Cargo resolves compatible crate versions, dependency graphs,
+# features, and build scripts without touching ~/.cargo or the network.
+#
+# Upstream /usr/bin/cargo only searches crates.io by default; distros do not
+# point /usr/bin/cargo at /usr/share/cargo/registry globally because Cargo's
+# directory source mechanism replaces crates.io entirely, which would break
+# normal user builds. Instead, distro package builders (such as Debian's
+# /usr/share/cargo/bin/cargo wrapper and Fedora's %cargo_prep macro) configure
+# source.crates-io.replace-with to point at /usr/share/cargo/registry. We pass
+# the same source replacement via --config and set CARGO_HOME to a temporary
+# directory so ~/.cargo is neither read nor modified.
+CARGO_REGISTRY_DIR ?= /usr/share/cargo/registry
+CARGO_OFFLINE_FLAGS = --offline \
+ --config 'source.crates-io.replace-with="system-registry"' \
+ --config 'source.system-registry.directory="$(CARGO_REGISTRY_DIR)"'
+
+# cargo build takes --target=<triple> as a CLI flag (which also places the
+# output in target/<triple>/release/) and compiler flags via RUSTFLAGS.
+# Build with -C relocation-model=pic so libz_rs.a can be linked into PIE
+# binaries.
+CARGO_TARGET := $(patsubst --target=%,%,$(firstword $(filter --target=%,$(RUST_FLAGS))))
+CARGO_RUSTFLAGS := $(filter-out --target=%,$(RUST_FLAGS)) -C relocation-model=pic
+
+# Build libz_rs.a and stage its headers into $(LIBZ_RS_OUTPUT)include/:
+# - Cargo writes Cargo.lock next to Cargo.toml, so the synthetic manifest and
+# lib.rs are generated inside the writable $(LIBZ_RS_OUTPUT) directory rather
+# than in $(srctree), and removed once the build finishes (any stale
+# Cargo.lock from an interrupted build is also removed upfront so a distro
+# package upgrade in $(CARGO_REGISTRY_DIR) is not blocked by an old lockfile).
+# - Enable export-symbols (unprefixed zlib C ABI symbols), c-allocator, std,
+# and gz (gzopen/gzopen64/gzread/etc.) on libz-rs-sys.
+# - Query cargo metadata for the resolved libz-rs-sys crate path so we copy
+# the matching zlib.h and zconf.h headers that Cargo selected.
+$(LIBZ_RS_OUTPUT)libz_rs.a: $(wildcard $(CARGO_REGISTRY_DIR)) | $(LIBZ_RS_OUTPUT)
+ $(Q){ \
+ rm -f $(LIBZ_RS_OUTPUT)Cargo.lock && \
+ printf '[package]\nname = "z_rs"\nversion = "0.1.0"\nedition = "2021"\n\n[lib]\nname = "z_rs"\npath = "lib.rs"\ncrate-type = ["staticlib"]\n\n[dependencies]\nlibz-rs-sys = { version = "*", default-features = false, features = ["export-symbols", "c-allocator", "std", "gz"] }\n' > $(LIBZ_RS_OUTPUT)Cargo.toml && \
+ printf 'pub use libz_rs_sys::*;\n' > $(LIBZ_RS_OUTPUT)lib.rs && \
+ inc_dir=$$(CARGO_HOME="$(LIBZ_RS_OUTPUT)cargo_home" $(CARGO) metadata $(CARGO_OFFLINE_FLAGS) --format-version 1 --manifest-path $(LIBZ_RS_OUTPUT)Cargo.toml | sed -n 's/.*"name":"libz_rs_sys","src_path":"\([^"]*\)\/src\/lib\.rs".*/\1/p') && \
+ test -n "$$inc_dir" && test -d "$$inc_dir/include" && \
+ mkdir -p $(LIBZ_RS_OUTPUT)include && \
+ cp -f "$$inc_dir"/include/*.h $(LIBZ_RS_OUTPUT)include/ && \
+ CARGO_HOME="$(LIBZ_RS_OUTPUT)cargo_home" RUSTC="$(RUSTC)" RUSTFLAGS="$(CARGO_RUSTFLAGS)" \
+ $(CARGO) build $(CARGO_OFFLINE_FLAGS) --release \
+ --manifest-path $(LIBZ_RS_OUTPUT)Cargo.toml \
+ --target-dir $(LIBZ_RS_OUTPUT)target \
+ $(if $(CARGO_TARGET),--target=$(CARGO_TARGET)) && \
+ mv -f $(LIBZ_RS_OUTPUT)target/$(if $(CARGO_TARGET),$(CARGO_TARGET)/)release/libz_rs.a $@ && \
+ rm -rf $(LIBZ_RS_OUTPUT)Cargo.toml $(LIBZ_RS_OUTPUT)Cargo.lock \
+ $(LIBZ_RS_OUTPUT)lib.rs $(LIBZ_RS_OUTPUT)target \
+ $(LIBZ_RS_OUTPUT)cargo_home; \
+ } > $(@:.a=.make.output) 2>&1 || { \
+ rm -rf $(LIBZ_RS_OUTPUT)Cargo.toml $(LIBZ_RS_OUTPUT)Cargo.lock \
+ $(LIBZ_RS_OUTPUT)lib.rs $(LIBZ_RS_OUTPUT)include \
+ $(LIBZ_RS_OUTPUT)target $(LIBZ_RS_OUTPUT)cargo_home $@; \
+ false; \
+ }
+
+# Only evaluate zlib-rs pkg-config / Cargo flags when building a zlib-rs target
+# (or 'all'), avoiding unnecessary shell calls during 'clean' or unrelated
+# feature tests in tools/build/feature/Makefile.
+# Note: GNU Make's $(filter ...) only supports a single '%' wildcard per
+# pattern, so $(findstring zlib-rs,...) is used to match targets like
+# $(OUTPUT)test-zlib-rs.bin, zlib-rs-cflags, and zlib-rs-libs.
+ifneq ($(if $(MAKECMDGOALS),$(or $(findstring zlib-rs,$(MAKECMDGOALS)),$(filter all %libz_rs.a,$(MAKECMDGOALS))),all),)
+ # 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 when not linking -static since it only
+ # provides a shared library, zlib-rs, or z_rs)
+ # 3. System Cargo registry built via Cargo into $(LIBZ_RS_OUTPUT)libz_rs.a
+ # (linked with -lpthread -ldl -lm required by the embedded Rust libstd)
+ 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 ($(if $(findstring -static,${LDFLAGS}),false,$(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 ($(wildcard $(CARGO_REGISTRY_DIR)),)
+ FEATURE_CFLAGS-zlib-rs := -I$(LIBZ_RS_OUTPUT)include
+ FEATURE_STATIC-zlib-rs := $(LIBZ_RS_OUTPUT)libz_rs.a
+ # Pass -Wl,--exclude-libs,libz_rs.a so symbols pulled into the executable
+ # from libz_rs.a are marked HIDDEN and not exported into .dynsym. That
+ # prevents shared libraries linked against system libz.so.1 (e.g.
+ # libelf.so, libdw.so, libcurl.so) from partially binding some zlib
+ # calls to the executable's libz_rs.a and others to libz.so.1.
+ FEATURE_LIBS-zlib-rs := $(FEATURE_STATIC-zlib-rs) \
+ -Wl,--exclude-libs,libz_rs.a -lpthread -ldl -lm
+ endif
+ endif
+endif
+
+zlib-rs-cflags: $(FEATURE_STATIC-zlib-rs)
+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..0c728531fcdc 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 \
@@ -100,7 +101,7 @@ else
endif
ifeq ($(findstring -static,${LDFLAGS}),-static)
- PKG_CONFIG += --static
+ override PKG_CONFIG += --static
endif
all: $(FILES)
@@ -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)
+
$(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.include b/tools/scripts/Makefile.include
index 378387f62960..7089e9ce64c7 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -109,8 +109,33 @@ CC_NO_CLANG := $(shell if command -v $(firstword $(CC)) >/dev/null 2>&1; then $(
# Some tools require bpftool
SYSTEM_BPFTOOL ?= bpftool
+CARGO ?= cargo
RUSTC ?= rustc
+# 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
+
+# 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
+ RUST_OUTPUT ?= $$(abspath $$(or $$(OUTPUT),$$(CURDIR)))/
+ FEATURE_CFLAGS-$(1) := $$(shell $$(MAKE) -s --no-print-directory -f $$(srctree)/tools/build/Makefile.rust RUST_OUTPUT="$$(RUST_OUTPUT)" $$(if $$(PKG_CONFIG),PKG_CONFIG="$$(PKG_CONFIG)") CARGO="$$(CARGO)" RUSTC="$$(RUSTC)" RUST_FLAGS="$$(RUST_FLAGS)" LDFLAGS="$$(LDFLAGS)" $(1)-cflags)
+ FEATURE_LIBS-$(1) := $$(shell $$(MAKE) -s --no-print-directory -f $$(srctree)/tools/build/Makefile.rust RUST_OUTPUT="$$(RUST_OUTPUT)" $$(if $$(PKG_CONFIG),PKG_CONFIG="$$(PKG_CONFIG)") CARGO="$$(CARGO)" 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.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [RFC PATCH v3 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test
2026-11-05 18:09 ` [RFC PATCH v3 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test Ian Rogers
@ 2026-11-05 18:53 ` bot+bpf-ci
0 siblings, 0 replies; 7+ messages in thread
From: bot+bpf-ci @ 2026-11-05 18:53 UTC (permalink / raw)
To: irogers, peterz, mingo, acme, namhyung, jolsa, irogers,
adrian.hunter, qmo, ojeda, nathan, nsc
Cc: boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross,
dakr, ndesaulniers, morbo, justinstitt, linux-perf-users, bpf,
rust-for-linux, linux-kbuild, llvm, linux-kernel, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3342 bytes --]
> tools build: Add Rust library build infrastructure and zlib-rs feature test
TL;DR: Prepending CLANG_CROSS_FLAGS to CXXFLAGS in the feature tests may break
C++ checks (cxa-demangle, llvm) when cross-building with CC=clang but a g++
CXX, silently dropping perf features.
> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> index 4d37d11f674c..ecf27626d493 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)" CARGO="$(CARGO)" 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
Is it correct to prepend $(CLANG_CROSS_FLAGS) to CXXFLAGS here?
CLANG_CROSS_FLAGS is computed in tools/scripts/Makefile.include from a
probe of CC alone (CC_NO_CLANG == 0 && CROSS_COMPILE set), and holds
clang-only options such as --target=<triple>, --prefix=, --sysroot= and
--gcc-toolchain=. Nothing checks that CXX is clang.
With 'make CC=clang CROSS_COMPILE=aarch64-linux-gnu-' (no LLVM=1),
Makefile.include leaves CXX as $(CROSS_COMPILE)g++, so each C++ feature
test would run as something like:
aarch64-linux-gnu-g++ --target=aarch64-linux-gnu ... --gcc-toolchain=/usr
-MD -Wall -Werror -o test-cxa-demangle.bin test-cxa-demangle.cpp
and g++ rejects the unrecognized --target option. The probe is silent
(output goes to /dev/null), so feature_check for cxa-demangle, llvm and
llvm-perf would return 0 and perf would drop HAVE_CXA_DEMANGLE_SUPPORT
and libllvm support without any error.
Before this patch CXXFLAGS in the feature sub-make did not contain
CLANG_CROSS_FLAGS, and Makefile.include only appends it to CFLAGS and
AFLAGS, so those tests passed. The same kind of failure was already fixed
for native perf builds in c8592f8da838 ("perf build: Only pass clang flags
to CXX when CXX is clang"), where tools/perf/Makefile.config probes
CXX_NO_CLANG separately.
Could CLANG_CROSS_FLAGS be added to CXXFLAGS only when CXX is clang, or
left on CFLAGS only? The commit message also does not mention that
CLANG_CROSS_FLAGS is now passed to every tool's feature tests.
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/42083491750
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH v3 2/3] perf build: Prefer zlib-rs over zlib when available
2026-11-05 18:09 [RFC PATCH v3 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
2026-11-05 18:09 ` [RFC PATCH v3 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test Ian Rogers
@ 2026-11-05 18:09 ` Ian Rogers
2026-11-05 18:53 ` bot+bpf-ci
2026-11-05 18:09 ` [RFC PATCH v3 3/3] bpftool: " Ian Rogers
2 siblings, 1 reply; 7+ messages in thread
From: Ian Rogers @ 2026-11-05 18:09 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter,
Quentin Monnet, Miguel Ojeda, Nathan Chancellor, Nicolas Schier
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Nick Desaulniers, Bill Wendling, Justin Stitt, 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.
- Replace -lz with $(ZLIB_LIBS) in DWARFLIBS and llvm-config
--system-libs so static libdw/libelf and libLLVM configurations use
the selected zlib implementation.
- 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 | 92 ++++++++++++++----------
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, 107 insertions(+), 43 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..81b56cbc8658 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -69,6 +69,12 @@ endif
include $(srctree)/tools/scripts/Makefile.arch
+ifneq ($(CROSS_COMPILE),)
+ ifneq ($(RUST_TARGET_FLAGS_$(ARCH)),)
+ RUST_FLAGS += --target=$(RUST_TARGET_FLAGS_$(ARCH))
+ endif
+endif
+
$(call detected_var,SRCARCH)
CFLAGS += -I$(OUTPUT)arch/$(SRCARCH)/include/generated
@@ -532,13 +538,54 @@ ifdef CORESIGHT
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),)
+ ifeq ($(RUST_TARGET_FLAGS_$(ARCH)),)
+ $(error Unknown rust cross compilation architecture $(ARCH))
+ endif
+ 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
- ifeq ($(feature-zlib), 1)
+ ifndef NO_ZLIB_RS
+ $(call feature_check,zlib-rs)
+ ifeq ($(feature-zlib-rs), 1)
+ $(call feature_rust_lib,zlib-rs)
+ ZLIB_CFLAGS := $(FEATURE_CFLAGS-zlib-rs)
+ ZLIB_LIBS := $(FEATURE_LIBS-zlib-rs)
+ CFLAGS += -DHAVE_ZLIB_RS_SUPPORT $(ZLIB_CFLAGS)
+ $(call detected,CONFIG_ZLIB_RS)
+ endif
+ endif
+ ifeq ($(ZLIB_LIBS),)
+ ifeq ($(feature-zlib), 1)
+ ZLIB_LIBS := -lz
+ else
+ NO_ZLIB := 1
+ endif
+ endif
+ ifneq ($(ZLIB_LIBS),)
CFLAGS += -DHAVE_ZLIB_SUPPORT
- EXTLIBS += -lz
+ EXTLIBS += $(ZLIB_LIBS)
$(call detected,CONFIG_ZLIB)
- else
- NO_ZLIB := 1
endif
endif
@@ -580,7 +627,7 @@ ifndef NO_LIBELF
ifndef NO_LIBDW
CFLAGS += -DHAVE_LIBDW_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
- EXTLIBS += ${DWARFLIBS}
+ EXTLIBS += $(patsubst -lz,$(or $(ZLIB_LIBS),-lz),${DWARFLIBS})
$(call detected,CONFIG_LIBDW)
endif # NO_LIBDW
@@ -908,7 +955,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 $(or $(ZLIB_LIBS),-lz)
endif
CFLAGS += -DHAVE_LIBBFD_SUPPORT
@@ -930,7 +977,7 @@ ifndef NO_LIBLLVM
CFLAGS += -DHAVE_LIBLLVM_SUPPORT
LLVM_CFLAGS := $(shell $(LLVM_CONFIG) --cflags 2>/dev/null)
LLVM_CXXFLAGS := $(shell $(LLVM_CONFIG) --cxxflags 2>/dev/null)
- LLVM_LIBLLVM := $(shell $(LLVM_CONFIG) --libs all 2>/dev/null) $(shell $(LLVM_CONFIG) --system-libs 2>/dev/null)
+ LLVM_LIBLLVM := $(shell $(LLVM_CONFIG) --libs all 2>/dev/null) $(patsubst -lz,$(or $(ZLIB_LIBS),-lz),$(shell $(LLVM_CONFIG) --system-libs 2>/dev/null))
LLVM_LIBDIR := $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
CFLAGS += $(LLVM_CFLAGS)
CXXFLAGS += -DHAVE_LIBLLVM_SUPPORT $(LLVM_CXXFLAGS)
@@ -1132,37 +1179,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..0c24b13e9e0c 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,13 @@ 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
+LIBZ_RS = $(filter %/libz_rs.a,$(ZLIB_LIBS))
+
ifneq ($(OUTPUT),)
LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
else
@@ -741,6 +750,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) $@
@@ -805,15 +819,25 @@ $(LIBAPI)-clean:
$(call QUIET_CLEAN, libapi)
$(Q)$(RM) -r -- $(LIBAPI_OUTPUT)
-$(LIBBPF): FORCE | $(LIBBPF_OUTPUT)
+$(LIBBPF): FORCE $(LIBZ_RS) | $(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)/ \
+ CARGO="$(CARGO)" 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 +1050,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 +1074,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..7c405f1a4c83 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 "cargo rust-libz-rs-sys-devel"
+ ;;
lzma)
echo "xz-devel"
;;
@@ -305,6 +308,9 @@ debian_pkg_for() {
zlib)
echo "zlib1g-dev"
;;
+ zlib-rs)
+ echo "cargo 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.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [RFC PATCH v3 2/3] perf build: Prefer zlib-rs over zlib when available
2026-11-05 18:09 ` [RFC PATCH v3 2/3] perf build: Prefer zlib-rs over zlib when available Ian Rogers
@ 2026-11-05 18:53 ` bot+bpf-ci
0 siblings, 0 replies; 7+ messages in thread
From: bot+bpf-ci @ 2026-11-05 18:53 UTC (permalink / raw)
To: irogers, peterz, mingo, acme, namhyung, jolsa, irogers,
adrian.hunter, qmo, ojeda, nathan, nsc
Cc: boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross,
dakr, ndesaulniers, morbo, justinstitt, linux-perf-users, bpf,
rust-for-linux, linux-kbuild, llvm, linux-kernel, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2006 bytes --]
> perf build: Prefer zlib-rs over zlib when available
TL;DR: install-build-deps.sh may fail entirely on Debian 13 (and possibly
Fedora) because the new zlib-rs package mapping names packages that may not
exist, with no availability check, so apt-get could install nothing.
> diff --git a/tools/perf/scripts/install-build-deps.sh b/tools/perf/scripts/install-build-deps.sh
> --- a/tools/perf/scripts/install-build-deps.sh
> +++ b/tools/perf/scripts/install-build-deps.sh
[ ... ]
> @@ -305,6 +308,9 @@ debian_pkg_for() {
> zlib)
> echo "zlib1g-dev"
> ;;
> + zlib-rs)
> + echo "cargo librust-libz-rs-sys-dev"
> + ;;
> lzma)
> echo "liblzma-dev"
> ;;
Will this break install-build-deps.sh on Debian 13 (trixie), which the
script header lists as validated?
trixie does not appear to ship librust-libz-rs-sys-dev, and unlike the RHEL
branch, the Debian/Ubuntu path in package_set() has no availability check
(pkg_available() is only used for RHEL). The name goes straight into the
install command:
echo "DEBIAN_FRONTEND=noninteractive apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y $*"
apt-get then fails with "E: Unable to locate package
librust-libz-rs-sys-dev" (exit 100) and installs nothing, including the
packages that are available. main() prints "error: the install command
failed" and exits 1.
Before this patch zlib-rs had no case, so it was skipped via
[ -n "$pkg" ] || continue and the install worked.
The fedora_pkg_for() name rust-libz-rs-sys-devel is also added without a
check, so Fedora would fail the same way if it lacks that package.
Should debian_pkg_for() probe availability the way pkg_available() does for
dnf, or leave zlib-rs unmapped on distros that do not package the crate?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/42083491750
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH v3 3/3] bpftool: Prefer zlib-rs over zlib when available
2026-11-05 18:09 [RFC PATCH v3 0/3] tools: Add Rust library build infrastructure and prefer zlib-rs Ian Rogers
2026-11-05 18:09 ` [RFC PATCH v3 1/3] tools build: Add Rust library build infrastructure and zlib-rs feature test Ian Rogers
2026-11-05 18:09 ` [RFC PATCH v3 2/3] perf build: Prefer zlib-rs over zlib when available Ian Rogers
@ 2026-11-05 18:09 ` Ian Rogers
2026-11-05 18:53 ` bot+bpf-ci
2 siblings, 1 reply; 7+ messages in thread
From: Ian Rogers @ 2026-11-05 18:09 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter,
Quentin Monnet, Miguel Ojeda, Nathan Chancellor, Nicolas Schier
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Nick Desaulniers, Bill Wendling, Justin Stitt, 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 (unless disabled with
NO_ZLIB_RS=1), falling back to -lz. Also replace -lz with $(ZLIB_LIBS)
in static llvm-config --system-libs.
Decompression of kernel configuration (/proc/config.gz) and compressed
ELF/BTF sections (via libbpf, and via libelf/libbfd/libLLVM in static
builds) processes data that benefits from a memory-safe implementation.
Preferring zlib-rs over C zlib provides memory safety and improved
decompression performance while keeping bpftool aligned with tools/perf
(including sharing libz_rs.a when building bootstrap bpftool for perf
BPF skeletons).
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/bpf/bpftool/.gitignore | 1 +
tools/bpf/bpftool/Makefile | 59 +++++++++++++++++++++++++++++++-----
2 files changed, 53 insertions(+), 7 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..0b5f3967465f 100644
--- a/tools/bpf/bpftool/Makefile
+++ b/tools/bpf/bpftool/Makefile
@@ -16,6 +16,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 +40,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 +119,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 +144,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 +155,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 +177,29 @@ 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 (libz_rs.a exports the full zlib C
+# ABI including both gzopen and gzopen64, so it is also compatible with a
+# pre-built libbpf.a compiled against system <zlib.h> with _FILE_OFFSET_BITS=64).
+# When cross-compiling, the host bootstrap bpftool still links against the
+# host's -lz.
+ZLIB_LIBS := -lz
+ZLIB_BOOTSTRAP_LIBS := -lz
+ifeq ($(feature-zlib-rs),1)
+ ifeq ($(NO_ZLIB_RS),)
+ $(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)
+ endif
+ endif
+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
@@ -188,7 +233,7 @@ ifeq ($(HAS_LLVM),1)
CFLAGS += $(filter-out -D_GNU_SOURCE,$(shell $(LLVM_CONFIG) --cflags))
LIBS += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS))
ifeq ($(shell $(LLVM_CONFIG) --shared-mode),static)
- LIBS += $(shell $(LLVM_CONFIG) --system-libs $(LLVM_CONFIG_LIB_COMPONENTS))
+ LIBS += $(patsubst -lz,$(ZLIB_LIBS),$(shell $(LLVM_CONFIG) --system-libs $(LLVM_CONFIG_LIB_COMPONENTS)))
LIBS += -lstdc++
endif
LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags)
@@ -200,7 +245,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 +349,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.455.g6c5a503b38-goog
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [RFC PATCH v3 3/3] bpftool: Prefer zlib-rs over zlib when available
2026-11-05 18:09 ` [RFC PATCH v3 3/3] bpftool: " Ian Rogers
@ 2026-11-05 18:53 ` bot+bpf-ci
0 siblings, 0 replies; 7+ messages in thread
From: bot+bpf-ci @ 2026-11-05 18:53 UTC (permalink / raw)
To: irogers, peterz, mingo, acme, namhyung, jolsa, irogers,
adrian.hunter, qmo, ojeda, nathan, nsc
Cc: boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross,
dakr, ndesaulniers, morbo, justinstitt, linux-perf-users, bpf,
rust-for-linux, linux-kbuild, llvm, linux-kernel, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2116 bytes --]
> bpftool: Prefer zlib-rs over zlib when available
TL;DR: Possible behaviour issue: bpftool ignores perf's NO_RUST/NO_ZLIB_RS, so
"make -C tools/perf NO_RUST=1" may still build and link the bootstrap bpftool
against zlib-rs via cargo.
> diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
> --- a/tools/bpf/bpftool/Makefile
> +++ b/tools/bpf/bpftool/Makefile
[ ... ]
> @@ -115,8 +119,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
The commit message says bpftool stays aligned with tools/perf, and that
zlib-rs is shared with the bootstrap bpftool built for perf BPF skeletons.
In perf, zlib-rs is turned off when NO_RUST is set or rustc is not found:
tools/perf/Makefile.config:
ifneq ($(NO_RUST), 0)
NO_ZLIB_RS := 1
That NO_ZLIB_RS is a plain makefile variable in perf, so it does not reach
the sub-make that tools/perf/bpf_skel.mak runs:
$(MAKE) -C ../bpf/bpftool OUTPUT=$(SKEL_TOOL_TMP_OUT)/ \
$(BPFTOOL_RUST_OUTPUT) bootstrap
bpftool only looks at NO_ZLIB_RS and CROSS_COMPILE and never at NO_RUST.
Can "make -C tools/perf NO_RUST=1" on a host that has cargo and the cargo
registry installed still list zlib-rs in the bootstrap FEATURE_TESTS here,
run cargo to build libz_rs.a, and link the bootstrap bpftool against it?
Would it make sense to pass NO_ZLIB_RS=1 from bpf_skel.mak when perf has
disabled zlib-rs, or to have bpftool honour NO_RUST=1?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/42083491750
^ permalink raw reply [flat|nested] 7+ messages in thread