Fix detect_targets_linux: Detect arch/libc at runtime using guess_host_triple (#649)

- Enable `guess_host_triple` on all targets
 - Fix `detect_targets_linux`: Detect runtime arch/libc using
   `guess_host_triple` instead of using the one specified in `TARGET`.
 - Add support for android in `detect_targets`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-01-04 12:32:13 +11:00 committed by GitHub
parent 49f60d37fe
commit 42672ccf40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 58 deletions

View file

@ -12,8 +12,6 @@ license = "Apache-2.0 OR MIT"
[dependencies] [dependencies]
tokio = { version = "1.23.0", features = ["rt", "process", "sync"], default-features = false } tokio = { version = "1.23.0", features = ["rt", "process", "sync"], default-features = false }
cfg-if = "1.0.0" cfg-if = "1.0.0"
[target.'cfg(not(target_os = "linux"))'.dependencies]
guess_host_triple = "0.1.3" guess_host_triple = "0.1.3"
[dev-dependencies] [dev-dependencies]

View file

@ -42,6 +42,8 @@ pub async fn detect_targets() -> Vec<String> {
if targets[0].contains("gnu") { if targets[0].contains("gnu") {
targets.push(targets[0].replace("gnu", "musl")); targets.push(targets[0].replace("gnu", "musl"));
} else if targets[0].contains("android") {
targets.push(targets[0].replace("android", "musl"));
} }
targets targets

View file

@ -2,43 +2,58 @@ use crate::TARGET;
use std::process::{Output, Stdio}; use std::process::{Output, Stdio};
use guess_host_triple::guess_host_triple;
use tokio::process::Command; use tokio::process::Command;
pub(super) async fn detect_targets_linux() -> Vec<String> { pub(super) async fn detect_targets_linux() -> Vec<String> {
let (abi, libc) = parse_abi_and_libc(); let target = guess_host_triple().unwrap_or(TARGET);
if let Libc::Glibc = libc { let (prefix, postfix) = target
// Glibc can only be dynamically linked. .rsplit_once('-')
// If we can run this binary, then it means that the target .expect("unwrap: target always has a -");
// supports both glibc and musl.
return create_targets_str(&["gnu", "musl"], abi); let (abi, libc) = if let Some(abi) = postfix.strip_prefix("musl") {
(abi, Libc::Musl)
} else if let Some(abi) = postfix.strip_prefix("gnu") {
(abi, Libc::Gnu)
} else if let Some(abi) = postfix.strip_prefix("android") {
(abi, Libc::Android)
} else {
(postfix, Libc::Unknown)
};
let musl_fallback_target = || format!("{prefix}-{}{abi}", "musl");
match libc {
Libc::Gnu => {
// guess_host_triple cannot detect whether the system is using glibc,
// musl libc or other libc.
//
// As such, we need to launch the test ourselves.
if supports_gnu().await {
vec![target.to_string(), musl_fallback_target()]
} else {
vec![musl_fallback_target()]
}
}
Libc::Android => vec![target.to_string(), musl_fallback_target()],
_ => vec![target.to_string()],
} }
}
if let Ok(Output { async fn supports_gnu() -> bool {
status: _, Command::new("ldd")
stdout,
stderr,
}) = Command::new("ldd")
.arg("--version") .arg("--version")
.stdin(Stdio::null()) .stdin(Stdio::null())
.output() .output()
.await .await
{ .ok()
let libc_version = if let Some(libc_version) = parse_libc_version_from_ldd_output(&stdout) { .and_then(|Output { stdout, stderr, .. }| {
libc_version parse_libc_version_from_ldd_output(&stdout)
} else if let Some(libc_version) = parse_libc_version_from_ldd_output(&stderr) { .or_else(|| parse_libc_version_from_ldd_output(&stderr))
libc_version })
} else { == Some("gnu")
return vec![create_target_str("musl", abi)];
};
if libc_version == "gnu" {
return create_targets_str(&["gnu", "musl"], abi);
}
}
// Fallback to using musl
vec![create_target_str("musl", abi)]
} }
fn parse_libc_version_from_ldd_output(output: &[u8]) -> Option<&'static str> { fn parse_libc_version_from_ldd_output(output: &[u8]) -> Option<&'static str> {
@ -53,34 +68,8 @@ fn parse_libc_version_from_ldd_output(output: &[u8]) -> Option<&'static str> {
} }
enum Libc { enum Libc {
Glibc, Gnu,
Musl, Musl,
} Android,
Unknown,
fn parse_abi_and_libc() -> (&'static str, Libc) {
let last = TARGET.rsplit_once('-').unwrap().1;
if let Some(libc_version) = last.strip_prefix("musl") {
(libc_version, Libc::Musl)
} else if let Some(libc_version) = last.strip_prefix("gnu") {
(libc_version, Libc::Glibc)
} else {
panic!("Unrecognized libc")
}
}
fn create_target_str(libc_version: &str, abi: &str) -> String {
let prefix = TARGET
.rsplit_once('-')
.expect("unwrap: TARGET always has a -")
.0;
format!("{prefix}-{libc_version}{abi}")
}
fn create_targets_str(libc_versions: &[&str], abi: &str) -> Vec<String> {
libc_versions
.iter()
.map(|libc_version| create_target_str(libc_version, abi))
.collect()
} }