use std::env;
use std::path::PathBuf;
use std::process::Command;
fn find_musl_gcc() -> Option<String> {
if let Ok(cc) = env::var("ONELF_MUSL_CC") {
return Some(cc);
}
if let Ok(cc) = env::var("CC_x86_64_unknown_linux_musl") {
return Some(cc);
}
for name in &["x86_64-linux-musl-gcc", "musl-gcc"] {
if let Ok(output) = Command::new("which").arg(name).output() {
if output.status.success() {
let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !path.is_empty() {
return Some(path);
}
}
}
}
if let Ok(entries) = std::fs::read_dir("/nix/store") {
for entry in entries.flatten() {
let name = entry.file_name();
let name_str = name.to_string_lossy();
if name_str.contains("musl") && name_str.contains("-dev") {
let gcc_path = entry.path().join("bin/musl-gcc");
if gcc_path.exists() {
return Some(gcc_path.to_string_lossy().to_string());
}
}
}
}
None
}
fn main() {
println!("cargo:rerun-if-env-changed=ONELF_RT_PATH");
println!("cargo:rerun-if-env-changed=ONELF_MUSL_CC");
println!("cargo:rerun-if-env-changed=CC_x86_64_unknown_linux_musl");
if let Ok(rt_path) = env::var("ONELF_RT_PATH") {
let path = PathBuf::from(&rt_path);
if !path.exists() {
panic!("ONELF_RT_PATH={rt_path} does not exist");
}
println!("cargo:rustc-env=ONELF_RT_PATH={rt_path}");
return;
}
println!("cargo:rerun-if-changed=../onelf-rt/src/");
println!("cargo:rerun-if-changed=../onelf-format/src/");
let out_dir = env::var("OUT_DIR").unwrap();
let profile = env::var("PROFILE").unwrap();
let target = "x86_64-unknown-linux-musl";
let cargo = PathBuf::from(env::var("CARGO").unwrap())
.canonicalize()
.unwrap();
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let rt_dir = manifest_dir.join("../onelf-rt");
if !rt_dir.exists() {
panic!(
"onelf-rt source not found at {}. Set ONELF_RT_PATH to a pre-built runtime binary.",
rt_dir.display()
);
}
let rt_dir = rt_dir.canonicalize().unwrap();
let target_dir = PathBuf::from(&out_dir).join("onelf-rt-build");
let musl_cc = find_musl_gcc().expect(
"Could not find musl-gcc. Set ONELF_MUSL_CC or CC_x86_64_unknown_linux_musl, \
or install musl-gcc to PATH.",
);
eprintln!("Using musl CC: {musl_cc}");
let mut cmd = Command::new(&cargo);
for (key, _) in env::vars() {
if (key.starts_with("CARGO") || key.starts_with("RUSTC")) && !key.ends_with("_LINKER") {
cmd.env_remove(&key);
}
}
let mut rustflags = String::from(
"-Ctarget-feature=+crt-static -Crelocation-model=static -Clink-arg=-Wl,--no-dynamic-linker",
);
if profile == "release" {
rustflags.push_str(" -Cdebuginfo=0");
}
cmd.env("RUSTFLAGS", &rustflags)
.env("CC", &musl_cc)
.env("CC_x86_64_unknown_linux_musl", &musl_cc)
.current_dir(&rt_dir)
.arg("build")
.arg("--target")
.arg(target)
.arg("--target-dir")
.arg(&target_dir);
if profile == "release" {
cmd.arg("--release");
}
eprintln!("Building onelf-rt for {target}...");
let status = cmd
.status()
.unwrap_or_else(|e| panic!("failed to build onelf-rt: {e}"));
if !status.success() {
panic!("onelf-rt build failed");
}
let rt_binary = target_dir.join(target).join(&profile).join("onelf-rt");
if !rt_binary.exists() {
panic!("onelf-rt binary not found at: {}", rt_binary.display());
}
println!("cargo:rustc-env=ONELF_RT_PATH={}", rt_binary.display());
}