diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54563a4..ea4e1b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,29 +6,30 @@ on: jobs: test-gnu: # dynamically linked glibc - name: Test on Ubuntu ${{ matrix.os-arch }} (${{ matrix.features }}) + name: Test on Ubuntu ${{ matrix.os-arch }} (${{ matrix.args }}) strategy: matrix: include: - rust-target: x86_64-unknown-linux-gnu os-target: x86_64-linux-gnu os-arch: amd64 - features: '' + args: '' - rust-target: x86_64-unknown-linux-gnu os-target: x86_64-linux-gnu os-arch: amd64 - features: static + args: --no-default-features + install-sys-libbpf: y - rust-target: aarch64-unknown-linux-gnu os-target: aarch64-linux-gnu os-arch: arm64 - features: '' + args: '' - rust-target: powerpc64le-unknown-linux-gnu os-target: powerpc64le-linux-gnu os-arch: ppc64el - features: '' + args: '' runs-on: ubuntu-latest env: CARGO_BUILD_TARGET: ${{ matrix.rust-target }} @@ -61,17 +62,9 @@ jobs: zlib1g-dev:${{ matrix.os-arch }} - name: Install libbpf-dev + if: matrix.install-sys-libbpf == 'y' run: sudo apt-get install libbpf-dev:${{ matrix.os-arch }} - - name: Install Static Compilation dependencies - run: | - sudo apt-get install \ - autopoint:${{ matrix.os-arch }} \ - autoconf:${{ matrix.os-arch }} \ - flex:${{ matrix.os-arch }} \ - bison:${{ matrix.os-arch }} \ - gawk:${{ matrix.os-arch }} - - name: Install linker for ${{ matrix.os-target }} if: matrix.os-arch != 'amd64' run: sudo apt-get install gcc-${{ matrix.os-target }} @@ -81,19 +74,21 @@ jobs: with: targets: ${{ matrix.rust-target }} - - run: cargo build --features "${{ matrix.features }}" + - run: cargo build ${{ matrix.args }} - - run: cargo test --features "${{ matrix.features }}" + - run: cargo test ${{ matrix.args }} if: matrix.os-arch == 'amd64' test-musl: # dynamically linked musl libc - name: Test on Alpine Linux x86_64 (${{ matrix.features }}) + name: Test on Alpine Linux x86_64 (${{ matrix.args }}) runs-on: ubuntu-latest strategy: matrix: - features: - - '' + include: + - args: '' + - args: --no-default-features + install-sys-libbpf: y env: CARGO_TERM_VERBOSE: 'true' steps: @@ -114,13 +109,14 @@ jobs: zlib-dev - name: Install libbpf-dev + if: matrix.install-sys-libbpf == 'y' run: apk add libbpf-dev shell: alpine.sh --root {0} - - run: cargo build --features "${{ matrix.features }}" + - run: cargo build ${{ matrix.args }} shell: alpine.sh {0} - - run: cargo test --features "${{ matrix.features }}" + - run: cargo test ${{ matrix.args }} shell: alpine.sh {0} test-libbpf-rs: diff --git a/Cargo.toml b/Cargo.toml index a4a157a..68a8818 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,5 +36,25 @@ num_cpus = "^1.16.0" crate-type = ["lib", "staticlib"] [features] -static = [] -novendor = [] # depricated, novendor is the default +default = ["vendored-libbpf"] +# Don't vendor anything. This feature is deprecated. Simply build without +# any features instead. +novendor = [] +# Meta-feature to use vendored versions of all dependencies. +vendored = ["vendored-libbpf", "vendored-libelf", "vendored-zlib"] +# Use vendored `libbpf`. Implies linking it statically. +vendored-libbpf = ["static-libbpf"] +# Use vendored `libelf`. Implies linking it statically. +vendored-libelf = ["static-libelf"] +# Use vendored `zlib`. Implies linking it statically. +vendored-zlib = ["static-zlib"] +# Meta-feature to link against all dependencies statically. +static = ["static-libbpf", "static-libelf", "static-zlib"] +# Link libbpf statically. +static-libbpf = [] +# Link libelf statically. Implies linking libbpf statically, because libbpf is +# the libelf consumer. +static-libelf = ["static-libbpf"] +# Link zlib statically. Implies linking libbpf statically, because libbpf is +# the libelf consumer. +static-zlib = ["static-libbpf"] diff --git a/build.rs b/build.rs index 7ac5ec1..7f5651d 100644 --- a/build.rs +++ b/build.rs @@ -1,10 +1,14 @@ // build.rs use std::env; +use std::ffi; use std::fs; +use std::os::fd::AsRawFd as _; use std::path; use std::process; +use nix::fcntl; + #[cfg(feature = "bindgen")] fn generate_bindings(src_dir: path::PathBuf) { use std::collections::HashSet; @@ -76,19 +80,17 @@ fn generate_bindings(src_dir: path::PathBuf) { #[cfg(not(feature = "bindgen"))] fn generate_bindings(_: path::PathBuf) {} -#[cfg(feature = "static")] -fn library_prefix() -> String { - "static=".to_string() -} - -#[cfg(not(feature = "static"))] -fn library_prefix() -> String { - "".to_string() -} - fn pkg_check(pkg: &str) { - if let Err(_) = process::Command::new(pkg).status() { - panic!("{} is required to compile libbpf-sys using the vendored copy of libbpf", pkg); + if process::Command::new(pkg) + .stdout(process::Stdio::null()) + .stderr(process::Stdio::null()) + .status() + .is_err() + { + panic!( + "{} is required to compile libbpf-sys with the selected set of features", + pkg + ); } } @@ -97,85 +99,88 @@ fn main() { generate_bindings(src_dir.clone()); - if cfg!(not(feature = "static")) { - println!("cargo:rustc-link-lib={}bpf\n", library_prefix()); + let vendored_libbpf = cfg!(feature = "vendored-libbpf"); + let vendored_libelf = cfg!(feature = "vendored-libelf"); + let vendored_zlib = cfg!(feature = "vendored-zlib"); + println!("Using feature vendored-libbpf={}", vendored_libbpf); + println!("Using feature vendored-libelf={}", vendored_libelf); + println!("Using feature vendored-zlib={}", vendored_zlib); + + let static_libbpf = cfg!(feature = "static-libbpf"); + let static_libelf = cfg!(feature = "static-libelf"); + let static_zlib = cfg!(feature = "static-zlib"); + println!("Using feature static-libbpf={}", static_libbpf); + println!("Using feature static-libelf={}", static_libelf); + println!("Using feature static-zlib={}", static_zlib); + + if cfg!(feature = "novendor") { + println!("cargo:warning=the `novendor` feature of `libbpf-sys` is deprecated; build without features instead"); + println!( + "cargo:rustc-link-lib={}bpf", + if static_libbpf { "static=" } else { "" } + ); return; } let out_dir = path::PathBuf::from(env::var_os("OUT_DIR").unwrap()); // check for all necessary compilation tools - pkg_check("make"); - pkg_check("pkg-config"); - pkg_check("autoreconf"); - pkg_check("autopoint"); - pkg_check("flex"); - pkg_check("bison"); - pkg_check("gawk"); - - let compiler = match cc::Build::new().try_get_compiler() { - Ok(compiler) => compiler, - Err(_) => panic!( - "a C compiler is required to compile libbpf-sys using the vendored copy of libbpf" - ), - }; - - // create obj_dir if it doesn't exist - let obj_dir = path::PathBuf::from(&out_dir.join("obj").into_os_string()); - let _ = fs::create_dir(&obj_dir); + if vendored_libelf { + pkg_check("autoreconf"); + pkg_check("autopoint"); + pkg_check("flex"); + pkg_check("bison"); + pkg_check("gawk"); + } - // compile static zlib and static libelf - make_zlib(&compiler, &src_dir, &out_dir); - make_elfutils(&compiler, &src_dir, &out_dir); + let (compiler, mut cflags) = if vendored_libbpf || vendored_libelf || vendored_zlib { + pkg_check("make"); + pkg_check("pkg-config"); - let cflags = if cfg!(feature = "vendored") { - // make sure that the headerfiles from libelf and zlib - // for libbpf come from the vendorized version - - let mut cflags = compiler.cflags_env(); - cflags.push(&format!(" -I{}/elfutils/libelf/", src_dir.display())); - cflags.push(&format!(" -I{}/zlib/", src_dir.display())); - cflags + let compiler = cc::Build::new().try_get_compiler().expect( + "a C compiler is required to compile libbpf-sys using the vendored copy of libbpf", + ); + let cflags = compiler.cflags_env(); + (Some(compiler), cflags) } else { - compiler.cflags_env() + (None, ffi::OsString::new()) }; - let status = process::Command::new("make") - .arg("install") - .arg("-j") - .arg(&format!("{}", num_cpus::get())) - .env("BUILD_STATIC_ONLY", "y") - .env("PREFIX", "/") - .env("LIBDIR", "") - .env("OBJDIR", &obj_dir) - .env("DESTDIR", &out_dir) - .env("CC", compiler.path()) - .env("CFLAGS", cflags) - .current_dir(&src_dir.join("libbpf/src")) - .status() - .expect("could not execute make"); - - assert!(status.success(), "make failed"); + if vendored_zlib { + make_zlib(compiler.as_ref().unwrap(), &src_dir, &out_dir); + cflags.push(&format!(" -I{}/zlib/", src_dir.display())); + } - let status = process::Command::new("make") - .arg("clean") - .current_dir(&src_dir.join("libbpf/src")) - .status() - .expect("could not execute make"); + if vendored_libelf { + make_elfutils(compiler.as_ref().unwrap(), &src_dir, &out_dir); + cflags.push(&format!(" -I{}/elfutils/libelf/", src_dir.display())); + } - assert!(status.success(), "make failed"); + if vendored_libbpf { + make_libbpf(compiler.as_ref().unwrap(), &cflags, &src_dir, &out_dir); + } println!( "cargo:rustc-link-search=native={}", out_dir.to_string_lossy() ); - println!("cargo:rustc-link-lib={}elf", library_prefix()); - println!("cargo:rustc-link-lib={}z", library_prefix()); - println!("cargo:rustc-link-lib=static=bpf"); + println!( + "cargo:rustc-link-lib={}elf", + if static_libelf { "static=" } else { "" } + ); + println!( + "cargo:rustc-link-lib={}z", + if static_zlib { "static=" } else { "" } + ); + println!( + "cargo:rustc-link-lib={}bpf", + if static_libbpf { "static=" } else { "" } + ); println!("cargo:include={}/include", out_dir.to_string_lossy()); + println!("cargo:rerun-if-env-changed=LD_LIBRARY_PATH"); if let Ok(ld_path) = env::var("LD_LIBRARY_PATH") { - for path in ld_path.split(":") { + for path in ld_path.split(':') { if !path.is_empty() { println!("cargo:rustc-link-search=native={}", path); } @@ -183,14 +188,11 @@ fn main() { } } -fn make_zlib(compiler: &cc::Tool, src_dir: &path::PathBuf, out_dir: &path::PathBuf) { - use nix::fcntl; - use std::os::fd::AsRawFd; - +fn make_zlib(compiler: &cc::Tool, src_dir: &path::Path, out_dir: &path::Path) { // lock README such that if two crates are trying to compile // this at the same time (eg libbpf-rs libbpf-cargo) // they wont trample each other - let file = std::fs::File::open(&src_dir.join("zlib/README")).unwrap(); + let file = std::fs::File::open(src_dir.join("zlib/README")).unwrap(); let fd = file.as_raw_fd(); fcntl::flock(fd, fcntl::FlockArg::LockExclusive).unwrap(); @@ -227,14 +229,11 @@ fn make_zlib(compiler: &cc::Tool, src_dir: &path::PathBuf, out_dir: &path::PathB assert!(status.success(), "make failed"); } -fn make_elfutils(compiler: &cc::Tool, src_dir: &path::PathBuf, out_dir: &path::PathBuf) { - use nix::fcntl; - use std::os::fd::AsRawFd; - +fn make_elfutils(compiler: &cc::Tool, src_dir: &path::Path, out_dir: &path::Path) { // lock README such that if two crates are trying to compile // this at the same time (eg libbpf-rs libbpf-cargo) // they wont trample each other - let file = std::fs::File::open(&src_dir.join("elfutils/README")).unwrap(); + let file = std::fs::File::open(src_dir.join("elfutils/README")).unwrap(); let fd = file.as_raw_fd(); fcntl::flock(fd, fcntl::FlockArg::LockExclusive).unwrap(); @@ -308,3 +307,39 @@ fn make_elfutils(compiler: &cc::Tool, src_dir: &path::PathBuf, out_dir: &path::P assert!(status.success(), "make failed"); } + +fn make_libbpf( + compiler: &cc::Tool, + cflags: &ffi::OsStr, + src_dir: &path::Path, + out_dir: &path::Path, +) { + // create obj_dir if it doesn't exist + let obj_dir = path::PathBuf::from(&out_dir.join("obj").into_os_string()); + let _ = fs::create_dir(&obj_dir); + + let status = process::Command::new("make") + .arg("install") + .arg("-j") + .arg(&format!("{}", num_cpus::get())) + .env("BUILD_STATIC_ONLY", "y") + .env("PREFIX", "/") + .env("LIBDIR", "") + .env("OBJDIR", &obj_dir) + .env("DESTDIR", out_dir) + .env("CC", compiler.path()) + .env("CFLAGS", cflags) + .current_dir(&src_dir.join("libbpf/src")) + .status() + .expect("could not execute make"); + + assert!(status.success(), "make failed"); + + let status = process::Command::new("make") + .arg("clean") + .current_dir(&src_dir.join("libbpf/src")) + .status() + .expect("could not execute make"); + + assert!(status.success(), "make failed"); +} diff --git a/src/lib.rs b/src/lib.rs index 8178a7e..ec7f9ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ include!("bindings.rs"); -#[cfg(feature = "static")] +#[cfg(feature = "vendored-libbpf")] macro_rules! header { ($file:literal) => { ($file, include_str!(concat!("../libbpf/src/", $file))) @@ -16,8 +16,8 @@ macro_rules! header { /// Vendored libbpf headers /// /// Tuple format is: (header filename, header contents) -#[cfg(feature = "static")] -pub const API_HEADERS: [(&'static str, &'static str); 10] = [ +#[cfg(feature = "vendored-libbpf")] +pub const API_HEADERS: [(&str, &str); 10] = [ header!("bpf.h"), header!("libbpf.h"), header!("btf.h"), diff --git a/tests/tests.rs b/tests/tests.rs index 38c82ed..7d6e8bb 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -9,7 +9,7 @@ mod tests { _arg1: *const std::os::raw::c_char, _ap: *mut __va_list_tag, ) -> std::os::raw::c_int { - return 0; + 0 } #[test]