1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
use indoc::{formatdoc, indoc};
use std::env::consts;
use std::ffi::OsString;
use which::which;
/// Provides assistance for cross-compiling from the user's host platform to the desired target platform.
///
/// This function will not install required toolchains, linkers or compilers automatically. It will
/// look for the required tools and returns a human-readable help text if they can't be found or
/// any other issue has been detected.
pub fn cross_compile_assistance(target_triple: impl AsRef<str>) -> CrossCompileAssistance {
let target_triple = target_triple.as_ref();
let (gcc_binary_name, help_text) = match (target_triple, consts::OS, consts::ARCH) {
(AARCH64_UNKNOWN_LINUX_MUSL, OS_LINUX, ARCH_X86_64) => (
"aarch64-linux-gnu-gcc",
indoc! {"
To install an aarch64 cross-compiler on Ubuntu:
sudo apt-get install g++-aarch64-linux-gnu libc6-dev-arm64-cross musl-tools
"},
),
(AARCH64_UNKNOWN_LINUX_MUSL, OS_MACOS, ARCH_X86_64 | ARCH_AARCH64) => (
"aarch64-unknown-linux-musl-gcc",
indoc! {"
To install an aarch64 cross-compiler on macOS:
brew install messense/macos-cross-toolchains/aarch64-unknown-linux-musl
"},
),
(AARCH64_UNKNOWN_LINUX_MUSL, OS_LINUX, ARCH_AARCH64)
| (X86_64_UNKNOWN_LINUX_MUSL, OS_LINUX, ARCH_X86_64) => (
"musl-gcc",
indoc! {"
To install musl-tools on Ubuntu:
sudo apt-get install musl-tools
"},
),
(X86_64_UNKNOWN_LINUX_MUSL, OS_LINUX, ARCH_AARCH64) => (
"x86_64-linux-gnu-gcc",
indoc! {"
To install an x86_64 cross-compiler on Ubuntu:
sudo apt-get install g++-x86-64-linux-gnu libc6-dev-amd64-cross musl-tools
"},
),
(X86_64_UNKNOWN_LINUX_MUSL, OS_MACOS, ARCH_X86_64 | ARCH_AARCH64) => (
"x86_64-unknown-linux-musl-gcc",
indoc! {"
To install an x86_64 cross-compiler on macOS:
brew install messense/macos-cross-toolchains/x86_64-unknown-linux-musl
"},
),
_ => return CrossCompileAssistance::NoAssistance,
};
match which(gcc_binary_name) {
Ok(_) => {
// When the gcc binary name is `musl-gcc`, Cargo will automatically select the appropriate default linker,
// and set the required environment variables.
if gcc_binary_name == "musl-gcc" {
CrossCompileAssistance::Configuration {
cargo_env: Vec::new(),
}
} else {
CrossCompileAssistance::Configuration {
cargo_env: vec![
(
// Required until Cargo can auto-detect the musl-cross gcc/linker itself,
// since otherwise it checks for a binary named 'musl-gcc' (which is handled above):
// https://github.com/rust-lang/cargo/issues/4133
OsString::from(format!(
"CARGO_TARGET_{}_LINKER",
target_triple.to_uppercase().replace('-', "_")
)),
OsString::from(gcc_binary_name),
),
(
// Required so that any crates that call out to gcc are also cross-compiled:
// https://github.com/alexcrichton/cc-rs/issues/82
OsString::from(format!("CC_{}", target_triple.replace('-', "_"))),
OsString::from(gcc_binary_name),
),
],
}
}
}
Err(_) => CrossCompileAssistance::HelpText(formatdoc! {"
For cross-compilation from {0} {1} to {target_triple},
a C compiler and linker for the target platform must be installed:
{help_text}
You will also need to install the Rust target:
rustup target add {target_triple}
",
consts::ARCH,
consts::OS
}),
}
}
pub enum CrossCompileAssistance {
/// No specific assistance available for the current host and target platform combination.
NoAssistance,
/// A human-readable help text with instructions on how to setup the
/// host machine for cross-compilation.
HelpText(String),
/// Required configuration to cross-compile to the target platform.
Configuration {
cargo_env: Vec<(OsString, OsString)>,
},
}
// Constants for supported target triples
const AARCH64_UNKNOWN_LINUX_MUSL: &str = "aarch64-unknown-linux-musl";
const X86_64_UNKNOWN_LINUX_MUSL: &str = "x86_64-unknown-linux-musl";
// Constants for `std::env::consts::OS` and `std::env::consts::ARCH`
const OS_LINUX: &str = "linux";
const OS_MACOS: &str = "macos";
const ARCH_X86_64: &str = "x86_64";
const ARCH_AARCH64: &str = "aarch64";