diff --git a/aya-gen/Cargo.toml b/aya-gen/Cargo.toml index dc38497f..5944e443 100644 --- a/aya-gen/Cargo.toml +++ b/aya-gen/Cargo.toml @@ -13,3 +13,4 @@ syn = "1" quote = "1" proc-macro2 = "1" indexmap = "1.6" +tempfile = "3" diff --git a/aya-gen/src/btf_types.rs b/aya-gen/src/btf_types.rs index a1c55443..d23fe2bc 100644 --- a/aya-gen/src/btf_types.rs +++ b/aya-gen/src/btf_types.rs @@ -1,10 +1,13 @@ use std::{ - fs, io, + fs::{self, File}, + io::{self, Write}, path::{Path, PathBuf}, process::Command, str::from_utf8, }; +use tempfile::tempdir; + use thiserror::Error; use crate::bindgen; @@ -18,7 +21,10 @@ pub enum Error { BpfToolExit { code: i32, stderr: String }, #[error("bindgen failed")] - Bindgen, + Bindgen(#[source] io::Error), + + #[error("{stderr}\nbindgen failed with exit code {code}")] + BindgenExit { code: i32, stderr: String }, #[error("rustfmt failed")] Rustfmt(#[source] io::Error), @@ -35,25 +41,49 @@ pub enum InputFile { pub fn generate>(input_file: InputFile, types: &[T]) -> Result { let mut bindgen = bindgen::bpf_builder(); - match input_file { - InputFile::Btf(path) => { - let c_header = c_header_from_btf(&path)?; - bindgen = bindgen.header_contents("kernel_types.h", &c_header); - } - InputFile::Header(header) => { - let c_header = fs::read_to_string(&header).map_err(|_| Error::ReadHeaderFile)?; - let name = Path::new(&header).file_name().unwrap().to_str().unwrap(); - bindgen = bindgen.header_contents(name, &c_header); - } - } + let (c_header, name) = match input_file { + InputFile::Btf(path) => (c_header_from_btf(&path)?, "kernel_types.h".to_string()), + InputFile::Header(header) => ( + fs::read_to_string(&header).map_err(|_| Error::ReadHeaderFile)?, + header.file_name().unwrap().to_str().unwrap().to_owned(), + ), + }; for ty in types { bindgen = bindgen.allowlist_type(ty); } - let bindings = bindgen.generate().or(Err(Error::Bindgen))?.to_string(); + // TODO: check if this part should be moved to bindgen::generate() + let dir = tempdir().unwrap(); + let file_path = dir.path().join(name); + let mut file = File::create(&file_path).unwrap(); + let _ = file.write(c_header.as_bytes()).unwrap(); + + let flags = bindgen.command_line_flags(); + + // TODO: check proper logging; it seems useful to see what command is + // launched but we can't disturb the normal output of the aya-gen tool + println!( + "Launching bindgen {} {}", + file_path.to_str().unwrap(), + flags.join(" ") + ); + + let output = Command::new("bindgen") + .arg(file_path) + .args(flags) + // TODO: pass additional arguments after -- + .output() + .map_err(Error::Bindgen)?; - Ok(bindings) + if !output.status.success() { + return Err(Error::BindgenExit { + code: output.status.code().unwrap(), + stderr: from_utf8(&output.stderr).unwrap().to_owned(), + }); + } + + Ok(from_utf8(&output.stdout).unwrap().to_owned()) } fn c_header_from_btf(path: &Path) -> Result {