use std::process::Command;
const WINDOWS_GNU_TARGET: &str = "x86_64-pc-windows-gnu";
const WINDOWS_MSVC_TARGET: &str = "x86_64-pc-windows-msvc";
const WINDOWS_GNU_I686_TARGET: &str = "i686-pc-windows-gnu";
const WINDOWS_ARM64_MSVC: &str = "aarch64-pc-windows-msvc";
const LINUX_MUSL_X64: &str = "x86_64-unknown-linux-musl";
const LINUX_AARCH64_GNU: &str = "aarch64-unknown-linux-gnu";
const LINUX_AARCH64_MUSL: &str = "aarch64-unknown-linux-musl";
const APPLE_AARCH64: &str = "aarch64-apple-darwin";
const APPLE_X64: &str = "x86_64-apple-darwin";
fn cargo_check(target: &str) -> std::process::Output {
Command::new("cargo")
.args(["check", "--target", target, "--lib"])
.env_remove("RUSTC_WRAPPER")
.env("CARGO_BUILD_RUSTC_WRAPPER", "")
.output()
.expect("failed to spawn cargo check")
}
fn target_installed(target: &str) -> bool {
Command::new("rustup")
.args(["target", "list", "--installed"])
.output()
.map(|o| {
String::from_utf8_lossy(&o.stdout)
.lines()
.any(|line| line.trim() == target)
})
.unwrap_or(false)
}
fn assert_no_gap14_errors(target: &str, output: &std::process::Output) {
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"cargo check --target {target} failed:\n{stderr}"
);
assert!(
!stderr.contains("E0433") && !stderr.contains("E0308"),
"GAP 14 regression detected in {target}: raw pointer / missing import errors:\n{stderr}"
);
}
#[test]
#[ignore = "requires x86_64-pc-windows-gnu target installed; see module docs"]
fn cross_compile_windows_gnu_x64_succeeds() {
if !target_installed(WINDOWS_GNU_TARGET) {
eprintln!(
"skipping: target {WINDOWS_GNU_TARGET} not installed; \
run `rustup target add {WINDOWS_GNU_TARGET}`"
);
return;
}
let output = cargo_check(WINDOWS_GNU_TARGET);
assert_no_gap14_errors(WINDOWS_GNU_TARGET, &output);
}
#[test]
#[ignore = "requires i686-pc-windows-gnu target installed and mingw32 toolchain"]
fn cross_compile_windows_gnu_i686_succeeds() {
if !target_installed(WINDOWS_GNU_I686_TARGET) {
eprintln!(
"skipping: target {WINDOWS_GNU_I686_TARGET} not installed; \
run `rustup target add {WINDOWS_GNU_I686_TARGET}`"
);
return;
}
let output = cargo_check(WINDOWS_GNU_I686_TARGET);
let stderr = String::from_utf8_lossy(&output.stderr);
if !output.status.success() && stderr.contains("i686-w64-mingw32-gcc") {
eprintln!(
"skipping: i686 mingw32 compiler not installed; install \
mingw32-gcc to enable this check"
);
return;
}
assert_no_gap14_errors(WINDOWS_GNU_I686_TARGET, &output);
}
#[test]
#[ignore = "requires x86_64-pc-windows-msvc target installed and MSVC toolchain"]
fn cross_compile_windows_msvc_succeeds() {
if !target_installed(WINDOWS_MSVC_TARGET) {
eprintln!(
"skipping: target {WINDOWS_MSVC_TARGET} not installed; \
run `rustup target add {WINDOWS_MSVC_TARGET}`"
);
return;
}
let output = cargo_check(WINDOWS_MSVC_TARGET);
let stderr = String::from_utf8_lossy(&output.stderr);
if !output.status.success() && stderr.contains("lib.exe") {
eprintln!(
"skipping: MSVC linker (lib.exe) not available; install \
Visual Studio Build Tools to enable this check"
);
return;
}
assert_no_gap14_errors(WINDOWS_MSVC_TARGET, &output);
}
fn skip_if_missing_linker(target: &str, output: &std::process::Output) -> bool {
if output.status.success() {
return false;
}
let stderr = String::from_utf8_lossy(&output.stderr);
let linker_hints = [
"linker",
"cannot find",
"not found",
"lib.exe",
"ld:",
"No such file",
"unknown target CPU",
"SDKROOT",
"xcrun",
];
if linker_hints.iter().any(|h| stderr.contains(h)) {
eprintln!("skipping: target {target} installed but host cannot link it:\n{stderr}");
return true;
}
false
}
#[test]
#[ignore = "requires aarch64-pc-windows-msvc target + Windows ARM64 toolchain"]
fn cross_compile_windows_arm64_msvc_succeeds() {
if !target_installed(WINDOWS_ARM64_MSVC) {
eprintln!(
"skipping: target {WINDOWS_ARM64_MSVC} not installed; \
run `rustup target add {WINDOWS_ARM64_MSVC}`"
);
return;
}
let output = cargo_check(WINDOWS_ARM64_MSVC);
if skip_if_missing_linker(WINDOWS_ARM64_MSVC, &output) {
return;
}
assert_no_gap14_errors(WINDOWS_ARM64_MSVC, &output);
}
#[test]
#[ignore = "requires x86_64-unknown-linux-musl target (Alpine / static containers)"]
fn cross_compile_linux_musl_x64_succeeds() {
if !target_installed(LINUX_MUSL_X64) {
eprintln!(
"skipping: target {LINUX_MUSL_X64} not installed; \
run `rustup target add {LINUX_MUSL_X64}`"
);
return;
}
let output = cargo_check(LINUX_MUSL_X64);
if skip_if_missing_linker(LINUX_MUSL_X64, &output) {
return;
}
assert_no_gap14_errors(LINUX_MUSL_X64, &output);
}
#[test]
#[ignore = "requires aarch64-unknown-linux-gnu target (Graviton / RPi 64-bit)"]
fn cross_compile_linux_aarch64_gnu_succeeds() {
if !target_installed(LINUX_AARCH64_GNU) {
eprintln!(
"skipping: target {LINUX_AARCH64_GNU} not installed; \
run `rustup target add {LINUX_AARCH64_GNU}`"
);
return;
}
let output = cargo_check(LINUX_AARCH64_GNU);
if skip_if_missing_linker(LINUX_AARCH64_GNU, &output) {
return;
}
assert_no_gap14_errors(LINUX_AARCH64_GNU, &output);
}
#[test]
#[ignore = "requires aarch64-unknown-linux-musl target"]
fn cross_compile_linux_aarch64_musl_succeeds() {
if !target_installed(LINUX_AARCH64_MUSL) {
eprintln!(
"skipping: target {LINUX_AARCH64_MUSL} not installed; \
run `rustup target add {LINUX_AARCH64_MUSL}`"
);
return;
}
let output = cargo_check(LINUX_AARCH64_MUSL);
if skip_if_missing_linker(LINUX_AARCH64_MUSL, &output) {
return;
}
assert_no_gap14_errors(LINUX_AARCH64_MUSL, &output);
}
#[test]
#[ignore = "requires aarch64-apple-darwin target (often macOS SDK / cross)"]
fn cross_compile_apple_aarch64_succeeds() {
if !target_installed(APPLE_AARCH64) {
eprintln!(
"skipping: target {APPLE_AARCH64} not installed; \
run `rustup target add {APPLE_AARCH64}`"
);
return;
}
let output = cargo_check(APPLE_AARCH64);
if skip_if_missing_linker(APPLE_AARCH64, &output) {
return;
}
assert_no_gap14_errors(APPLE_AARCH64, &output);
}
#[test]
#[ignore = "requires x86_64-apple-darwin target"]
fn cross_compile_apple_x64_succeeds() {
if !target_installed(APPLE_X64) {
eprintln!(
"skipping: target {APPLE_X64} not installed; \
run `rustup target add {APPLE_X64}`"
);
return;
}
let output = cargo_check(APPLE_X64);
if skip_if_missing_linker(APPLE_X64, &output) {
return;
}
assert_no_gap14_errors(APPLE_X64, &output);
}