From 6580d77fa4229f727363a6dca6d0f7a6e6f77aec Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 28 Nov 2024 15:26:14 -0500 Subject: [PATCH] Use aya-build --- Cargo.toml | 2 +- {{project-name}}/Cargo.toml | 3 +- {{project-name}}/build.rs | 159 +++--------------------------------- 3 files changed, 14 insertions(+), 150 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8936d14..a05d7a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,12 +5,12 @@ default-members = ["{{project-name}}", "{{project-name}}-common"] [workspace.dependencies] aya = { version = "0.13.1", default-features = false } +aya-build = { version = "0.1.2", default-features = false } aya-ebpf = { version = "0.1.1", default-features = false } aya-log = { version = "0.2.1", default-features = false } aya-log-ebpf = { version = "0.1.1", default-features = false } anyhow = { version = "1", default-features = false } -cargo_metadata = { version = "0.18.0", default-features = false } # `std` feature is currently required to build `clap`. # # See https://github.com/clap-rs/clap/blob/61f5ee5/clap_builder/src/lib.rs#L15. diff --git a/{{project-name}}/Cargo.toml b/{{project-name}}/Cargo.toml index 8fe51d7..b8affd9 100644 --- a/{{project-name}}/Cargo.toml +++ b/{{project-name}}/Cargo.toml @@ -19,7 +19,8 @@ clap = { workspace = true, features = ["derive"] } {% endif -%} [build-dependencies] -cargo_metadata = { workspace = true } +anyhow = { workspace = true } +aya-build = { workspace = true } # TODO(https://github.com/rust-lang/cargo/issues/12375): this should be an artifact dependency, but # it's not possible to tell cargo to use `-Z build-std` to build it. We cargo-in-cargo in the build # script to build this, but we want to teach cargo about the dependecy so that cache invalidation diff --git a/{{project-name}}/build.rs b/{{project-name}}/build.rs index e9c7fd5..2e7e132 100644 --- a/{{project-name}}/build.rs +++ b/{{project-name}}/build.rs @@ -1,151 +1,14 @@ -use std::{ - env, fs, - io::{BufRead as _, BufReader}, - path::PathBuf, - process::{Child, Command, Stdio}, -}; - -use cargo_metadata::{ - Artifact, CompilerMessage, Message, Metadata, MetadataCommand, Package, Target, -}; - -/// This crate has a runtime dependency on artifacts produced by the `{{project-name}}-ebpf` crate. -/// This would be better expressed as one or more [artifact-dependencies][bindeps] but issues such -/// as: -/// -/// * https://github.com/rust-lang/cargo/issues/12374 -/// * https://github.com/rust-lang/cargo/issues/12375 -/// * https://github.com/rust-lang/cargo/issues/12385 -/// -/// prevent their use for the time being. -/// -/// [bindeps]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html?highlight=feature#artifact-dependencies -fn main() { - let Metadata { packages, .. } = MetadataCommand::new().no_deps().exec().unwrap(); +use anyhow::{anyhow, Context as _}; +use aya_build::cargo_metadata; + +fn main() -> anyhow::Result<()> { + let cargo_metadata::Metadata { packages, .. } = cargo_metadata::MetadataCommand::new() + .no_deps() + .exec() + .context("MetadataCommand::exec")?; let ebpf_package = packages .into_iter() - .find(|Package { name, .. }| name == "{{project-name}}-ebpf") - .unwrap(); - - let out_dir = env::var_os("OUT_DIR").unwrap(); - let out_dir = PathBuf::from(out_dir); - - let endian = env::var_os("CARGO_CFG_TARGET_ENDIAN").unwrap(); - let target = if endian == "big" { - "bpfeb" - } else if endian == "little" { - "bpfel" - } else { - panic!("unsupported endian={:?}", endian) - }; - - // TODO(https://github.com/rust-lang/cargo/issues/4001): Make this `false` if we can determine - // we're in a check build. - let build_ebpf = true; - if build_ebpf { - let arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap(); - - let target = format!("{target}-unknown-none"); - - let Package { manifest_path, .. } = ebpf_package; - let ebpf_dir = manifest_path.parent().unwrap(); - - // We have a build-dependency on `{{project-name}}-ebpf`, so cargo will automatically rebuild us - // if `{{project-name}}-ebpf`'s *library* target or any of its dependencies change. Since we - // depend on `{{project-name}}-ebpf`'s *binary* targets, that only gets us half of the way. This - // stanza ensures cargo will rebuild us on changes to the binaries too, which gets us the - // rest of the way. - println!("cargo:rerun-if-changed={}", ebpf_dir.as_str()); - - let mut cmd = Command::new("cargo"); - cmd.args([ - "+nightly", - "build", - "-Z", - "build-std=core", - "--bins", - "--message-format=json", - "--release", - "--target", - &target, - ]); - - cmd.env("CARGO_CFG_BPF_TARGET_ARCH", arch); - - // Workaround to make sure that the correct toolchain is used. - for key in ["RUSTC", "RUSTC_WORKSPACE_WRAPPER"] { - cmd.env_remove(key); - } - cmd.current_dir(ebpf_dir); - - // Workaround for https://github.com/rust-lang/cargo/issues/6412 where cargo flocks itself. - let ebpf_target_dir = out_dir.join("{{project-name}}-ebpf"); - cmd.arg("--target-dir").arg(&ebpf_target_dir); - - let mut child = cmd - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); - let Child { stdout, stderr, .. } = &mut child; - - // Trampoline stdout to cargo warnings. - let stderr = stderr.take().unwrap(); - let stderr = BufReader::new(stderr); - let stderr = std::thread::spawn(move || { - for line in stderr.lines() { - let line = line.unwrap(); - println!("cargo:warning={line}"); - } - }); - - let stdout = stdout.take().unwrap(); - let stdout = BufReader::new(stdout); - let mut executables = Vec::new(); - for message in Message::parse_stream(stdout) { - #[allow(clippy::collapsible_match)] - match message.expect("valid JSON") { - Message::CompilerArtifact(Artifact { - executable, - target: Target { name, .. }, - .. - }) => { - if let Some(executable) = executable { - executables.push((name, executable.into_std_path_buf())); - } - } - Message::CompilerMessage(CompilerMessage { message, .. }) => { - for line in message.rendered.unwrap_or_default().split('\n') { - println!("cargo:warning={line}"); - } - } - Message::TextLine(line) => { - println!("cargo:warning={line}"); - } - _ => {} - } - } - - let status = child - .wait() - .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - assert_eq!(status.code(), Some(0), "{cmd:?} failed: {status:?}"); - - stderr.join().map_err(std::panic::resume_unwind).unwrap(); - - for (name, binary) in executables { - let dst = out_dir.join(name); - let _: u64 = fs::copy(&binary, &dst) - .unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}")); - } - } else { - let Package { targets, .. } = ebpf_package; - for Target { name, kind, .. } in targets { - if *kind != ["bin"] { - continue; - } - let dst = out_dir.join(name); - fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}")); - } - } + .find(|cargo_metadata::Package { name, .. }| name == "{{project-name}}-ebpf") + .ok_or_else(|| anyhow!("{{project-name}}-ebpf package not found"))?; + aya_build::build_ebpf([ebpf_package]) }