//! ```cargo //! [dependencies] //! libbpf-sys = { version = "0.6.1-1" } //! anyhow = "1" //! ``` use std::{ env, fs::{self, OpenOptions}, io::Write, path::Path, process::Command, string::String, }; use anyhow::{bail, Context, Result}; static CLANG_DEFAULT: &str = "/usr/bin/clang"; /// Extract vendored libbpf headers from libbpf-sys. fn extract_libbpf_headers>(include_path: P) -> Result<()> { let dir = include_path.as_ref().join("bpf"); fs::create_dir_all(&dir)?; for (filename, contents) in libbpf_sys::API_HEADERS.iter() { let path = dir.as_path().join(filename); let mut file = OpenOptions::new().write(true).create(true).open(path)?; file.write_all(contents.as_bytes())?; } Ok(()) } /// Build eBPF programs with clang and libbpf headers. fn build_ebpf>(in_file: P, out_file: P, include_path: P) -> Result<()> { extract_libbpf_headers(include_path.clone())?; let clang = match env::var("CLANG") { Ok(val) => val, Err(_) => String::from(CLANG_DEFAULT), }; let arch = match std::env::consts::ARCH { "x86_64" => "x86", "aarch64" => "arm64", _ => std::env::consts::ARCH, }; let mut cmd = Command::new(clang); cmd.arg(format!("-I{}", include_path.as_ref().to_string_lossy())) .arg("-g") .arg("-O2") .arg("-target") .arg("bpf") .arg("-c") .arg(format!("-D__TARGET_ARCH_{}", arch)) .arg(in_file.as_ref().as_os_str()) .arg("-o") .arg(out_file.as_ref().as_os_str()); let output = cmd.output().context("Failed to execute clang")?; if !output.status.success() { bail!( "Failed to compile eBPF programs\n \ stdout=\n \ {}\n \ stderr=\n \ {}\n", String::from_utf8(output.stdout).unwrap(), String::from_utf8(output.stderr).unwrap() ); } Ok(()) } fn main() -> Result<()> { let args: Vec = env::args().collect(); if args.len() != 3 { bail!("requires 2 arguments. src and dst") } let path = env::current_dir()?; let src = Path::new(&args[1]); let dst = Path::new(&args[2]); let include_path = path.join("include"); fs::create_dir_all(include_path.clone())?; build_ebpf(src, dst, &include_path)?; Ok(()) }