Skip to content

Commit f8568c2

Browse files
committed
Auto merge of rust-lang#111351 - ferrocene:pa-prevent-wrong-cc, r=onur-ozkan
Prevent using the default `cc` when that'd result in a broken build This PR adds a check in bootstrap to prevent issues like rust-lang#111142 to happen. What happened there is, no compiler for `aarch64-unknown-none` was detected by bootstrap, and so the `cc` crate defaulted to the system host C compiler. That resulted in a broken target, as `libcompiler_builtins.rlib` (or well anything compiling C code in its build script) contained half the object files compiled for aarch64 and half of them compiled for x86_64. The check added in the PR ensures that, for cross-compilation, the detected C compiler is not the same one as the host compiler, unless the detected compiler is clang (as it supports all targets from a single binary). This should not cause too many false positives, as for example a `./x build library --target i686-unknown-linux-gnu` still works from a x86_64 host. If a false positive occurs, the error message still explains the workaround. Example error message: ``` running: "/home/pietro/r/github/rust-lang/rust/2/build/bootstrap/debug/broken-cc" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-ffunction-sections" "-fdata-sections" "-fPIC" "--broken-cc-target=aarch64-unknown-none" "--broken-cc-detected=cc" "-I" "/home/pietro/r/github/rust-lang/rust/2/src/llvm-project/compiler-rt/lib/builtins" "-fno-builtin" "-fvisibility=hidden" "-ffreestanding" "-DVISIBILITY_HIDDEN" "-o" "/home/pietro/r/github/rust-lang/rust/2/build/x86_64-unknown-linux-gnu/stage0-std/aarch64-unknown-none/release/build/compiler_builtins-13da5a491a5cb882/out/ea072bc2688e9ac2-lse_cas1_relax.o" "-c" "/home/pietro/r/github/rust-lang/rust/2/build/x86_64-unknown-linux-gnu/stage0-std/aarch64-unknown-none/release/build/compiler_builtins-13da5a491a5cb882/out/lse_cas1_relax.S" cargo:warning= cargo:warning= Error: the automatic detection of the C compiler for cross-compiled cargo:warning= target aarch64-unknown-none returned the compiler also used for the cargo:warning= current host platform. cargo:warning= cargo:warning= This is likely wrong, and will likely result in a broken compilation cargo:warning= artifact. Please specify the correct compiler for that target, either cargo:warning= with environment variables: cargo:warning= cargo:warning= CC_aarch64_unknown_none=path/to/cc cargo:warning= CXX_aarch64_unknown_none=path/to/cxx cargo:warning= cargo:warning= ...or in config.toml: cargo:warning= cargo:warning= [target."aarch64-unknown-none"] cargo:warning= cc = "path/to/cc" cargo:warning= cxx = "path/to/cxx" cargo:warning= cargo:warning= The detected C compiler was: cargo:warning= cargo:warning= cc cargo:warning= exit status: 1 --- stderr error occurred: Command "/home/pietro/r/github/rust-lang/rust/2/build/bootstrap/debug/broken-cc" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-ffunction-sections" "-fdata-sections" "-fPIC" "--broken-cc-target=aarch64-unknown-none" "--broken-cc-detected=cc" "-I" "/home/pietro/r/github/rust-lang/rust/2/src/llvm-project/compiler-rt/lib/builtins" "-fno-builtin" "-fvisibility=hidden" "-ffreestanding" "-DVISIBILITY_HIDDEN" "-o" "/home/pietro/r/github/rust-lang/rust/2/build/x86_64-unknown-linux-gnu/stage0-std/aarch64-unknown-none/release/build/compiler_builtins-13da5a491a5cb882/out/ea072bc2688e9ac2-lse_cas1_relax.o" "-c" "/home/pietro/r/github/rust-lang/rust/2/build/x86_64-unknown-linux-gnu/stage0-std/aarch64-unknown-none/release/build/compiler_builtins-13da5a491a5cb882/out/lse_cas1_relax.S" with args "broken-cc" did not execute successfully (status code exit status: 1). Build completed unsuccessfully in 0:00:02 ``` Fixes rust-lang#111142 r? `@jyn514`
2 parents ee85f7f + bda0331 commit f8568c2

File tree

5 files changed

+96
-1
lines changed

5 files changed

+96
-1
lines changed

