compile-ebpf.ers 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. //! ```cargo
  2. //! [dependencies]
  3. //! libbpf-sys = { version = "0.6.1-1" }
  4. //! anyhow = "1"
  5. //! ```
  6. use std::{
  7. env,
  8. fs::{self, OpenOptions},
  9. io::Write,
  10. path::Path,
  11. process::Command,
  12. string::String,
  13. };
  14. use anyhow::{bail, Context, Result};
  15. static CLANG_DEFAULT: &str = "/usr/bin/clang";
  16. /// Extract vendored libbpf headers from libbpf-sys.
  17. fn extract_libbpf_headers<P: AsRef<Path>>(include_path: P) -> Result<()> {
  18. let dir = include_path.as_ref().join("bpf");
  19. fs::create_dir_all(&dir)?;
  20. for (filename, contents) in libbpf_sys::API_HEADERS.iter() {
  21. let path = dir.as_path().join(filename);
  22. let mut file = OpenOptions::new().write(true).create(true).open(path)?;
  23. file.write_all(contents.as_bytes())?;
  24. }
  25. Ok(())
  26. }
  27. /// Build eBPF programs with clang and libbpf headers.
  28. fn build_ebpf<P: Clone + AsRef<Path>>(in_file: P, out_file: P, include_path: P) -> Result<()> {
  29. extract_libbpf_headers(include_path.clone())?;
  30. let clang = match env::var("CLANG") {
  31. Ok(val) => val,
  32. Err(_) => String::from(CLANG_DEFAULT),
  33. };
  34. let arch = match std::env::consts::ARCH {
  35. "x86_64" => "x86",
  36. "aarch64" => "arm64",
  37. _ => std::env::consts::ARCH,
  38. };
  39. let mut cmd = Command::new(clang);
  40. cmd.arg(format!("-I{}", include_path.as_ref().to_string_lossy()))
  41. .arg("-g")
  42. .arg("-O2")
  43. .arg("-target")
  44. .arg("bpf")
  45. .arg("-c")
  46. .arg(format!("-D__TARGET_ARCH_{}", arch))
  47. .arg(in_file.as_ref().as_os_str())
  48. .arg("-o")
  49. .arg(out_file.as_ref().as_os_str());
  50. let output = cmd.output().context("Failed to execute clang")?;
  51. if !output.status.success() {
  52. bail!(
  53. "Failed to compile eBPF programs\n \
  54. stdout=\n \
  55. {}\n \
  56. stderr=\n \
  57. {}\n",
  58. String::from_utf8(output.stdout).unwrap(),
  59. String::from_utf8(output.stderr).unwrap()
  60. );
  61. }
  62. Ok(())
  63. }
  64. fn main() -> Result<()> {
  65. let args: Vec<String> = env::args().collect();
  66. if args.len() != 3 {
  67. bail!("requires 2 arguments. src and dst")
  68. }
  69. let path = env::current_dir()?;
  70. let src = Path::new(&args[1]);
  71. let dst = Path::new(&args[2]);
  72. let include_path = path.join("include");
  73. fs::create_dir_all(include_path.clone())?;
  74. build_ebpf(src, dst, &include_path)?;
  75. Ok(())
  76. }