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}