123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- use std::{
- env, fs,
- path::{Path, PathBuf},
- process::Command,
- };
- use anyhow::{bail, Context};
- use clap::Parser;
- use crate::utils::WORKSPACE_ROOT;
- #[derive(Debug, Copy, Clone)]
- pub enum Architecture {
- BpfEl,
- BpfEb,
- }
- impl std::str::FromStr for Architecture {
- type Err = String;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- Ok(match s {
- "bpfel-unknown-none" => Architecture::BpfEl,
- "bpfeb-unknown-none" => Architecture::BpfEb,
- _ => return Err("invalid target".to_owned()),
- })
- }
- }
- impl std::fmt::Display for Architecture {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(match self {
- Architecture::BpfEl => "bpfel-unknown-none",
- Architecture::BpfEb => "bpfeb-unknown-none",
- })
- }
- }
- #[derive(Debug, Parser)]
- pub struct Options {
- /// Set the endianness of the BPF target
- #[clap(default_value = "bpfel-unknown-none", long)]
- pub target: Architecture,
- /// Build the release target
- #[clap(long)]
- pub release: bool,
- /// Libbpf dir, required for compiling C code
- #[clap(long, action)]
- pub libbpf_dir: PathBuf,
- }
- pub fn build_ebpf(opts: Options) -> anyhow::Result<()> {
- build_rust_ebpf(&opts)?;
- build_c_ebpf(&opts)
- }
- fn build_rust_ebpf(opts: &Options) -> anyhow::Result<()> {
- let mut dir = PathBuf::from(WORKSPACE_ROOT.to_string());
- dir.push("test/integration-ebpf");
- let target = format!("--target={}", opts.target);
- let mut args = vec![
- "+nightly",
- "build",
- "--verbose",
- target.as_str(),
- "-Z",
- "build-std=core",
- ];
- if opts.release {
- args.push("--release")
- }
- let status = Command::new("cargo")
- .current_dir(&dir)
- .args(&args)
- .status()
- .expect("failed to build bpf program");
- assert!(status.success());
- Ok(())
- }
- fn get_libbpf_headers<P: AsRef<Path>>(libbpf_dir: P, include_path: P) -> anyhow::Result<()> {
- let dir = include_path.as_ref();
- fs::create_dir_all(dir)?;
- let status = Command::new("make")
- .current_dir(libbpf_dir.as_ref().join("src"))
- .arg(format!("INCLUDEDIR={}", dir.as_os_str().to_string_lossy()))
- .arg("install_headers")
- .status()
- .expect("failed to build get libbpf headers");
- assert!(status.success());
- Ok(())
- }
- fn build_c_ebpf(opts: &Options) -> anyhow::Result<()> {
- let mut src = PathBuf::from(WORKSPACE_ROOT.to_string());
- src.push("test/integration-ebpf/src/bpf");
- let mut out_path = PathBuf::from(WORKSPACE_ROOT.to_string());
- out_path.push("target");
- out_path.push(opts.target.to_string());
- out_path.push(if opts.release { "release " } else { "debug" });
- let include_path = out_path.join("include");
- get_libbpf_headers(&opts.libbpf_dir, &include_path)?;
- let files = fs::read_dir(&src).unwrap();
- for file in files {
- let p = file.unwrap().path();
- if let Some(ext) = p.extension() {
- if ext == "c" {
- let mut out = PathBuf::from(&out_path);
- out.push(p.file_name().unwrap());
- out.set_extension("o");
- compile_with_clang(&p, &out, &include_path)?;
- }
- }
- }
- Ok(())
- }
- /// Build eBPF programs with clang and libbpf headers.
- fn compile_with_clang<P: Clone + AsRef<Path>>(
- src: P,
- out: P,
- include_path: P,
- ) -> anyhow::Result<()> {
- let clang = match env::var("CLANG") {
- Ok(val) => val,
- Err(_) => String::from("/usr/bin/clang"),
- };
- 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(src.as_ref().as_os_str())
- .arg("-o")
- .arg(out.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(())
- }
|