Skip to content

Commit 8c3b3ba

Browse files
committed
Overhaul vendoring/linking features
This change overhauls the vendoring & static linking features that the library exposes, in an attempt to make everything more to the point. 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. 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) Signed-off-by: Daniel Müller <[email protected]>
1 parent d001cd7 commit 8c3b3ba

File tree

4 files changed

+80
-43
lines changed

4 files changed

+80
-43
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: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::env;
44
use std::ffi;
5+
use std::ffi::OsString;
56
use std::fs;
67
use std::os::fd::AsRawFd as _;
78
use std::path;
@@ -80,16 +81,6 @@ fn generate_bindings(src_dir: path::PathBuf) {
8081
#[cfg(not(feature = "bindgen"))]
8182
fn generate_bindings(_: path::PathBuf) {}
8283

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-
9384
fn pkg_check(pkg: &str) {
9485
if process::Command::new(pkg)
9586
.stdout(process::Stdio::null())
@@ -98,7 +89,7 @@ fn pkg_check(pkg: &str) {
9889
.is_err()
9990
{
10091
panic!(
101-
"{} is required to compile libbpf-sys using the vendored copy of libbpf",
92+
"{} is required to compile libbpf-sys with the selected set of features",
10293
pkg
10394
);
10495
}
@@ -109,57 +100,83 @@ fn main() {
109100

110101
generate_bindings(src_dir.clone());
111102

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

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

119128
// check for all necessary compilation tools
120-
pkg_check("make");
121-
pkg_check("pkg-config");
122-
if cfg!(feature = "vendored") {
129+
if vendored_libelf {
123130
pkg_check("autoreconf");
124131
pkg_check("autopoint");
125132
pkg_check("flex");
126133
pkg_check("bison");
127-
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+
pkg_check("gawk");
140+
141+
let compiler = cc::Build::new().try_get_compiler().expect(
142+
"a C compiler is required to compile libbpf-sys using the vendored copy of libbpf",
143+
);
144+
let cflags = compiler.cflags_env();
145+
(Some(compiler), cflags)
146+
} else {
147+
(None, OsString::new())
135148
};
136149

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

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();
155+
if vendored_libelf {
156+
make_elfutils(compiler.as_ref().unwrap(), &src_dir, &out_dir);
147157
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-
};
158+
}
153159

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

156164
println!(
157165
"cargo:rustc-link-search=native={}",
158166
out_dir.to_string_lossy()
159167
);
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");
168+
println!(
169+
"cargo:rustc-link-lib={}elf",
170+
if static_libelf { "static=" } else { "" }
171+
);
172+
println!(
173+
"cargo:rustc-link-lib={}z",
174+
if static_zlib { "static=" } else { "" }
175+
);
176+
println!(
177+
"cargo:rustc-link-lib={}bpf",
178+
if static_libbpf { "static=" } else { "" }
179+
);
163180
println!("cargo:include={}/include", out_dir.to_string_lossy());
164181

165182
if let Ok(ld_path) = env::var("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 = "vendor-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 = "vendor-libbpf")]
1920
pub const API_HEADERS: [(&str, &str); 10] = [
2021
header!("bpf.h"),
2122
header!("libbpf.h"),

0 commit comments

Comments
 (0)