use std::borrow::Cow;
use std::env;
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
fn main() {
let target =
env::var("TARGET").expect("selinux-sys: Environment variable 'TARGET' was not defined.");
match get_target_os(&target) {
None => return,
Some("android") | Some("androideabi") | Some("darwin") | Some("dragonfly")
| Some("freebsd") | Some("hurd") | Some("linux") | Some("netbsd") | Some("openbsd") => {
}
_ => return, }
let out_dir = env::var_os("OUT_DIR")
.map(PathBuf::from)
.expect("fts-sys: Environment variable 'OUT_DIR' was not defined.");
println!("cargo:root={}", out_dir.to_str().unwrap());
let sysroot = target_env_var_os("SYSROOT", &target).map(PathBuf::from);
generate_bindings(&target, sysroot.as_deref(), &out_dir)
}
fn target_env_var_os(name: &str, target: &str) -> Option<OsString> {
rerun_if_env_changed(name, target);
let target_underscores = target.replace('-', "_");
env::var_os(format!("{name}_{target}"))
.or_else(|| env::var_os(format!("{name}_{target_underscores}")))
.or_else(|| env::var_os(format!("TARGET_{name}")))
.or_else(|| env::var_os(name))
}
fn rerun_if_env_changed(name: &str, target: &str) {
let target_underscores = target.replace('-', "_");
println!("cargo:rerun-if-env-changed={name}_{target}");
println!("cargo:rerun-if-env-changed={name}_{target_underscores}");
println!("cargo:rerun-if-env-changed=TARGET_{name}");
println!("cargo:rerun-if-env-changed={name}");
}
fn get_target_os(target: &str) -> Option<&str> {
let components: Vec<_> = target.split('-').collect();
let os_index = match components.len() {
2 => {
if components[1] == "none" {
return None; }
1
}
3 | 4 => {
if components[1] == "none" || components[2] == "none" {
return None; }
2
}
_ => panic!("Unrecognized target triplet '{target}'"),
};
Some(components[os_index])
}
fn translate_rustc_target_to_clang(rustc_target: &str) -> Cow<'_, str> {
if let Some(suffix) = rustc_target.strip_prefix("riscv32") {
let suffix = suffix.trim_start_matches(|c| c != '-');
Cow::Owned(format!("riscv32{suffix}"))
} else if let Some(suffix) = rustc_target.strip_prefix("riscv64") {
let suffix = suffix.trim_start_matches(|c| c != '-');
Cow::Owned(format!("riscv64{suffix}"))
} else if let Some(suffix) = rustc_target.strip_prefix("aarch64-apple-") {
Cow::Owned(format!("arm64-apple-{suffix}"))
} else if let Some(prefix) = rustc_target.strip_suffix("-espidf") {
Cow::Owned(format!("{prefix}-elf"))
} else {
Cow::Borrowed(rustc_target)
}
}
fn generate_bindings(target: &str, sysroot: Option<&Path>, out_dir: &Path) {
let clang_target = translate_rustc_target_to_clang(target);
let mut builder = bindgen::Builder::default()
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.default_enum_style(bindgen::EnumVariation::ModuleConsts)
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
.size_t_is_usize(true)
.derive_debug(true)
.derive_copy(true)
.impl_debug(true)
.clang_arg(format!("--target={clang_target}"));
if let Some(sysroot) = sysroot.map(Path::as_os_str).map(OsStr::to_str) {
let sysroot = sysroot.expect("SYSROOT is not encoded in UTF-8");
builder = builder.clang_arg(format!("--sysroot={sysroot}"));
}
builder = builder
.allowlist_function("fts_(open|read|children|set|close)")
.allowlist_type("FTSENT")
.blocklist_type("(FTS|stat|timespec|dev_t|ino_t|nlink_t)")
.allowlist_var("FTS_.+")
.header("src/fts-sys.h");
let bindings = builder
.generate()
.expect("fts-sys: Failed to generate Rust bindings for 'fts.h'.");
bindings
.write_to_file(out_dir.join("fts-sys.rs"))
.expect("fts-sys: Failed to write 'fts-sys.rs'.")
}