pub const DEFAULT_TARGETS: &[&str] = &[
"x86_64-unknown-linux-gnu",
"x86_64-apple-darwin",
"aarch64-apple-darwin",
"x86_64-pc-windows-msvc",
"aarch64-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
];
pub fn rust_arch_to_goarch(token: &str, little_endian: bool) -> Option<&'static str> {
let mapped = match token {
"x86_64" | "amd64" => "amd64",
"aarch64" | "arm64" => "arm64",
"x86" | "i686" | "i386" | "i586" => "386",
"s390x" => "s390x",
"riscv64" | "riscv64gc" => "riscv64",
"loongarch64" | "loong64" => "loong64",
"sparcv9" | "sparc64" => "sparc64",
"powerpc64le" | "ppc64le" => "ppc64le",
"powerpc64" | "ppc64" => {
if little_endian {
"ppc64le"
} else {
"ppc64"
}
}
"mipsel" => "mipsel",
"mips64el" => "mips64el",
"mips" => {
if little_endian {
"mipsel"
} else {
"mips"
}
}
"mips64" => {
if little_endian {
"mips64el"
} else {
"mips64"
}
}
_ => return None,
};
Some(mapped)
}
pub fn map_target(triple: &str) -> (String, String) {
let os = if triple.contains("android") {
"android"
} else if triple.contains("ios") {
"ios"
} else if triple.contains("linux") {
"linux"
} else if triple.contains("darwin") || triple.contains("apple") {
"darwin"
} else if triple.contains("windows") {
"windows"
} else if triple.contains("freebsd") {
"freebsd"
} else if triple.contains("netbsd") {
"netbsd"
} else if triple.contains("openbsd") {
"openbsd"
} else if triple.contains("aix") {
"aix"
} else if triple.contains("solaris") {
"solaris"
} else if triple.contains("illumos") {
"illumos"
} else {
"unknown"
};
let arch = if triple == "darwin-universal" {
"all"
} else if triple.contains("x86_64") || triple.contains("amd64") {
"amd64"
} else if triple.contains("aarch64") || triple.contains("arm64") {
"arm64"
} else {
let first = triple.split('-').next().unwrap_or("unknown");
match first {
"armv7" | "armv7l" => "armv7",
"armv6" | "armv6l" | "arm" => "armv6",
other => rust_arch_to_goarch(other, false).unwrap_or(other),
}
};
(os.to_string(), arch.to_string())
}
pub fn libc_from_target(triple: &str) -> &'static str {
if triple.contains("musl") {
"musl"
} else if triple.contains("gnu") {
"gnu"
} else {
""
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownDebianArch {
pub input: String,
}
impl std::fmt::Display for UnknownDebianArch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"no Debian (dpkg) architecture name is known for target '{}' \
— set an explicit `deb_architecture:` override on the Artifactory \
entry (e.g. `deb_architecture: \"amd64\"`) to name the repository \
slice for this build",
self.input
)
}
}
impl std::error::Error for UnknownDebianArch {}
pub fn debian_arch_from_target(triple: &str) -> Result<String, UnknownDebianArch> {
let (_, arch) = map_target(triple);
debian_arch_from_arch(&arch)
.map(str::to_string)
.ok_or_else(|| UnknownDebianArch {
input: triple.to_string(),
})
}
pub fn debian_arch_from_arch(arch: &str) -> Option<&'static str> {
let mapped = match arch {
"amd64" => "amd64",
"arm64" => "arm64",
"386" => "i386",
"armv7" => "armhf",
"armv6" => "armel",
"ppc64le" => "ppc64el",
"ppc64" => "ppc64",
"s390x" => "s390x",
"riscv64" => "riscv64",
"mips64" => "mips64",
"mips64el" => "mips64el",
"mips" => "mips",
"mipsel" => "mipsel",
"sparc64" => "sparc64",
"loong64" => "loong64",
_ => return None,
};
Some(mapped)
}
pub fn is_darwin(triple: &str) -> bool {
triple.contains("darwin") || triple.contains("apple")
}
pub fn is_macos(triple: &str) -> bool {
triple.contains("darwin")
}
pub fn is_linux(triple: &str) -> bool {
triple.contains("linux") && !triple.contains("android")
}
pub fn is_windows(triple: &str) -> bool {
triple.contains("windows")
}
pub fn is_windows_msvc(triple: &str) -> bool {
triple.contains("windows-msvc")
}
pub fn is_ios(triple: &str) -> bool {
triple.contains("ios")
}
pub fn is_aix(triple: &str) -> bool {
triple.contains("aix")
}
pub fn is_nfpm_target(triple: &str) -> bool {
is_linux(triple) || is_ios(triple) || triple.contains("android") || is_aix(triple)
}
pub fn os_arch_with_default(target: Option<&str>, default_os: &str) -> (String, String) {
target
.map(map_target)
.unwrap_or_else(|| (default_os.to_string(), "amd64".to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_target_to_os_arch() {
let (os, arch) = map_target("x86_64-unknown-linux-gnu");
assert_eq!(os, "linux");
assert_eq!(arch, "amd64");
}
#[test]
fn test_darwin_arm64() {
let (os, arch) = map_target("aarch64-apple-darwin");
assert_eq!(os, "darwin");
assert_eq!(arch, "arm64");
}
#[test]
fn test_windows() {
let (os, arch) = map_target("x86_64-pc-windows-msvc");
assert_eq!(os, "windows");
assert_eq!(arch, "amd64");
}
#[test]
fn test_is_macos_excludes_apple_non_macos() {
assert!(is_macos("x86_64-apple-darwin"));
assert!(is_macos("aarch64-apple-darwin"));
assert!(is_macos("darwin-universal"));
for t in [
"aarch64-apple-ios",
"aarch64-apple-tvos",
"aarch64-apple-watchos",
] {
assert!(is_darwin(t), "{t} is a broad apple/darwin target");
assert!(
!is_macos(t),
"{t} must NOT be macOS — no brew-installable binary"
);
}
assert!(!is_macos("x86_64-unknown-linux-gnu"));
assert!(!is_macos("x86_64-pc-windows-msvc"));
}
#[test]
fn test_is_windows_msvc() {
assert!(is_windows_msvc("x86_64-pc-windows-msvc"));
assert!(is_windows_msvc("aarch64-pc-windows-msvc"));
assert!(!is_windows_msvc("x86_64-pc-windows-gnu"));
assert!(!is_windows_msvc("x86_64-unknown-linux-gnu"));
assert!(!is_windows_msvc("aarch64-apple-darwin"));
}
#[test]
fn test_riscv64() {
let (os, arch) = map_target("riscv64gc-unknown-linux-gnu");
assert_eq!(os, "linux");
assert_eq!(arch, "riscv64");
}
#[test]
fn test_i686() {
let (os, arch) = map_target("i686-unknown-linux-gnu");
assert_eq!(os, "linux");
assert_eq!(arch, "386");
}
#[test]
fn test_armv7() {
let (os, arch) = map_target("armv7-unknown-linux-gnueabihf");
assert_eq!(os, "linux");
assert_eq!(arch, "armv7");
}
#[test]
fn test_freebsd() {
let (os, arch) = map_target("x86_64-unknown-freebsd");
assert_eq!(os, "freebsd");
assert_eq!(arch, "amd64");
}
#[test]
fn test_s390x() {
let (os, arch) = map_target("s390x-unknown-linux-gnu");
assert_eq!(os, "linux");
assert_eq!(arch, "s390x");
}
#[test]
fn test_ppc64le() {
let (os, arch) = map_target("powerpc64le-unknown-linux-gnu");
assert_eq!(os, "linux");
assert_eq!(arch, "ppc64le");
}
#[test]
fn test_android() {
let (os, arch) = map_target("aarch64-linux-android");
assert_eq!(os, "android");
assert_eq!(arch, "arm64");
}
#[test]
fn test_linux_musl() {
let (os, arch) = map_target("aarch64-unknown-linux-musl");
assert_eq!(os, "linux");
assert_eq!(arch, "arm64");
}
#[test]
fn test_unknown_target() {
let (os, arch) = map_target("wasm32-unknown-unknown");
assert_eq!(os, "unknown");
assert_eq!(arch, "wasm32");
}
#[test]
fn test_ios() {
let (os, arch) = map_target("aarch64-apple-ios");
assert_eq!(os, "ios");
assert_eq!(arch, "arm64");
}
#[test]
fn test_aix() {
let (os, arch) = map_target("powerpc64-ibm-aix");
assert_eq!(os, "aix");
assert_eq!(arch, "ppc64");
}
#[test]
fn test_solaris_sparcv9() {
let (os, arch) = map_target("sparcv9-sun-solaris");
assert_eq!(os, "solaris");
assert_eq!(arch, "sparc64");
}
#[test]
fn test_sparc64_linux() {
let (os, arch) = map_target("sparc64-unknown-linux-gnu");
assert_eq!(os, "linux");
assert_eq!(arch, "sparc64");
}
#[test]
fn test_illumos() {
let (os, arch) = map_target("x86_64-unknown-illumos");
assert_eq!(os, "illumos");
assert_eq!(arch, "amd64");
}
#[test]
fn test_goarch_table_agrees_with_map_target_on_every_token() {
let tokens = [
"x86_64",
"amd64",
"aarch64",
"arm64",
"i686",
"i386",
"i586",
"s390x",
"riscv64",
"riscv64gc",
"loongarch64",
"loong64",
"sparcv9",
"sparc64",
"powerpc64",
"ppc64",
"powerpc64le",
"ppc64le",
"mips",
"mipsel",
"mips64",
"mips64el",
];
for token in tokens {
let expected = rust_arch_to_goarch(token, false)
.unwrap_or_else(|| panic!("table must cover {token}"));
let (_, arch) = map_target(&format!("{token}-unknown-linux-gnu"));
assert_eq!(
arch, expected,
"map_target and rust_arch_to_goarch must agree on '{token}'"
);
}
}
#[test]
fn test_goarch_endian_disambiguation() {
assert_eq!(rust_arch_to_goarch("powerpc64", true), Some("ppc64le"));
assert_eq!(rust_arch_to_goarch("powerpc64", false), Some("ppc64"));
assert_eq!(rust_arch_to_goarch("mips64", true), Some("mips64el"));
assert_eq!(rust_arch_to_goarch("mips64", false), Some("mips64"));
assert_eq!(rust_arch_to_goarch("mips", true), Some("mipsel"));
assert_eq!(rust_arch_to_goarch("powerpc64le", false), Some("ppc64le"));
assert_eq!(rust_arch_to_goarch("mips64el", false), Some("mips64el"));
}
#[test]
fn test_goarch_table_excludes_arm_and_unknowns() {
assert_eq!(rust_arch_to_goarch("arm", true), None);
assert_eq!(rust_arch_to_goarch("armv7", false), None);
assert_eq!(rust_arch_to_goarch("wasm32", false), None);
assert_eq!(rust_arch_to_goarch("frob", false), None);
}
#[test]
fn test_libc_from_target() {
assert_eq!(libc_from_target("x86_64-unknown-linux-musl"), "musl");
assert_eq!(libc_from_target("aarch64-unknown-linux-musl"), "musl");
assert_eq!(libc_from_target("x86_64-unknown-linux-gnu"), "gnu");
assert_eq!(libc_from_target("armv7-unknown-linux-gnueabihf"), "gnu");
assert_eq!(libc_from_target("x86_64-apple-darwin"), "");
assert_eq!(libc_from_target("x86_64-pc-windows-msvc"), "");
assert_eq!(libc_from_target("x86_64-pc-windows-gnu"), "gnu");
}
#[test]
fn test_debian_arch_from_target() {
assert_eq!(
debian_arch_from_target("x86_64-unknown-linux-gnu").unwrap(),
"amd64"
);
assert_eq!(
debian_arch_from_target("aarch64-unknown-linux-gnu").unwrap(),
"arm64"
);
assert_eq!(
debian_arch_from_target("armv7-unknown-linux-gnueabihf").unwrap(),
"armhf"
);
assert_eq!(
debian_arch_from_target("i686-unknown-linux-gnu").unwrap(),
"i386"
);
assert_eq!(
debian_arch_from_target("arm-unknown-linux-gnueabi").unwrap(),
"armel"
);
assert_eq!(
debian_arch_from_target("powerpc64le-unknown-linux-gnu").unwrap(),
"ppc64el"
);
assert_eq!(
debian_arch_from_target("s390x-unknown-linux-gnu").unwrap(),
"s390x"
);
assert_eq!(
debian_arch_from_target("riscv64gc-unknown-linux-gnu").unwrap(),
"riscv64"
);
assert_eq!(
debian_arch_from_target("loongarch64-unknown-linux-gnu").unwrap(),
"loong64"
);
}
#[test]
fn test_debian_arch_unmapped_triple_hard_errors() {
for bad in [
"frob-unknown-linux-gnu",
"wasm32-unknown-unknown",
"darwin-universal",
] {
let err = debian_arch_from_target(bad).expect_err(&format!("'{bad}' must be rejected"));
assert_eq!(err.input, bad, "error carries the offending triple");
let msg = err.to_string();
assert!(msg.contains(bad), "message quotes the bad triple: {msg}");
assert!(
msg.contains("deb_architecture"),
"message names the override field as the fix: {msg}"
);
}
}
#[test]
fn test_is_nfpm_target() {
assert!(is_nfpm_target("x86_64-unknown-linux-gnu"));
assert!(is_nfpm_target("aarch64-linux-android"));
assert!(is_nfpm_target("aarch64-apple-ios"));
assert!(is_nfpm_target("powerpc64-ibm-aix"));
assert!(!is_nfpm_target("x86_64-apple-darwin"));
assert!(!is_nfpm_target("x86_64-pc-windows-msvc"));
assert!(!is_nfpm_target("x86_64-unknown-freebsd"));
}
}