Skip to main content

cargo_test_support/
cross_compile.rs

1//! Support for cross-compile tests with the `--target` flag.
2//!
3//! Note that cross-testing is very limited. You need to install the
4//! "alternate" target to the host (32-bit for 64-bit hosts or vice-versa).
5//!
6//! Set `CFG_DISABLE_CROSS_TESTS=1` environment variable to disable these tests
7//! if you are unable to use the alternate target. Unfortunately 32-bit
8//! support on macOS is going away, so macOS users are out of luck.
9//!
10//! These tests are all disabled on rust-lang/rust's CI, but run in Cargo's CI.
11
12/// The host tuple of the compiler used to build test projects.
13pub fn native() -> &'static str {
14    crate::rustc_host()
15}
16
17pub fn native_arch() -> &'static str {
18    match native()
19        .split("-")
20        .next()
21        .expect("Target tuple has unexpected format")
22    {
23        "x86_64" => "x86_64",
24        "aarch64" => "aarch64",
25        "i686" => "x86",
26        _ => panic!("This test should be gated on cross_compile::disabled."),
27    }
28}
29
30/// The alternate target-tuple to build with.
31///
32/// Only use this function on tests that check `cross_compile::disabled`.
33pub fn alternate() -> &'static str {
34    try_alternate().expect("This test should be gated on cross_compile::disabled.")
35}
36
37/// A possible alternate target-tuple to build with.
38pub(crate) fn try_alternate() -> Option<&'static str> {
39    if cfg!(target_os = "macos") {
40        Some("x86_64-apple-darwin")
41    } else if cfg!(target_os = "linux") {
42        Some("i686-unknown-linux-gnu")
43    } else if cfg!(all(target_os = "windows", target_env = "msvc")) {
44        Some("i686-pc-windows-msvc")
45    } else if cfg!(all(target_os = "windows", target_env = "gnu")) {
46        Some("i686-pc-windows-gnu")
47    } else {
48        None
49    }
50}
51
52pub fn alternate_arch() -> &'static str {
53    if cfg!(target_os = "macos") {
54        "x86_64"
55    } else {
56        "x86"
57    }
58}
59
60/// A target-tuple that is neither the host nor the target.
61///
62/// Rustc may not work with it and it's alright, apart from being a
63/// valid target tuple it is supposed to be used only as a
64/// placeholder for targets that should not be considered.
65pub fn unused() -> &'static str {
66    "wasm32-unknown-unknown"
67}
68
69/// Check if the given target has been installed.
70///
71/// Generally `testsuite::utils::cross_compile::disabled` should be used to check if cross-compilation is allowed.
72/// And [`alternate`] to get the cross target.
73///
74/// You should only use this as a last resort to skip tests,
75/// because it doesn't report skipped tests as ignored.
76pub fn requires_target_installed(target: &str) -> bool {
77    let has_target = std::process::Command::new("rustup")
78        .args(["target", "list", "--installed"])
79        .output()
80        .ok()
81        .map(|output| {
82            String::from_utf8(output.stdout)
83                .map(|stdout| stdout.contains(target))
84                .unwrap_or_default()
85        })
86        .unwrap_or_default();
87    if !has_target {
88        let msg =
89            format!("to run this test, run `rustup target add {target} --toolchain <toolchain>`",);
90        if cargo_util::is_ci() {
91            panic!("{msg}");
92        } else {
93            eprintln!("{msg}");
94        }
95    }
96    has_target
97}