use cc::Build;
use std::{
env,
error::Error,
io::{self, ErrorKind::InvalidData},
process::Command,
str,
};
fn linux_has_getrandom() -> bool {
let glibc_version = || -> Result<(u8, u8), Box<dyn Error>> {
let lld_result = Command::new("ldd").arg("--version").output()?;
let output = String::from_utf8(lld_result.stdout)?;
let (major, minor) = output
.lines()
.find_map(|line| line.strip_prefix("ldd (GNU libc) "))
.and_then(|version| version.split_once('.'))
.ok_or_else(|| io::Error::from(InvalidData))?;
let major_minor = (major.parse()?, minor.parse()?);
Ok(major_minor)
};
glibc_version()
.map(|major_minor| matches!(major_minor, (2..=255, 25..=255)))
.map_err(|e| eprintln!("Failed to get glibc version: {e}"))
.unwrap_or(false)
}
fn select_random() -> &'static str {
let os = env::var("CARGO_CFG_TARGET_OS").expect("Cannot determine target architecture");
let flavour = env::var("CARGO_CFG_TARGET_ENV").expect("Cannot determine target environment");
match (os.as_str(), flavour.as_str()) {
("macos" | "ios", _) => {
println!("cargo:rustc-link-lib=framework=Security");
"librandom/secrandomcopybytes.c"
}
("freebsd" | "openbsd" | "netbsd", _) => "librandom/arc4random.c",
("linux", "gnu") if linux_has_getrandom() => "librandom/getrandom.c",
("linux", _) => "librandom/urandom.c",
("windows", _) => "librandom/cryptgenrandom.c",
(os, flavour) => panic!("Unsupported target OS: {os}-{flavour}"),
}
}
fn main() {
let provider = select_random();
eprintln!("Selected provider: {provider}");
Build::new().file(provider).warnings_into_errors(true).compile("helpers");
}