|
@@ -0,0 +1,85 @@
|
|
|
+//! ```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<P: AsRef<Path>>(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<P: Clone + AsRef<Path>>(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<String> = 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(())
|
|
|
+}
|