use std::{env, path::PathBuf, process::Command};
use which::which;
macro_rules! berr {
($($arg:tt)*) => {{
Error::Err { msg: format!($($arg)*) }
}}
}
fn main() {
match run() {
Ok(()) => {}
Err(e) => {
panic!("build failed: {}", e);
}
}
}
fn run() -> Result<(), Error> {
println!("cargo:rerun-if-changed=src/env_shim.c");
let out_dir = env::var("OUT_DIR").map_err(|e| berr!("no OUT_DIR: {}", e))?;
let mut target_so = PathBuf::from(out_dir);
target_so.push("env_shim.so");
let cc = select_cc()?;
let output = Command::new(cc)
.arg("-shared")
.arg("-fPIC")
.arg("-o")
.arg(target_so)
.arg("./src/env_shim.c")
.output()
.map_err(|e| berr!("building env shim: {}", e))?;
if !output.status.success() {
let stdout = String::from_utf8_lossy(output.stdout.as_slice());
let stderr = String::from_utf8_lossy(output.stderr.as_slice());
return Err(berr!(
"error building overlay, code = {}\nSTDOUT: {}\nSTDERR: {}",
output.status,
stdout,
stderr
));
}
Ok(())
}
fn select_cc() -> Result<PathBuf, Error> {
if let Ok(cc) = env::var("CC") {
Ok(PathBuf::from(cc))
} else if let Ok(gcc) = which("gcc") {
Ok(gcc)
} else if let Ok(clang) = which("clang") {
Ok(clang)
} else {
Err(berr!("could not select cc"))
}
}
#[non_exhaustive]
#[derive(Debug)]
enum Error {
Err { msg: String },
__NonExhaustive,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Error::Err { msg } => write!(f, "{}", msg)?,
_ => write!(f, "{:?}", self)?,
}
Ok(())
}
}
impl std::error::Error for Error {}