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
12use std::env;
13
14/// The arch triple of the test-running host.
15pub fn native() -> &'static str {
16    env!("NATIVE_ARCH")
17}
18
19pub fn native_arch() -> &'static str {
20    match native()
21        .split("-")
22        .next()
23        .expect("Target triple has unexpected format")
24    {
25        "x86_64" => "x86_64",
26        "aarch64" => "aarch64",
27        "i686" => "x86",
28        _ => panic!("This test should be gated on cross_compile::disabled."),
29    }
30}
31
32/// The alternate target-triple to build with.
33///
34/// Only use this function on tests that check `cross_compile::disabled`.
35pub fn alternate() -> &'static str {
36    try_alternate().expect("This test should be gated on cross_compile::disabled.")
37}
38
39/// A possible alternate target-triple to build with.
40pub(crate) fn try_alternate() -> Option<&'static str> {
41    if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
42        Some("x86_64-apple-darwin")
43    } else if cfg!(target_os = "macos") {
44        Some("x86_64-apple-ios")
45    } else if cfg!(target_os = "linux") {
46        Some("i686-unknown-linux-gnu")
47    } else if cfg!(all(target_os = "windows", target_env = "msvc")) {
48        Some("i686-pc-windows-msvc")
49    } else if cfg!(all(target_os = "windows", target_env = "gnu")) {
50        Some("i686-pc-windows-gnu")
51    } else {
52        None
53    }
54}
55
56pub fn alternate_arch() -> &'static str {
57    if cfg!(target_os = "macos") {
58        "x86_64"
59    } else {
60        "x86"
61    }
62}
63
64/// A target-triple that is neither the host nor the target.
65///
66/// Rustc may not work with it and it's alright, apart from being a
67/// valid target triple it is supposed to be used only as a
68/// placeholder for targets that should not be considered.
69pub fn unused() -> &'static str {
70    "wasm32-unknown-unknown"
71}
72
73/// Check if the given target has been installed.
74///
75/// Generally `testsuite::utils::cross_compile::disabled` should be used to check if cross-compilation is allowed.
76/// And [`alternate`] to get the cross target.
77///
78/// You should only use this as a last resort to skip tests,
79/// because it doesn't report skipped tests as ignored.
80pub fn requires_target_installed(target: &str) -> bool {
81    let has_target = std::process::Command::new("rustup")
82        .args(["target", "list", "--installed"])
83        .output()
84        .ok()
85        .map(|output| {
86            String::from_utf8(output.stdout)
87                .map(|stdout| stdout.contains(target))
88                .unwrap_or_default()
89        })
90        .unwrap_or_default();
91    if !has_target {
92        let msg =
93            format!("to run this test, run `rustup target add {target} --toolchain <toolchain>`",);
94        if cargo_util::is_ci() {
95            panic!("{msg}");
96        } else {
97            eprintln!("{msg}");
98        }
99    }
100    has_target
101}