Skip to content

Commit 5a0308a

Browse files
committed
Auto merge of #31884 - alexcrichton:no-bootstrap-from-existing, r=brson
These commits add support to the rustbuild build system to compile non-build-system compilers. For example this will allow creating an ARM compiler on a x86 system. The high level way this works is: * The only compiler ever run is the build target compiler. No other compiler is assumed to be runnable. * As a result, all output artifacts come from the build compiler. * The libs for the stageN cross-compiled compiler will be linked into place after the build target builds them. This will break the assumption that a compiler never links to anything it didn't itself produce, but it retains the assumption that a compiler only ever links to anything built in the same stage. I believe this means that the stage1 cross-compiled compilers will still be usable. I tested this by creating an `arm-unknown-linux-gnueabihf` compiler. So far the linking ended up all working OK (including LLVM being cross compiled), but I haven't been able to run it yet (in QEMU for a raspberry pi). I think that's because my system linker is messed up or something like that (some newer option is assumed when it's not actually there). Overall, though, this means that rustbuild can compile an arm-unknown-linux-gnueabihf compiler. Ideally we could even start shipping nightlies based on this at some point!
2 parents 52cb8a9 + 15b4a8c commit 5a0308a

File tree

10 files changed

+216
-101
lines changed

10 files changed

+216
-101
lines changed

src/bootstrap/Cargo.lock

+18-35
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bootstrap/bootstrap.py

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def download_rust_nightly(self):
7373

7474
if self.rustc().startswith(self.bin_root()) and \
7575
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
76+
shutil.rmtree(self.bin_root())
7677
filename = "rust-std-nightly-" + self.build + ".tar.gz"
7778
url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date()
7879
tarball = os.path.join(rustc_cache, filename)

src/bootstrap/build/compile.rs

+60-22
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,30 @@ pub fn std<'a>(build: &'a Build, stage: u32, target: &str,
5858
}
5959

6060
build.run(&mut cargo);
61+
std_link(build, stage, target, compiler, host);
62+
}
63+
64+
/// Link all libstd rlibs/dylibs into the sysroot location.
65+
///
66+
/// Links those artifacts generated in the given `stage` for `target` produced
67+
/// by `compiler` into `host`'s sysroot.
68+
pub fn std_link(build: &Build,
69+
stage: u32,
70+
target: &str,
71+
compiler: &Compiler,
72+
host: &str) {
73+
let libdir = build.sysroot_libdir(stage, host, target);
74+
let out_dir = build.cargo_out(stage, compiler.host, true, target);
75+
76+
// If we're linking one compiler host's output into another, then we weren't
77+
// called from the `std` method above. In that case we clean out what's
78+
// already there and then also link compiler-rt into place.
79+
if host != compiler.host {
80+
let _ = fs::remove_dir_all(&libdir);
81+
t!(fs::create_dir_all(&libdir));
82+
t!(fs::hard_link(&build.compiler_rt_built.borrow()[target],
83+
libdir.join(staticlib("compiler-rt", target))));
84+
}
6185
add_to_sysroot(&out_dir, &libdir);
6286
}
6387

@@ -99,7 +123,6 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
99123
host, target);
100124

101125
let out_dir = build.cargo_out(stage, &host, false, target);
102-
let rustc = out_dir.join(exe("rustc", target));
103126
build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
104127

