fn main() { if supported() { println!("cargo:rustc-cfg=linker"); } } #[cfg(feature = "always-supported")] fn supported() -> bool { true } #[cfg(feature = "always-fallback")] fn supported() -> bool { false } #[cfg(not(any( feature = "always-supported", feature = "always-fallback", )))] fn supported() -> bool { use std::process::Command; let dir = tempfile::tempdir().unwrap(); let test_c = dir.path().join("test.c"); let compiler = cc::Build::new() .cargo_metadata(false) .get_compiler(); let compiler_path = compiler.path(); let target = std::env::var("TARGET").unwrap(); // It might be better to #include the relevant headers and check that the // argument types are as expected. if target.contains("linux") { std::fs::write(&test_c, b" void renameat2(); void statfs(); int main() { renameat2(); statfs(); }" ).unwrap(); let status = Command::new(compiler_path) .current_dir(dir.path()) .arg("test.c") .status() .unwrap(); if status.success() { return true; } // musl doesn't expose a wrapper around the renameat2 syscall but it // does have the syscall number definition. So we're providing our own // wrapper. Although, the syscall might not exist and we'd get an error // instead of using the fallback in that case. if target.contains("musl") { cc::Build::new() .file("src/linux-musl.c") .compile("linux-musl"); return true; } } false }