use std::{env, path::PathBuf, process::Command};
fn main() {
let sysroot = build_lib();
generates_bindings_to_rust(sysroot.as_deref());
}
fn build_lib() -> Option<String> {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let c_src = manifest_dir.join("./lwprintf/lwprintf/src/lwprintf/lwprintf.c");
let include_dir = manifest_dir.join("./lwprintf/lwprintf/src/include");
let opts_file = manifest_dir.join("lwprintf_opts.h");
println!("cargo:rerun-if-changed={}", c_src.display());
println!("cargo:rerun-if-changed={}", opts_file.display());
println!(
"cargo:rerun-if-changed={}",
include_dir.join("lwprintf/lwprintf.h").display()
);
let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
let libc_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let mut builder = cc::Build::new();
builder
.file(&c_src)
.include(&include_dir)
.include(&manifest_dir)
.warnings(true);
let get_sys_root = |cc: &str| {
let output = Command::new(cc)
.args(["-print-sysroot"])
.output()
.expect("failed to execute process: gcc -print-sysroot");
let sysroot = core::str::from_utf8(&output.stdout).unwrap();
let sysroot = sysroot.trim_end();
format!("-I{}/include/", sysroot)
};
let sys_root = if os == "none" {
let musl_gcc = format!("{}-linux-musl-gcc", arch);
builder.flag_if_supported("-ffreestanding");
builder.flag_if_supported("-nostdlib");
builder.compiler(&musl_gcc);
let sysroot = get_sys_root(&musl_gcc);
Some(sysroot)
} else if arch == "loongarch64" && libc_env == "musl" {
let musl_gcc = format!("{}-linux-musl-gcc", arch);
let sysroot = get_sys_root(&musl_gcc);
Some(sysroot)
} else {
None
};
builder.compile("lwprintf");
sys_root
}
fn generates_bindings_to_rust(sysroot: Option<&str>) {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let header = manifest_dir.join("wrapper.h");
let include_dir = manifest_dir.join("./lwprintf/lwprintf/src/include");
let opts_dir = &manifest_dir;
println!("cargo:rerun-if-changed={}", header.display());
println!(
"cargo:rerun-if-changed={}",
include_dir.join("lwprintf.h").display()
);
let target = env::var("TARGET").unwrap();
let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
if os == "none" {
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let musl_target = format!("{}-unknown-linux-musl", arch);
unsafe {
env::set_var("TARGET", musl_target);
}
}
let mut bindings = bindgen::Builder::default()
.use_core()
.wrap_unsafe_ops(true)
.header(header.to_string_lossy())
.clang_arg(format!("-I{}", include_dir.display()))
.clang_arg(format!("-I{}", opts_dir.display()))
.layout_tests(false)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
if let Some(sysroot) = sysroot {
bindings = bindings.clang_arg(sysroot);
}
let bindings = bindings.generate().expect("Unable to generate bindings");
if os == "none" {
unsafe {
env::set_var("TARGET", target);
}
}
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("lwprintf.rs"))
.expect("Couldn't write bindings!");
}