Skip to content

Commit efbbd0c

Browse files
committed
prevent using the default cc when that'd result in a broken build
1 parent 6eb3e97 commit efbbd0c

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
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/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 {

0 commit comments

Comments
 (0)