105128
let mut cargo = build.cargo(stage, compiler, false, target, "build");
@@ -131,10 +154,13 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
131154
if !build.unstable_features {
132155
cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
133156
}
134-
if let Some(config) = build.config.target_config.get(target) {
135-
if let Some(ref s) = config.llvm_config {
136-
cargo.env("LLVM_CONFIG", s);
137-
}
157+
let target_config = build.config.target_config.get(target);
158+
if let Some(ref s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
159+
cargo.env("LLVM_CONFIG", s);
160+
} else {
161+
let llvm_config = build.llvm_out(&build.config.build).join("bin")
162+
.join(exe("llvm-config", target));
163+
cargo.env("LLVM_CONFIG", llvm_config);
138164
}
139165
if build.config.llvm_static_stdcpp {
140166
cargo.env("LLVM_STATIC_STDCPP",
@@ -148,12 +174,21 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
148174
}
149175
build.run(&mut cargo);
150176

151-
let sysroot_libdir = build.sysroot_libdir(stage, host, target);
152-
add_to_sysroot(&out_dir, &sysroot_libdir);
177+
rustc_link(build, stage, target, compiler, compiler.host);
178+
}
153179

154-
if host == target {
155-
assemble_compiler(build, stage, target, &rustc);
156-
}
180+
/// Link all librustc rlibs/dylibs into the sysroot location.
181+
///
182+
/// Links those artifacts generated in the given `stage` for `target` produced
183+
/// by `compiler` into `host`'s sysroot.
184+
pub fn rustc_link(build: &Build,
185+
stage: u32,
186+
target: &str,
187+
compiler: &Compiler,
188+
host: &str) {
189+
let libdir = build.sysroot_libdir(stage, host, target);
190+
let out_dir = build.cargo_out(stage, compiler.host, false, target);
191+
add_to_sysroot(&out_dir, &libdir);
157192
}
158193

159194
/// Cargo's output path for the standard library in a given stage, compiled
@@ -169,39 +204,42 @@ fn compiler_file(compiler: &Path, file: &str) -> String {
169204

170205
/// Prepare a new compiler from the artifacts in `stage`
171206
///
172-
/// This will link the compiler built by `host` during the stage
173-
/// specified to the sysroot location for `host` to be the official
174-
/// `stage + 1` compiler for that host. This means that the `rustc` binary
175-
/// itself will be linked into place along with all supporting dynamic
176-
/// libraries.
177-
fn assemble_compiler(build: &Build, stage: u32, host: &str, rustc: &Path) {
207+
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
208+
/// must have been previously produced by the `stage - 1` build.config.build
209+
/// compiler.
210+
pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
211+
assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded");
212+
178213
// Clear out old files
179-
let sysroot = build.sysroot(stage + 1, host);
214+
let sysroot = build.sysroot(stage, host);
180215
let _ = fs::remove_dir_all(&sysroot);
181216
t!(fs::create_dir_all(&sysroot));
182217

183218
// Link in all dylibs to the libdir
184219
let sysroot_libdir = sysroot.join(libdir(host));
185220
t!(fs::create_dir_all(&sysroot_libdir));
186-
let src_libdir = build.sysroot_libdir(stage, host, host);
221+
let src_libdir = build.sysroot_libdir(stage - 1, &build.config.build, host);
187222
for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
188223
let filename = f.file_name().into_string().unwrap();
189224
if is_dylib(&filename) {
190225
t!(fs::hard_link(&f.path(), sysroot_libdir.join(&filename)));
191226
}
192227
}
193228

229+
let out_dir = build.cargo_out(stage - 1, &build.config.build, false, host);
230+
194231
// Link the compiler binary itself into place
232+
let rustc = out_dir.join(exe("rustc", host));
195233
let bindir = sysroot.join("bin");
196234
t!(fs::create_dir_all(&bindir));
197-
let compiler = build.compiler_path(&Compiler::new(stage + 1, host));
235+
let compiler = build.compiler_path(&Compiler::new(stage, host));
198236
let _ = fs::remove_file(&compiler);
199237
t!(fs::hard_link(rustc, compiler));
200238

201239
// See if rustdoc exists to link it into place
202-
let exe = exe("rustdoc", host);
203-
let rustdoc_src = rustc.parent().unwrap().join(&exe);
204-
let rustdoc_dst = bindir.join(exe);
240+
let rustdoc = exe("rustdoc", host);
241+
let rustdoc_src = out_dir.join(&rustdoc);
242+
let rustdoc_dst = bindir.join(&rustdoc);
205243
if fs::metadata(&rustdoc_src).is_ok() {
206244
let _ = fs::remove_file(&rustdoc_dst);
207245
t!(fs::hard_link(&rustdoc_src, &rustdoc_dst));

src/bootstrap/build/mod.rs

+23-23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ mod sanity;
3939
mod step;
4040
mod util;
4141

42+
#[cfg(windows)]
43+
mod job;
44+
45+
#[cfg(not(windows))]
46+
mod job {
47+
pub unsafe fn setup() {}
48+
}
49+
4250
pub use build::config::Config;
4351
pub use build::flags::Flags;
4452

@@ -114,14 +122,9 @@ impl Build {
114122
pub fn build(&mut self) {
115123
use build::step::Source::*;
116124

117-
// see comments in job.rs for what's going on here
118-
#[cfg(windows)]
119-
fn setup_job() {
120-
mod job;
121-
unsafe { job::setup() }
125+
unsafe {
126+
job::setup();
122127
}
123-
#[cfg(not(windows))] fn setup_job() {}
124-
setup_job();
125128

126129
if self.flags.clean {
127130
return clean::clean(self);
@@ -146,8 +149,19 @@ impl Build {
146149
Librustc { stage, compiler } => {
147150
compile::rustc(self, stage, target.target, &compiler);
148151
}
152+
LibstdLink { stage, compiler, host } => {
153+
compile::std_link(self, stage, target.target,
154+
&compiler, host);
155+
}
156+
LibrustcLink { stage, compiler, host } => {
157+
compile::rustc_link(self, stage, target.target,
158+
&compiler, host);
159+
}
160+
Rustc { stage: 0 } => {
161+
// nothing to do...
162+
}
149163
Rustc { stage } => {
150-
println!("ok, rustc stage{} in {}", stage, target.target);
164+
compile::assemble_rustc(self, stage, target.target);
151165
}
152166
}
153167
}
@@ -425,21 +439,7 @@ impl Build {
425439
}
426440

427441
fn rustc_flags(&self, target: &str) -> Vec<String> {
428-
let mut base = match target {
429-
"arm-unknown-linux-gnueabihf" => {
430-
vec!["-Ctarget-feature=+v6,+vfp2".to_string()]
431-
}
432-
"mips-unknown-linux-gnu" => {
433-
vec!["-Ctarget-cpu=mips32r2".to_string(),
434-
"-Ctarget-feature=+mips32r2".to_string(),
435-
"-Csoft-float".to_string()]
436-
}
437-
"mipsel-unknown-linux-gnu" => {
438-
vec!["-Ctarget-cpu=mips32".to_string(),
439-
"-Ctarget-feature=+mips32".to_string()]
440-
}
441-
_ => Vec::new(),
442-
};
442+
let mut base = Vec::new();
443443
if target != self.config.build && !target.contains("msvc") {
444444
base.push(format!("-Clinker={}", self.cc(target).display()));
445445
}

src/bootstrap/build/native.rs

+8
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ pub fn compiler_rt(build: &Build, target: &str) {
115115
let mode = if build.config.rust_optimize {"Release"} else {"Debug"};
116116
let (dir, build_target, libname) = if target.contains("linux") {
117117
let os = if target.contains("android") {"-android"} else {""};
118+
let arch = if arch.starts_with("arm") && target.contains("eabihf") {
119+
"armhf"
120+
} else {
121+
arch
122+
};
118123
let target = format!("clang_rt.builtins-{}{}", arch, os);
119124
("linux".to_string(), target.clone(), target)
120125
} else if target.contains("darwin") {
@@ -151,7 +156,10 @@ pub fn compiler_rt(build: &Build, target: &str) {
151156
.define("COMPILER_RT_DEFAULT_TARGET_TRIPLE", target)
152157
.define("COMPILER_RT_BUILD_SANITIZERS", "OFF")
153158
.define("COMPILER_RT_BUILD_EMUTLS", "OFF")
159+
// inform about c/c++ compilers, the c++ compiler isn't actually used but
160+
// it's needed to get the initial configure to work on all platforms.
154161
.define("CMAKE_C_COMPILER", build.cc(target))
162+
.define("CMAKE_CXX_COMPILER", build.cc(target))
155163
.build_target(&build_target);
156164
cfg.build();
157165
}

0 commit comments

Comments
 (0)