Skip to content

Prevent using the default cc when that'd result in a broken build #111351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/bootstrap/src/bin/broken-cc.rs
Original file line number Diff line number Diff line change
@@ -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
}
3 changes: 3 additions & 0 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
34 changes: 34 additions & 0 deletions src/bootstrap/src/utils/cc_detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 5 additions & 1 deletion src/ci/docker/host-x86_64/test-various/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions tests/auxiliary/rust_test_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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;
}
Expand Down