Use aya-build
parent
cb9ab79705
commit
6580d77fa4
@ -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])
|
||||
}
|
||||
|
Loading…
Reference in New Issue