Skip to content

Commit eac7ce4

Browse files
committed
Overhaul vendoring/linking features
This change overhauls the vendoring & static linking features that the library exposes. Please refer to the larger discussion [0] for additional context, but in short: we introduce separate features for vendoring/linking each of the three system library dependencies: libbpf, libelf, zlib. "static" and "vendored" meta-features are still available, which apply to all three libraries in unison. The remaining dependencies are expressed declaratively via dependent features. E.g., because zlib is only a dependency of libbpf (and not a direct one), linking it statically implies linking libbpf statically. In the future, this design would make it possible to enable additional configurations. For example, currently vendoring any library implies linking it statically, because we only build the static version. This is more of a simplification than a strict requirement and if needed, we could support dynamic linking when using a vendored copy. We could alternatively move to a model where we err out on combinations that make little sense/are risky/whatever. Doing so could be beneficial if we ever were to loosen some of those dependencies down the line to minimize chance of breakage. I am unsure how likely that really is or whether it would be cause for concern, and I generally like the declarative nature of "this feature depends on this other" in Cargo.toml, but we could change that if we feel strongly. The default features mirror the previous default and no behavior change should occur. The existing novendor feature is kept but deprecated and should be removed in the future (a warning will be printed as part of the build). It was certainly one of the main causes of confusion where novendor and vendored could co-exist and it was hard to understand what would or wouldn't happen. In the new world, users are advised to simply build with all features disabled. I tested everything on a binary depending on libbpf-sys with various features enabled and spot checked the expected dynamic library dependencies. We could enshrine that as a CI step, but given that this logic is expected to change infrequently I didn't go down that road. [0] libbpf#64 (comment) Closes: libbpf#70 Signed-off-by: Daniel Müller <[email protected]>
1 parent 627c2ac commit eac7ce4

File tree

4 files changed

+78
-42
lines changed

4 files changed

+78
-42
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- rust-target: x86_64-unknown-linux-gnu
1919
os-target: x86_64-linux-gnu
2020
os-arch: amd64
21-
args: --features=novendor
21+
args: --no-default-features
2222
install-sys-libbpf: y
2323

2424
- rust-target: aarch64-unknown-linux-gnu
@@ -87,7 +87,7 @@ jobs:
8787
matrix:
8888
include:
8989
- args: ''
90-
- args: --features=novendor
90+
- args: --no-default-features
9191
install-sys-libbpf: y
9292
env:
9393
CARGO_TERM_VERBOSE: 'true'

Cargo.toml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ num_cpus = "^1.16.0"
3636
crate-type = ["lib", "staticlib"]
3737

3838
[features]
39+
default = ["vendored-libbpf"]
40+
# Don't vendor anything. This feature is deprecated. Simply build without
41+
# any features instead.
3942
novendor = []
40-
static = []
41-
vendored = ["static"]
43+
# Meta-feature to use vendored versions of all dependencies.
44+
vendored = ["vendored-libbpf", "vendored-libelf", "vendored-zlib"]
45+
# Use vendored `libbpf`. Implies linking it statically.
46+
vendored-libbpf = ["static-libbpf"]
47+
# Use vendored `libelf`. Implies linking it statically.
48+
vendored-libelf = ["static-libelf"]
49+
# Use vendored `zlib`. Implies linking it statically.
50+
vendored-zlib = ["static-zlib"]
51+
# Meta-feature to link against all dependencies statically.
52+
static = ["static-libbpf", "static-libelf", "static-zlib"]
53+
# Link libbpf statically.
54+
static-libbpf = []
55+
# Link libelf statically. Implies linking libbpf statically, because libbpf is
56+
# the libelf consumer.
57+
static-libelf = ["static-libbpf"]
58+
# Link zlib statically. Implies linking libbpf statically, because libbpf is
59+
# the libelf consumer.
60+
static-zlib = ["static-libbpf"]

