use std::env;
use std::path::Path;
pub(crate) fn generate_rust_binding(in_h_path: &Path, out_rs_path: &Path) {
let c_header_path = in_h_path.display().to_string();
let cargo_cfg = bindgen::CargoCallbacks::new().rerun_on_header_files(false);
let builder = bindgen::Builder::default()
.header(c_header_path)
.parse_callbacks(Box::new(cargo_cfg))
.prepend_enum_name(false)
.blocklist_type("max_align_t");
std::fs::create_dir_all(
out_rs_path
.parent()
.expect("bindgen output file has parent dir"),
)
.expect("create bindgen output dir");
let bindings = configure_platform_specific(builder)
.generate()
.unwrap_or_else(|err| {
panic!(
"bindgen generate failed\n c: {}\n rs: {}\n err: {}\n",
in_h_path.display(),
out_rs_path.display(),
err
)
});
bindings.write_to_file(out_rs_path).unwrap_or_else(|err| {
panic!(
"bindgen write failed\n c: {}\n rs: {}\n err: {}\n",
in_h_path.display(),
out_rs_path.display(),
err
)
});
}
fn configure_platform_specific(builder: bindgen::Builder) -> bindgen::Builder {
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
if target_vendor == "apple" {
eprintln!("Build selected for macOS.");
let path = env::var("LLVM_PATH").expect("env var 'LLVM_PATH' not set");
builder
.clang_arg("-I")
.clang_arg(apple_include_path().expect("apple include path"))
.clang_arg("-L")
.clang_arg(format!("{path}/lib"))
.clang_arg("-Wl,-flat_namespace,-undefined,dynamic_lookup")
} else {
eprintln!("Build selected for Linux/Windows.");
builder
}
}
fn apple_include_path() -> Result<String, std::io::Error> {
use std::process::Command;
let target = std::env::var("TARGET").unwrap();
let platform = if target.contains("apple-darwin") {
"macosx"
} else if target == "x86_64-apple-ios" || target == "aarch64-apple-ios-sim" {
"iphonesimulator"
} else if target == "aarch64-apple-ios" {
"iphoneos"
} else {
panic!("not building for macOS or iOS");
};
let output = Command::new("xcrun")
.args(["--sdk", platform, "--show-sdk-path"])
.output()?
.stdout;
let prefix = std::str::from_utf8(&output)
.expect("invalid output from `xcrun`")
.trim_end();
let suffix = "usr/include";
let directory = format!("{prefix}/{suffix}");
Ok(directory)
}