src/bootstrap/src/bin/broken-cc.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Show an error message when the wrong C compiler is detected. See the cc_detect module inside of
2+
// bootstrap for more context on why this binary was added.
3+
4+
use std::process::ExitCode;
5+
6+
const PREFIX: &str = " ";
7+
8+
fn main() -> ExitCode {
9+
let mut target = None;
10+
let mut detected_cc = None;
11+
for arg in std::env::args() {
12+
match arg.split_once('=') {
13+
Some(("--broken-cc-target", t)) => target = Some(t.to_string()),
14+
Some(("--broken-cc-detected", d)) => detected_cc = Some(d.to_string()),
15+
_ => {}
16+
}
17+
}
18+
19+
let detected_cc = detected_cc.expect("broken-cc not invoked by bootstrap correctly");
20+
let target = target.expect("broken-cc not invoked by bootstrap correctly");
21+
let underscore_target = target.replace('-', "_");
22+
23+
eprintln!();
24+
eprintln!("{PREFIX}Error: the automatic detection of the C compiler for cross-compiled");
25+
eprintln!("{PREFIX}target {target} returned the C compiler also used for the");
26+
eprintln!("{PREFIX}current host platform.");
27+
eprintln!();
28+
eprintln!("{PREFIX}This is likely wrong, and will likely result in a broken compilation");
29+
eprintln!("{PREFIX}artifact. Please specify the correct C compiler for that target, either");
30+
eprintln!("{PREFIX}with environment variables:");
31+
eprintln!();
32+
eprintln!("{PREFIX} CC_{underscore_target}=path/to/cc");
33+
eprintln!("{PREFIX} CXX_{underscore_target}=path/to/cxx");
34+
eprintln!();
35+
eprintln!("{PREFIX}...or in config.toml:");
36+
eprintln!();
37+
eprintln!("{PREFIX} [target.\"{target}\"]");
38+
eprintln!("{PREFIX} cc = \"path/to/cc\"");
39+
eprintln!("{PREFIX} cxx = \"path/to/cxx\"");
40+
eprintln!();
41+
eprintln!("{PREFIX}The detected C compiler was:");
42+
eprintln!();
43+
eprintln!("{PREFIX} {detected_cc}");
44+
eprintln!();
45+
46+
ExitCode::FAILURE
47+
}

src/bootstrap/src/core/build_steps/test.rs

+3
Original file line numberDiff line numberDiff line change
@@ -3062,6 +3062,9 @@ impl Step for TestHelpers {
30623062
cfg.archiver(ar);
30633063
}
30643064
cfg.compiler(builder.cc(target));
3065+
for flag in builder.cflags(target, GitRepo::Rustc, CLang::C) {
3066+
cfg.flag(&flag);
3067+
}
30653068
}
30663069
cfg.cargo_metadata(false)
30673070
.out_dir(&dst)

src/bootstrap/src/utils/cc_detect.rs

+34
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,40 @@ pub fn find_target(build: &Build, target: TargetSelection) {
115115
}
116116

117117
let compiler = cfg.get_compiler();
118+
119+
// When the cc crate cannot find the appropriate C compiler for the requested target, rather
120+
// than erroring out it returns the default C compiler. In most cases, this is wrong.
121+
//
122+
// For example, let's say that you're cross-compiling for aarch64-unknown-none from an x86_64
123+
// host, and that target is not recognized by the cc crate. In that case, the detected cc will
124+
// be an x86_64 compiler, even though we're compiling for aarch64-unknown-none. If a crate then
125+
// compiles some C code in its build script, the resulting rlib will have mixed AArch64 and
126+
// x86_64 objects in it, and the linker will show rather unhelpful messages.
127+
//
128+
// To avoid the confusing error messages, we detect whether the configuration is likely broken,
129+
// and if so we replace the detected C compiler with a stub binary that prints a useful error
130+
// message, telling the user to manually configure their C compiler.
131+
//
132+
// We use a custom binary rather than erroring out directly here because some build steps might
133+
// not need a C compiler at all, and it would be annoying to prevent the build in those cases.
134+
let default_cc = new_cc_build(build, build.build).get_compiler();
135+
if target != build.build && !compiler.is_like_clang() && compiler.path() == default_cc.path() {
136+
let mut broken_cc = new_cc_build(build, target);
137+
broken_cc.compiler(
138+
std::env::current_exe()
139+
.expect("failed to retrieve path to the bootstrap executable")
140+
.parent()
141+
.unwrap()
142+
.join(format!("broken-cc{}", std::env::consts::EXE_SUFFIX)),
143+
);
144+
broken_cc.flag(&format!("--broken-cc-target={target}"));
145+
broken_cc.flag(&format!("--broken-cc-detected={}", default_cc.path().display()));
146+
147+
build.cc.borrow_mut().insert(target, broken_cc.get_compiler());
148+
build.cxx.borrow_mut().insert(target, broken_cc.get_compiler());
149+
return;
150+
}
151+
118152
let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
119153
ar
120154
} else {

src/ci/docker/host-x86_64/test-various/Dockerfile

+5-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_T
6060
tests/assembly \
6161
library/core
6262

63-
ENV NVPTX_TARGETS=nvptx64-nvidia-cuda
63+
ENV NVPTX_TARGETS=nvptx64-nvidia-cuda \
64+
CC_nvptx64_nvidia_cuda=clang-11 \
65+
CXX_nvptx64_nvidia_cuda=clang++-11 \
66+
CFLAGS_nvptx64_nvidia_cuda=-flto \
67+
CXXFLAGS_nvptx64_nvidia_cuda=-flto
6468
ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \
6569
tests/run-make \
6670
tests/assembly

tests/auxiliary/rust_test_helpers.c

+7
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,11 @@ float get_c_exhaust_sysv64_ints(
268268
return h.c;
269269
}
270270

271+
// Variadic arguments are broken when using clang to compile nvptx-nvidia-cuda,
272+
// causing clang to ICE. As no test run on CI currently relies on these
273+
// functions, we don't compile them when building for nvptx-nvidia-cuda.
274+
#ifndef __CUDA_ARCH__
275+
271276
// Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs
272277
// passed as variadic arguments. There are two versions of this function: the
273278
// variadic one, and the one that takes a `va_list`.
@@ -290,6 +295,8 @@ double rust_interesting_average(uint64_t n, ...) {
290295
return sum;
291296
}
292297

298+
#endif
299+
293300
int32_t rust_int8_to_int32(int8_t x) {
294301
return (int32_t)x;
295302
}

0 commit comments

Comments
 (0)