From 42672ccf4005cc5ef353d3f867d1703228b4fbca Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Wed, 4 Jan 2023 12:32:13 +1100 Subject: [PATCH] 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 --- crates/detect-targets/Cargo.toml | 2 - crates/detect-targets/src/detect.rs | 2 + crates/detect-targets/src/detect/linux.rs | 101 ++++++++++------------ 3 files changed, 47 insertions(+), 58 deletions(-) diff --git a/crates/detect-targets/Cargo.toml b/crates/detect-targets/Cargo.toml index a3469b29..529f6805 100644 --- a/crates/detect-targets/Cargo.toml +++ b/crates/detect-targets/Cargo.toml @@ -12,8 +12,6 @@ license = "Apache-2.0 OR MIT" [dependencies] tokio = { version = "1.23.0", features = ["rt", "process", "sync"], default-features = false } cfg-if = "1.0.0" - -[target.'cfg(not(target_os = "linux"))'.dependencies] guess_host_triple = "0.1.3" [dev-dependencies] diff --git a/crates/detect-targets/src/detect.rs b/crates/detect-targets/src/detect.rs index 4c1877fe..2ef978c8 100644 --- a/crates/detect-targets/src/detect.rs +++ b/crates/detect-targets/src/detect.rs @@ -42,6 +42,8 @@ pub async fn detect_targets() -> Vec { if targets[0].contains("gnu") { targets.push(targets[0].replace("gnu", "musl")); + } else if targets[0].contains("android") { + targets.push(targets[0].replace("android", "musl")); } targets diff --git a/crates/detect-targets/src/detect/linux.rs b/crates/detect-targets/src/detect/linux.rs index ebe635a6..bedbc775 100644 --- a/crates/detect-targets/src/detect/linux.rs +++ b/crates/detect-targets/src/detect/linux.rs @@ -2,43 +2,58 @@ use crate::TARGET; use std::process::{Output, Stdio}; +use guess_host_triple::guess_host_triple; use tokio::process::Command; pub(super) async fn detect_targets_linux() -> Vec { - let (abi, libc) = parse_abi_and_libc(); + let target = guess_host_triple().unwrap_or(TARGET); - if let Libc::Glibc = libc { - // Glibc can only be dynamically linked. - // If we can run this binary, then it means that the target - // supports both glibc and musl. - return create_targets_str(&["gnu", "musl"], abi); + let (prefix, postfix) = target + .rsplit_once('-') + .expect("unwrap: target always has a -"); + + 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 { - status: _, - stdout, - stderr, - }) = Command::new("ldd") +async fn supports_gnu() -> bool { + Command::new("ldd") .arg("--version") .stdin(Stdio::null()) .output() .await - { - let libc_version = if let Some(libc_version) = parse_libc_version_from_ldd_output(&stdout) { - libc_version - } else if let Some(libc_version) = parse_libc_version_from_ldd_output(&stderr) { - libc_version - } else { - 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)] + .ok() + .and_then(|Output { stdout, stderr, .. }| { + parse_libc_version_from_ldd_output(&stdout) + .or_else(|| parse_libc_version_from_ldd_output(&stderr)) + }) + == Some("gnu") } 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 { - Glibc, + Gnu, Musl, -} - -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 { - libc_versions - .iter() - .map(|libc_version| create_target_str(libc_version, abi)) - .collect() + Android, + Unknown, }