build.rs

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,6 @@ fn generate_bindings(src_dir: path::PathBuf) {
8080
#[cfg(not(feature = "bindgen"))]
8181
fn generate_bindings(_: path::PathBuf) {}
8282

83-
#[cfg(feature = "static")]
84-
fn library_prefix() -> String {
85-
"static=".to_string()
86-
}
87-
88-
#[cfg(not(feature = "static"))]
89-
fn library_prefix() -> String {
90-
"".to_string()
91-
}
92-
9383
fn pkg_check(pkg: &str) {
9484
if process::Command::new(pkg)
9585
.stdout(process::Stdio::null())
@@ -98,7 +88,7 @@ fn pkg_check(pkg: &str) {
9888
.is_err()
9989
{
10090
panic!(
101-
"{} is required to compile libbpf-sys using the vendored copy of libbpf",
91+
"{} is required to compile libbpf-sys with the selected set of features",
10292
pkg
10393
);
10494
}
@@ -109,57 +99,83 @@ fn main() {
10999

110100
generate_bindings(src_dir.clone());
111101

102+
let vendored_libbpf = cfg!(feature = "vendored-libbpf");
103+
let vendored_libelf = cfg!(feature = "vendored-libelf");
104+
let vendored_zlib = cfg!(feature = "vendored-zlib");
105+
println!("Using feature vendored-libbpf={}", vendored_libbpf);
106+
println!("Using feature vendored-libelf={}", vendored_libelf);
107+
println!("Using feature vendored-zlib={}", vendored_zlib);
108+
109+
let static_libbpf = cfg!(feature = "static-libbpf");
110+
let static_libelf = cfg!(feature = "static-libelf");
111+
let static_zlib = cfg!(feature = "static-zlib");
112+
println!("Using feature static-libbpf={}", static_libbpf);
113+
println!("Using feature static-libelf={}", static_libelf);
114+
println!("Using feature static-zlib={}", static_zlib);
115+
112116
if cfg!(feature = "novendor") {
113-
println!("cargo:rustc-link-lib={}bpf\n", library_prefix());
117+
println!("cargo:warning=the `novendor` feature of `libbpf-sys` is deprecated; build without features instead");
118+
println!(
119+
"cargo:rustc-link-lib={}bpf",
120+
if static_libbpf { "static=" } else { "" }
121+
);
114122
return;
115123
}
116124

117125
let out_dir = path::PathBuf::from(env::var_os("OUT_DIR").unwrap());
118126

119127
// check for all necessary compilation tools
120-
pkg_check("make");
121-
pkg_check("pkg-config");
122-
if cfg!(feature = "vendored") {
128+
if vendored_libelf {
123129
pkg_check("autoreconf");
124130
pkg_check("autopoint");
125131
pkg_check("flex");
126132
pkg_check("bison");
127133
pkg_check("gawk");
128134
}
129135

130-
let compiler = match cc::Build::new().try_get_compiler() {
131-
Ok(compiler) => compiler,
132-
Err(_) => panic!(
133-
"a C compiler is required to compile libbpf-sys using the vendored copy of libbpf"
134-
),
136+
let (compiler, mut cflags) = if vendored_libbpf || vendored_libelf || vendored_zlib {
137+
pkg_check("make");
138+
pkg_check("pkg-config");
139+
140+
let compiler = cc::Build::new().try_get_compiler().expect(
141+
"a C compiler is required to compile libbpf-sys using the vendored copy of libbpf",
142+
);
143+
let cflags = compiler.cflags_env();
144+
(Some(compiler), cflags)
145+
} else {
146+
(None, ffi::OsString::new())
135147
};
136148

137-
if cfg!(feature = "vendored") {
138-
make_zlib(&compiler, &src_dir, &out_dir);
139-
make_elfutils(&compiler, &src_dir, &out_dir);
149+
if vendored_zlib {
150+
make_zlib(compiler.as_ref().unwrap(), &src_dir, &out_dir);
151+
cflags.push(&format!(" -I{}/zlib/", src_dir.display()));
140152
}
141153

142-
let cflags = if cfg!(feature = "vendored") {
143-
// make sure that the headerfiles from libelf and zlib
144-
// for libbpf come from the vendorized version
145-
146-
let mut cflags = compiler.cflags_env();
154+
if vendored_libelf {
155+
make_elfutils(compiler.as_ref().unwrap(), &src_dir, &out_dir);
147156
cflags.push(&format!(" -I{}/elfutils/libelf/", src_dir.display()));
148-
cflags.push(&format!(" -I{}/zlib/", src_dir.display()));
149-
cflags
150-
} else {
151-
compiler.cflags_env()
152-
};
157+
}
153158

154-
make_libbpf(&compiler, &cflags, &src_dir, &out_dir);
159+
if vendored_libbpf {
160+
make_libbpf(compiler.as_ref().unwrap(), &cflags, &src_dir, &out_dir);
161+
}
155162

156163
println!(
157164
"cargo:rustc-link-search=native={}",
158165
out_dir.to_string_lossy()
159166
);
160-
println!("cargo:rustc-link-lib={}elf", library_prefix());
161-
println!("cargo:rustc-link-lib={}z", library_prefix());
162-
println!("cargo:rustc-link-lib=static=bpf");
167+
println!(
168+
"cargo:rustc-link-lib={}elf",
169+
if static_libelf { "static=" } else { "" }
170+
);
171+
println!(
172+
"cargo:rustc-link-lib={}z",
173+
if static_zlib { "static=" } else { "" }
174+
);
175+
println!(
176+
"cargo:rustc-link-lib={}bpf",
177+
if static_libbpf { "static=" } else { "" }
178+
);
163179
println!("cargo:include={}/include", out_dir.to_string_lossy());
164180

165181
println!("cargo:rerun-if-env-changed=LD_LIBRARY_PATH");

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
include!("bindings.rs");
88

9+
#[cfg(feature = "vendored-libbpf")]
910
macro_rules! header {
1011
($file:literal) => {
1112
($file, include_str!(concat!("../libbpf/src/", $file)))
@@ -15,7 +16,7 @@ macro_rules! header {
1516
/// Vendored libbpf headers
1617
///
1718
/// Tuple format is: (header filename, header contents)
18-
#[cfg(not(feature = "novendor"))]
19+
#[cfg(feature = "vendored-libbpf")]
1920
pub const API_HEADERS: [(&str, &str); 10] = [
2021
header!("bpf.h"),
2122
header!("libbpf.h"),

0 commit comments

Comments
 (0)