#[cfg(any(feature = "linux-backport", feature = "windows"))]
extern crate cc;
#[cfg(any(feature = "linux-backport", feature = "windows"))]
extern crate semver;
fn main() {
#[cfg(all(feature = "linux-backport", target_os = "linux"))]
linux::build_explicit_bzero_backport();
#[cfg(all(feature = "windows", target_os = "windows"))]
windows::build_explicit_bzero_shim();
}
#[cfg(all(feature = "linux-backport", target_os = "linux"))]
mod linux {
use super::cc;
use super::semver::Version;
use std::process::Command;
const GLIBC_WITH_EXPLICIT_BZERO: &str = "2.25.0";
const MUSL_WITH_EXPLICIT_BZERO: &str = "1.1.20";
struct LddVersion {
success: bool,
stdout: String,
stderr: String,
}
enum StdLibrary {
GNU(Version),
Musl(Version),
Unsupported,
}
impl StdLibrary {
fn should_build_explicit_bzero(&self) -> Option<bool> {
match self {
StdLibrary::GNU(ver) => {
Some(ver < &Version::parse(GLIBC_WITH_EXPLICIT_BZERO).unwrap())
}
StdLibrary::Musl(ver) => {
Some(ver < &Version::parse(MUSL_WITH_EXPLICIT_BZERO).unwrap())
}
StdLibrary::Unsupported => None,
}
}
}
impl LddVersion {
fn new() -> Self {
let output = Command::new("/usr/bin/ldd")
.arg("--version")
.output()
.unwrap();
Self {
success: output.status.success(),
stdout: String::from_utf8(output.stdout).unwrap(),
stderr: String::from_utf8(output.stderr).unwrap(),
}
}
fn resolve(&self) -> StdLibrary {
let stdout = self.stdout.to_ascii_lowercase();
let stderr = self.stderr.to_ascii_lowercase();
for glibc_str in &["glibc", "gnu libc"] {
if stdout.find(glibc_str).is_some() || stderr.find(glibc_str).is_some() {
return self.get_glibc_version();
}
}
if stdout.find("musl").is_some() || stderr.find("musl").is_some() {
return self.get_musl_version();
}
StdLibrary::Unsupported
}
fn get_glibc_version(&self) -> StdLibrary {
if !self.success {
panic!(
"/usr/bin/ldd --version exited with error: {:?}",
self.stderr
);
}
let info = self.stdout.split('\n').next().unwrap();
let version =
Version::parse(&(info.split(' ').last().unwrap().to_owned() + ".0")).unwrap();
StdLibrary::GNU(version)
}
fn get_musl_version(&self) -> StdLibrary {
let info = self.stderr.split('\n').collect::<Vec<&str>>()[1];
let version = Version::parse(info.split(' ').collect::<Vec<&str>>()[1]).unwrap();
StdLibrary::Musl(version)
}
}
pub fn build_explicit_bzero_backport() {
let ldd_version = LddVersion::new();
let stdlib = ldd_version.resolve();
match stdlib.should_build_explicit_bzero() {
Some(should_build) => if should_build {
cc::Build::new()
.file("src/os/linux/explicit_bzero_backport.c")
.compile("explicit_bzero");
},
None => panic!("unsupported standard library"),
}
}
}
#[cfg(all(feature = "windows", target_os = "windows"))]
mod windows {
use super::cc;
pub fn build_explicit_bzero_shim() {
cc::Build::new()
.file("src/os/windows/explicit_bzero_shim.c")
.compile("explicit_bzero");
}
}