handle cross-compilation test failure more gracefully

The current cross-compilation test module fails every test if an
appropriate cross standard library is not found.  This behavior is
unhelpful, because the failures are verbose, unexpected, and there's no
obvious way to make them go away.

Instead, it would be better to check once before all the tests that an
appropriate cross-compilation setup is available.  Once that check has
been done, a single test can fail with an appropriate `panic!` message
while the other tests silently pass.  The `panic!` message can inform
the user about their options, either setting an appropriate environment
variable, or using rustup to install the necessary cross standard
library.

Assuming the user has rustup installed, the single failure now looks
something like:

```
	thread 'plugin_deps' panicked at 'Cannot cross compile to i686-unknown-linux-gnu.

This failure can be safely ignored. If you would prefer to not see this
failure, you can set the environment variable CFG_DISABLE_CROSS_TESTS to "1".

Alternatively, you can install the necessary libraries for cross-compilation with

    rustup toolchain install stable-i686-unknown-linux-gnu

You may need to install runtime libraries for your Linux distribution as well.
', tests/cross-compile.rs:87
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```

Fixes #3086.
This commit is contained in:
Nathan Froyd 2017-01-06 14:30:38 -05:00
parent 508d66bca7
commit bbc1079877

View file

@ -3,10 +3,13 @@ extern crate cargotest;
extern crate hamcrest;
use std::env;
use std::process::Command;
use std::sync::{Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use cargo::util::process;
use cargotest::{is_nightly, rustc_host};
use cargotest::support::{project, execs, basic_bin_manifest};
use cargotest::support::{project, execs, main_file, basic_bin_manifest};
use hamcrest::{assert_that, existing_file};
fn disabled() -> bool {
@ -19,9 +22,82 @@ fn disabled() -> bool {
// Right now the windows bots cannot cross compile due to the mingw setup,
// so we disable ourselves on all but macos/linux setups where the rustc
// install script ensures we have both architectures
!(cfg!(target_os = "macos") ||
cfg!(target_os = "linux") ||
cfg!(target_env = "msvc"))
if !(cfg!(target_os = "macos") ||
cfg!(target_os = "linux") ||
cfg!(target_env = "msvc")) {
return true;
}
// It's not particularly common to have a cross-compilation setup, so
// try to detect that before we fail a bunch of tests through no fault
// of the user.
static mut CAN_RUN_CROSS_TESTS: bool = false;
static CHECK: Once = ONCE_INIT;
let cross_target = alternate();
CHECK.call_once(|| {
let p = project("cross_test")
.file("Cargo.toml", &basic_bin_manifest("cross_test"))
.file("src/cross_test.rs", &main_file(r#""testing!""#, &[]));
let result = p.cargo_process("build")
.arg("--target").arg(&cross_target)
.exec_with_output();
if result.is_ok() {
unsafe {
CAN_RUN_CROSS_TESTS = true;
}
}
});
if unsafe { CAN_RUN_CROSS_TESTS } {
// We were able to compile a simple project, so the user has the
// necessary std:: bits installed. Therefore, tests should not
// be disabled.
return false;
}
// We can't compile a simple cross project. We want to warn the user
// by failing a single test and having the remainder of the cross tests
// pass. We don't use std::sync::Once here because panicing inside its
// call_once method would poison the Once instance, which is not what
// we want.
static HAVE_WARNED: AtomicBool = ATOMIC_BOOL_INIT;
if HAVE_WARNED.swap(true, Ordering::SeqCst) {
// We are some other test and somebody else is handling the warning.
// Just disable the current test.
return true;
}
// We are responsible for warning the user, which we do by panicing.
let rustup_available = Command::new("rustup").output().is_ok();
let linux_help = if cfg!(target_os = "linux") {
"
You may need to install runtime libraries for your Linux distribution as well.".to_string()
} else {
"".to_string()
};
let rustup_help = if rustup_available {
format!("
Alternatively, you can install the necessary libraries for cross-compilation with
rustup target add {}{}", cross_target, linux_help)
} else {
"".to_string()
};
panic!("Cannot cross compile to {}.
This failure can be safely ignored. If you would prefer to not see this
failure, you can set the environment variable CFG_DISABLE_CROSS_TESTS to \"1\".{}
", cross_target, rustup_help);
}
fn alternate() -> String {