mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-21 13:08:42 +00:00
Merge pull request #160 from NobodyXu/feature/target-detection
This commit is contained in:
commit
0c83d010b1
4 changed files with 192 additions and 2 deletions
34
Cargo.lock
generated
34
Cargo.lock
generated
|
@ -148,6 +148,7 @@ dependencies = [
|
|||
"dirs",
|
||||
"env_logger",
|
||||
"flate2",
|
||||
"guess_host_triple",
|
||||
"log",
|
||||
"miette",
|
||||
"reqwest",
|
||||
|
@ -355,6 +356,27 @@ dependencies = [
|
|||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
|
@ -509,6 +531,18 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "guess_host_triple"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b35a8ce923c7490629d84e12fa2f75e1733f1ec692a47c264f9b7fd632855afc"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"log",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.13"
|
||||
|
|
|
@ -62,6 +62,9 @@ zip = { version = "0.6.2", default-features = false, features = [ "deflate", "bz
|
|||
# Enable feature zstdmt to enable multithreading in libzstd.
|
||||
zstd = { version = "0.10.0", features = [ "bindgen", "zstdmt" ], default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
guess_host_triple = "0.1.3"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.9.0"
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ pub use helpers::*;
|
|||
pub mod bins;
|
||||
pub mod fetchers;
|
||||
|
||||
/// Compiled target triple, used as default for binary fetching
|
||||
pub const TARGET: &str = env!("TARGET");
|
||||
mod target;
|
||||
pub use target::*;
|
||||
|
||||
/// Default package path template (may be overridden in package Cargo.toml)
|
||||
pub const DEFAULT_PKG_URL: &str =
|
||||
|
|
153
src/target.rs
Normal file
153
src/target.rs
Normal file
|
@ -0,0 +1,153 @@
|
|||
use std::io::{BufRead, Cursor};
|
||||
use std::process::Output;
|
||||
use tokio::process::Command;
|
||||
|
||||
/// Compiled target triple, used as default for binary fetching
|
||||
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>> {
|
||||
if let Some(target) = get_target_from_rustc().await {
|
||||
let mut v = vec![target];
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if v[0].contains("gnu") {
|
||||
v.push(v[0].replace("gnu", "musl").into_boxed_str());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
if &*v[0] == macos::AARCH64 {
|
||||
v.push(macos::X86.into());
|
||||
}
|
||||
|
||||
v
|
||||
} else {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
linux::detect_targets_linux().await
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
macos::detect_targets_macos()
|
||||
}
|
||||
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||
{
|
||||
vec![TARGET.into()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Figure out what the host target is using `rustc`.
|
||||
/// If `rustc` is absent, then it would return `None`.
|
||||
async fn get_target_from_rustc() -> Option<Box<str>> {
|
||||
let Output { status, stdout, .. } = Command::new("rustc").arg("-vV").output().await.ok()?;
|
||||
if !status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Cursor::new(stdout)
|
||||
.lines()
|
||||
.filter_map(|line| line.ok())
|
||||
.find_map(|line| {
|
||||
line.strip_prefix("host: ")
|
||||
.map(|host| host.to_owned().into_boxed_str())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux {
|
||||
use super::{Command, Output, TARGET};
|
||||
|
||||
pub(super) 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_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 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_from_ldd_output(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
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_abi() -> &'static str {
|
||||
let last = TARGET.rsplit_once('-').unwrap().1;
|
||||
|
||||
if let Some(libc_version) = last.strip_prefix("musl") {
|
||||
libc_version
|
||||
} else if let Some(libc_version) = last.strip_prefix("gnu") {
|
||||
libc_version
|
||||
} else {
|
||||
panic!("Unrecognized libc")
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos {
|
||||
use guess_host_triple::guess_host_triple;
|
||||
|
||||
pub(super) const AARCH64: &str = "aarch64-apple-darwin";
|
||||
pub(super) const X86: &str = "x86_64-apple-darwin";
|
||||
|
||||
pub(super) fn detect_targets_macos() -> Vec<Box<str>> {
|
||||
if guess_host_triple() == Some(AARCH64) {
|
||||
vec![AARCH64.into(), X86.into()]
|
||||
} else {
|
||||
vec![X86.into()]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue