use super::common::CommandExt;
use std::process::Command;
#[derive(Debug, PartialEq, Eq)]
struct RustCfg {
target_arch: Option<String>,
}
fn parse_rust_cfg(cfg: String) -> RustCfg {
let target_line = "target_arch=\"";
let mut target_arch = None;
for line in cfg.split('\n') {
if line.starts_with(target_line) {
let len = target_line.len();
let arch = line.chars().skip(len).take(line.len() - len - 1).collect();
target_arch.replace(arch);
}
}
RustCfg { target_arch }
}
pub fn target_triple() -> Result<String, crate::Error> {
let arch_res = Command::new("rustc").args(["--print", "cfg"]).output_ok();
let arch = match arch_res {
Ok(output) => parse_rust_cfg(String::from_utf8_lossy(&output.stdout).into())
.target_arch
.expect("could not find `target_arch` when running `rustc --print cfg`."),
Err(err) => {
log::warn!(
"failed to determine target arch using rustc, error: `{}`. The fallback is the architecture of the machine that compiled this crate.",
err,
);
if cfg!(target_arch = "x86") {
"i686".into()
} else if cfg!(target_arch = "x86_64") {
"x86_64".into()
} else if cfg!(target_arch = "arm") {
"armv7".into()
} else if cfg!(target_arch = "aarch64") {
"aarch64".into()
} else {
return Err(crate::Error::ArchError(String::from(
"Unable to determine target-architecture",
)));
}
}
};
let os = if cfg!(target_os = "linux") {
"unknown-linux"
} else if cfg!(target_os = "macos") {
"apple-darwin"
} else if cfg!(target_os = "windows") {
"pc-windows"
} else if cfg!(target_os = "freebsd") {
"unknown-freebsd"
} else {
return Err(crate::Error::ArchError(String::from(
"Unable to determine target-os",
)));
};
let os = if cfg!(target_os = "macos") || cfg!(target_os = "freebsd") {
String::from(os)
} else {
let env = if cfg!(target_env = "gnu") {
"gnu"
} else if cfg!(target_env = "musl") {
"musl"
} else if cfg!(target_env = "msvc") {
"msvc"
} else {
return Err(crate::Error::ArchError(String::from(
"Unable to determine target-environment",
)));
};
format!("{os}-{env}")
};
Ok(format!("{arch}-{os}"))
}
#[cfg(test)]
mod tests {
use super::RustCfg;
#[test]
fn parse_rust_cfg() {
assert_eq!(
super::parse_rust_cfg("target_arch".into()),
RustCfg { target_arch: None }
);
assert_eq!(
super::parse_rust_cfg(
r#"debug_assertions
target_arch="aarch64"
target_endian="little"
target_env=""
target_family="unix"
target_os="macos"
target_pointer_width="64"
target_vendor="apple"
unix"#
.into()
),
RustCfg {
target_arch: Some("aarch64".into())
}
);
}
}