diff --git a/src/bootstrap/src/bin/broken-cc.rs b/src/bootstrap/src/bin/broken-cc.rs new file mode 100644 index 0000000000000..4f5e4ba529c26 --- /dev/null +++ b/src/bootstrap/src/bin/broken-cc.rs @@ -0,0 +1,47 @@ +// Show an error message when the wrong C compiler is detected. See the cc_detect module inside of +// bootstrap for more context on why this binary was added. + +use std::process::ExitCode; + +const PREFIX: &str = " "; + +fn main() -> ExitCode { + let mut target = None; + let mut detected_cc = None; + for arg in std::env::args() { + match arg.split_once('=') { + Some(("--broken-cc-target", t)) => target = Some(t.to_string()), + Some(("--broken-cc-detected", d)) => detected_cc = Some(d.to_string()), + _ => {} + } + } + + let detected_cc = detected_cc.expect("broken-cc not invoked by bootstrap correctly"); + let target = target.expect("broken-cc not invoked by bootstrap correctly"); + let underscore_target = target.replace('-', "_"); + + eprintln!(); + eprintln!("{PREFIX}Error: the automatic detection of the C compiler for cross-compiled"); + eprintln!("{PREFIX}target {target} returned the C compiler also used for the"); + eprintln!("{PREFIX}current host platform."); + eprintln!(); + eprintln!("{PREFIX}This is likely wrong, and will likely result in a broken compilation"); + eprintln!("{PREFIX}artifact. Please specify the correct C compiler for that target, either"); + eprintln!("{PREFIX}with environment variables:"); + eprintln!(); + eprintln!("{PREFIX} CC_{underscore_target}=path/to/cc"); + eprintln!("{PREFIX} CXX_{underscore_target}=path/to/cxx"); + eprintln!(); + eprintln!("{PREFIX}...or in config.toml:"); + eprintln!(); + eprintln!("{PREFIX} [target.\"{target}\"]"); + eprintln!("{PREFIX} cc = \"path/to/cc\""); + eprintln!("{PREFIX} cxx = \"path/to/cxx\""); + eprintln!(); + eprintln!("{PREFIX}The detected C compiler was:"); + eprintln!(); + eprintln!("{PREFIX} {detected_cc}"); + eprintln!(); + + ExitCode::FAILURE +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 831a86940fb48..63e642a882c00 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2960,6 +2960,9 @@ impl Step for TestHelpers { cfg.archiver(ar); } cfg.compiler(builder.cc(target)); + for flag in builder.cflags(target, GitRepo::Rustc, CLang::C) { + cfg.flag(&flag); + } } cfg.cargo_metadata(false) .out_dir(&dst) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 52b36ce75f343..2f31680146c08 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -115,6 +115,40 @@ pub fn find_target(build: &Build, target: TargetSelection) { } let compiler = cfg.get_compiler(); + + // When the cc crate cannot find the appropriate C compiler for the requested target, rather + // than erroring out it returns the default C compiler. In most cases, this is wrong. + // + // For example, let's say that you're cross-compiling for aarch64-unknown-none from an x86_64 + // host, and that target is not recognized by the cc crate. In that case, the detected cc will + // be an x86_64 compiler, even though we're compiling for aarch64-unknown-none. If a crate then + // compiles some C code in its build script, the resulting rlib will have mixed AArch64 and + // x86_64 objects in it, and the linker will show rather unhelpful messages. + // + // To avoid the confusing error messages, we detect whether the configuration is likely broken, + // and if so we replace the detected C compiler with a stub binary that prints a useful error + // message, telling the user to manually configure their C compiler. + // + // We use a custom binary rather than erroring out directly here because some build steps might + // not need a C compiler at all, and it would be annoying to prevent the build in those cases. + let default_cc = new_cc_build(build, build.build).get_compiler(); + if target != build.build && !compiler.is_like_clang() && compiler.path() == default_cc.path() { + let mut broken_cc = new_cc_build(build, target); + broken_cc.compiler( + std::env::current_exe() + .expect("failed to retrieve path to the bootstrap executable") + .parent() + .unwrap() + .join(format!("broken-cc{}", std::env::consts::EXE_SUFFIX)), + ); + broken_cc.flag(&format!("--broken-cc-target={target}")); + broken_cc.flag(&format!("--broken-cc-detected={}", default_cc.path().display())); + + build.cc.borrow_mut().insert(target, broken_cc.get_compiler()); + build.cxx.borrow_mut().insert(target, broken_cc.get_compiler()); + return; + } + let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { ar } else { diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 4fe66014c17cd..203bdbb3c307d 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -60,7 +60,11 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_T tests/assembly \ library/core -ENV NVPTX_TARGETS=nvptx64-nvidia-cuda +ENV NVPTX_TARGETS=nvptx64-nvidia-cuda \ + CC_nvptx64_nvidia_cuda=clang-11 \ + CXX_nvptx64_nvidia_cuda=clang++-11 \ + CFLAGS_nvptx64_nvidia_cuda=-flto \ + CXXFLAGS_nvptx64_nvidia_cuda=-flto ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \ tests/run-make \ tests/assembly diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c index 977ea487a9804..f2be900038737 100644 --- a/tests/auxiliary/rust_test_helpers.c +++ b/tests/auxiliary/rust_test_helpers.c @@ -268,6 +268,11 @@ float get_c_exhaust_sysv64_ints( return h.c; } +// Variadic arguments are broken when using clang to compile nvptx-nvidia-cuda, +// causing clang to ICE. As no test run on CI currently relies on these +// functions, we don't compile them when building for nvptx-nvidia-cuda. +#ifndef __CUDA_ARCH__ + // Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs // passed as variadic arguments. There are two versions of this function: the // variadic one, and the one that takes a `va_list`. @@ -290,6 +295,8 @@ double rust_interesting_average(uint64_t n, ...) { return sum; } +#endif + int32_t rust_int8_to_int32(int8_t x) { return (int32_t)x; }