use std::{
borrow::Cow,
env,
ffi::OsStr,
process::{Output, Stdio},
};
use cfg_if::cfg_if;
use tokio::process::Command;
#[cfg(feature = "tracing")]
use tracing::debug;
cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
mod linux;
} else if #[cfg(target_os = "macos")] {
mod macos;
} else if #[cfg(target_os = "windows")] {
mod windows;
}
}
pub async fn detect_targets() -> Vec<String> {
let target = get_target_from_rustc().await;
#[cfg(feature = "tracing")]
debug!("get_target_from_rustc()={target:?}");
let target = target.unwrap_or_else(|| {
let target = guess_host_triple::guess_host_triple();
#[cfg(feature = "tracing")]
debug!("guess_host_triple::guess_host_triple()={target:?}");
target.unwrap_or(crate::TARGET).to_string()
});
cfg_if! {
if #[cfg(target_os = "macos")] {
let mut targets = vec![target];
targets.extend(macos::detect_alternative_targets(&targets[0]).await);
targets
} else if #[cfg(target_os = "windows")] {
let mut targets = vec![target];
targets.extend(windows::detect_alternative_targets(&targets[0]));
targets
} else if #[cfg(any(target_os = "linux", target_os = "android"))] {
linux::detect_targets(target).await
} else {
vec![target]
}
}
}
async fn get_target_from_rustc() -> Option<String> {
let cmd = env::var_os("CARGO")
.map(Cow::Owned)
.unwrap_or_else(|| Cow::Borrowed(OsStr::new("rustc")));
let Output { status, stdout, .. } = Command::new(cmd)
.arg("-vV")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
.ok()?
.wait_with_output()
.await
.ok()?;
if !status.success() {
return None;
}
let stdout = String::from_utf8_lossy(&stdout);
let target = stdout
.lines()
.find_map(|line| line.strip_prefix("host: "))?;
let mut parts: Vec<&str> = target.splitn(4, '-').collect();
if *parts.get(2)? == "linux" {
parts[1] = "unknown";
}
Some(parts.join("-"))
}