Impl detect_targets for linux

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2022-06-06 22:32:15 +10:00
parent 69f2a56595
commit 8bd4b9b6a1
No known key found for this signature in database
GPG key ID: 591C0B03040416D6
2 changed files with 96 additions and 1 deletions

View file

@ -16,7 +16,7 @@ pub mod bins;
pub mod fetchers; pub mod fetchers;
mod target; mod target;
pub use target::TARGET; pub use target::{detect_targets, TARGET};
/// Default package path template (may be overridden in package Cargo.toml) /// Default package path template (may be overridden in package Cargo.toml)
pub const DEFAULT_PKG_URL: &str = pub const DEFAULT_PKG_URL: &str =

View file

@ -1,2 +1,97 @@
/// Compiled target triple, used as default for binary fetching /// Compiled target triple, used as default for binary fetching
pub const TARGET: &str = env!("TARGET"); pub const TARGET: &str = env!("TARGET");
/// Detect the targets supported at runtime,
/// which might be different from `TARGET` which is detected
/// at compile-time.
///
/// Return targets supported in the order of preference.
/// If target_os is linux and it support gnu, then it is preferred
/// to musl.
///
/// If target_os is mac and it is aarch64, then aarch64 is preferred
/// to x86_64.
///
/// Check [this issue](https://github.com/ryankurte/cargo-binstall/issues/155)
/// for more information.
pub async fn detect_targets() -> Vec<Box<str>> {
#[cfg(target_os = "linux")]
{
return linux::detect_targets_linux().await;
}
todo!()
}
#[cfg(target_os = "linux")]
mod linux {
use super::TARGET;
use std::process::Output;
use tokio::process::Command;
async fn detect_targets_linux() -> Vec<Box<str>> {
let abi = parse_abi();
if let Ok(Output {
status: _,
stdout,
stderr,
}) = Command::new("ldd").arg("--version").output().await
{
let libc_version = if let Some(libc_version) = parse_libc_version(stdout) {
libc_version
} else if let Some(libc_version) = parse_libc_version(stderr) {
libc_version
} else {
return vec![create_target_str("musl", abi)];
};
if libc_version == "gnu" {
return vec![
create_target_str("gnu", abi),
create_target_str("musl", abi),
];
}
}
// Fallback to using musl
vec![create_target_str("musl", abi)]
}
fn parse_libc_version(output: &[u8]) -> Option<&'static str> {
let s = String::from_utf8_lossy(output);
if s.contains("musl libc") {
Some("musl")
} else if s.contains("GLIBC") {
Some("gnu")
} else {
None
}
}
const fn parse_abi() -> &'static str {
if TARGET.endswith("abi64") {
"abi64"
} else if TARGET.endswith("eabi") {
"eabi"
} else if TARGET.endswith("eabihf") {
"eabihf"
} else if TARGET.endswith("gnu") || TARGET.endswith("musl") {
""
} else {
panic!("Unknown abi")
}
}
fn create_target_str(libc_version: &str, abi: &str) -> Box<str> {
let prefix = TARGET.rsplit_once('-').unwrap().0;
let mut target = String::with_capacity(prefix.len() + 1 + libc_version.len() + abi.len());
target.push_str(prefix);
target.push('-');
target.push_str(libc_version);
target.push_str(abi);
target.into_boxed_str()
}
}