]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | //! Implementation of compiling various phases of the compiler and standard |
2 | //! library. | |
3 | //! | |
4 | //! This module contains some of the real meat in the rustbuild build system | |
5 | //! which is where Cargo is used to compiler the standard library, libtest, and | |
6 | //! compiler. This module is also responsible for assembling the sysroot as it | |
7 | //! goes along from the output of the previous stage. | |
8 | ||
0531ce1d | 9 | use std::borrow::Cow; |
7cac9316 | 10 | use std::env; |
0731742a | 11 | use std::fs; |
7cac9316 XL |
12 | use std::io::BufReader; |
13 | use std::io::prelude::*; | |
7453a54e | 14 | use std::path::{Path, PathBuf}; |
a1dfa0c6 | 15 | use std::process::{Command, Stdio, exit}; |
7cac9316 | 16 | use std::str; |
7453a54e | 17 | |
48663c56 | 18 | use build_helper::{output, mtime, t, up_to_date}; |
9e0c209e | 19 | use filetime::FileTime; |
48663c56 | 20 | use serde::Deserialize; |
3b2f2976 | 21 | use serde_json; |
7453a54e | 22 | |
0731742a | 23 | use crate::dist; |
532ac7d7 | 24 | use crate::util::{exe, is_dylib}; |
0731742a XL |
25 | use crate::{Compiler, Mode, GitRepo}; |
26 | use crate::native; | |
7453a54e | 27 | |
0731742a XL |
28 | use crate::cache::{INTERNER, Interned}; |
29 | use crate::builder::{Step, RunConfig, ShouldRun, Builder}; | |
3b2f2976 | 30 | |
83c7162d | 31 | #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] |
3b2f2976 XL |
32 | pub struct Std { |
33 | pub target: Interned<String>, | |
34 | pub compiler: Compiler, | |
35 | } | |
36 | ||
37 | impl Step for Std { | |
38 | type Output = (); | |
39 | const DEFAULT: bool = true; | |
40 | ||
9fa01778 | 41 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
2c00a5a8 | 42 | run.all_krates("std") |
3b2f2976 XL |
43 | } |
44 | ||
9fa01778 | 45 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
46 | run.builder.ensure(Std { |
47 | compiler: run.builder.compiler(run.builder.top_stage, run.host), | |
48 | target: run.target, | |
49 | }); | |
50 | } | |
51 | ||
9fa01778 | 52 | /// Builds the standard library. |
3b2f2976 XL |
53 | /// |
54 | /// This will build the standard library for a particular stage of the build | |
55 | /// using the `compiler` targeting the `target` architecture. The artifacts | |
56 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 57 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
58 | let target = self.target; |
59 | let compiler = self.compiler; | |
60 | ||
8faf50e0 XL |
61 | if builder.config.keep_stage.contains(&compiler.stage) { |
62 | builder.info("Warning: Using a potentially old libstd. This may not behave well."); | |
63 | builder.ensure(StdLink { | |
a1dfa0c6 | 64 | compiler, |
8faf50e0 XL |
65 | target_compiler: compiler, |
66 | target, | |
67 | }); | |
68 | return; | |
69 | } | |
70 | ||
3b2f2976 XL |
71 | builder.ensure(StartupObjects { compiler, target }); |
72 | ||
dc9dc135 XL |
73 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
74 | if compiler_to_use != compiler { | |
3b2f2976 | 75 | builder.ensure(Std { |
dc9dc135 | 76 | compiler: compiler_to_use, |
3b2f2976 XL |
77 | target, |
78 | }); | |
dc9dc135 | 79 | builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target)); |
3b2f2976 XL |
80 | |
81 | // Even if we're not building std this stage, the new sysroot must | |
0731742a XL |
82 | // still contain the third party objects needed by various targets. |
83 | copy_third_party_objects(builder, &compiler, target); | |
3b2f2976 XL |
84 | |
85 | builder.ensure(StdLink { | |
dc9dc135 | 86 | compiler: compiler_to_use, |
3b2f2976 XL |
87 | target_compiler: compiler, |
88 | target, | |
89 | }); | |
90 | return; | |
91 | } | |
92 | ||
0731742a | 93 | copy_third_party_objects(builder, &compiler, target); |
3b2f2976 | 94 | |
94b46f34 | 95 | let mut cargo = builder.cargo(compiler, Mode::Std, target, "build"); |
0531ce1d XL |
96 | std_cargo(builder, &compiler, target, &mut cargo); |
97 | ||
83c7162d XL |
98 | let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); |
99 | builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage, | |
100 | &compiler.host, target)); | |
101 | run_cargo(builder, | |
abe05a73 | 102 | &mut cargo, |
dc9dc135 | 103 | vec![], |
83c7162d | 104 | &libstd_stamp(builder, compiler, target), |
2c00a5a8 | 105 | false); |
3b2f2976 XL |
106 | |
107 | builder.ensure(StdLink { | |
83c7162d | 108 | compiler: builder.compiler(compiler.stage, builder.config.build), |
3b2f2976 XL |
109 | target_compiler: compiler, |
110 | target, | |
111 | }); | |
112 | } | |
113 | } | |
114 | ||
0731742a | 115 | /// Copies third pary objects needed by various targets. |
9fa01778 | 116 | fn copy_third_party_objects(builder: &Builder<'_>, compiler: &Compiler, target: Interned<String>) { |
0731742a XL |
117 | let libdir = builder.sysroot_libdir(*compiler, target); |
118 | ||
119 | // Copies the crt(1,i,n).o startup objects | |
120 | // | |
121 | // Since musl supports fully static linking, we can cross link for it even | |
122 | // with a glibc-targeting toolchain, given we have the appropriate startup | |
123 | // files. As those shipped with glibc won't work, copy the ones provided by | |
124 | // musl so we have them on linux-gnu hosts. | |
125 | if target.contains("musl") { | |
126 | for &obj in &["crt1.o", "crti.o", "crtn.o"] { | |
127 | builder.copy( | |
128 | &builder.musl_root(target).unwrap().join("lib").join(obj), | |
129 | &libdir.join(obj), | |
130 | ); | |
131 | } | |
532ac7d7 XL |
132 | } else if target.ends_with("-wasi") { |
133 | for &obj in &["crt1.o"] { | |
134 | builder.copy( | |
135 | &builder.wasi_root(target).unwrap().join("lib/wasm32-wasi").join(obj), | |
136 | &libdir.join(obj), | |
137 | ); | |
138 | } | |
0731742a XL |
139 | } |
140 | ||
141 | // Copies libunwind.a compiled to be linked wit x86_64-fortanix-unknown-sgx. | |
142 | // | |
143 | // This target needs to be linked to Fortanix's port of llvm's libunwind. | |
144 | // libunwind requires support for rwlock and printing to stderr, | |
145 | // which is provided by std for this target. | |
146 | if target == "x86_64-fortanix-unknown-sgx" { | |
147 | let src_path_env = "X86_FORTANIX_SGX_LIBS"; | |
148 | let obj = "libunwind.a"; | |
149 | let src = env::var(src_path_env).expect(&format!("{} not found in env", src_path_env)); | |
150 | let src = Path::new(&src).join(obj); | |
151 | builder.copy(&src, &libdir.join(obj)); | |
3b2f2976 XL |
152 | } |
153 | } | |
154 | ||
155 | /// Configure cargo to compile the standard library, adding appropriate env vars | |
156 | /// and such. | |
9fa01778 | 157 | pub fn std_cargo(builder: &Builder<'_>, |
3b2f2976 XL |
158 | compiler: &Compiler, |
159 | target: Interned<String>, | |
160 | cargo: &mut Command) { | |
041b39d2 | 161 | if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { |
8bb4bdeb XL |
162 | cargo.env("MACOSX_DEPLOYMENT_TARGET", target); |
163 | } | |
164 | ||
dc9dc135 XL |
165 | // Determine if we're going to compile in optimized C intrinsics to |
166 | // the `compiler-builtins` crate. These intrinsics live in LLVM's | |
167 | // `compiler-rt` repository, but our `src/llvm-project` submodule isn't | |
168 | // always checked out, so we need to conditionally look for this. (e.g. if | |
169 | // an external LLVM is used we skip the LLVM submodule checkout). | |
170 | // | |
171 | // Note that this shouldn't affect the correctness of `compiler-builtins`, | |
172 | // but only its speed. Some intrinsics in C haven't been translated to Rust | |
173 | // yet but that's pretty rare. Other intrinsics have optimized | |
174 | // implementations in C which have only had slower versions ported to Rust, | |
175 | // so we favor the C version where we can, but it's not critical. | |
176 | // | |
177 | // If `compiler-rt` is available ensure that the `c` feature of the | |
178 | // `compiler-builtins` crate is enabled and it's configured to learn where | |
179 | // `compiler-rt` is located. | |
180 | let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); | |
181 | let compiler_builtins_c_feature = if compiler_builtins_root.exists() { | |
182 | cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); | |
183 | " compiler-builtins-c".to_string() | |
184 | } else { | |
185 | String::new() | |
186 | }; | |
187 | ||
83c7162d | 188 | if builder.no_std(target) == Some(true) { |
dc9dc135 XL |
189 | let mut features = "compiler-builtins-mem".to_string(); |
190 | features.push_str(&compiler_builtins_c_feature); | |
191 | ||
83c7162d | 192 | // for no-std targets we only compile a few no_std crates |
0731742a | 193 | cargo |
83c7162d | 194 | .args(&["-p", "alloc"]) |
83c7162d | 195 | .arg("--manifest-path") |
0731742a XL |
196 | .arg(builder.src.join("src/liballoc/Cargo.toml")) |
197 | .arg("--features") | |
48663c56 | 198 | .arg("compiler-builtins-mem compiler-builtins-c"); |
83c7162d | 199 | } else { |
dc9dc135 XL |
200 | let mut features = builder.std_features(); |
201 | features.push_str(&compiler_builtins_c_feature); | |
8bb4bdeb | 202 | |
83c7162d XL |
203 | if compiler.stage != 0 && builder.config.sanitizers { |
204 | // This variable is used by the sanitizer runtime crates, e.g. | |
205 | // rustc_lsan, to build the sanitizer runtime from C code | |
206 | // When this variable is missing, those crates won't compile the C code, | |
207 | // so we don't set this variable during stage0 where llvm-config is | |
208 | // missing | |
209 | // We also only build the runtimes when --enable-sanitizers (or its | |
210 | // config.toml equivalent) is used | |
211 | let llvm_config = builder.ensure(native::Llvm { | |
212 | target: builder.config.build, | |
213 | emscripten: false, | |
214 | }); | |
215 | cargo.env("LLVM_CONFIG", llvm_config); | |
216 | } | |
3b2f2976 | 217 | |
83c7162d XL |
218 | cargo.arg("--features").arg(features) |
219 | .arg("--manifest-path") | |
220 | .arg(builder.src.join("src/libstd/Cargo.toml")); | |
7453a54e | 221 | |
83c7162d XL |
222 | if target.contains("musl") { |
223 | if let Some(p) = builder.musl_root(target) { | |
224 | cargo.env("MUSL_ROOT", p); | |
225 | } | |
7453a54e | 226 | } |
532ac7d7 XL |
227 | |
228 | if target.ends_with("-wasi") { | |
229 | if let Some(p) = builder.wasi_root(target) { | |
230 | cargo.env("WASI_ROOT", p); | |
231 | } | |
232 | } | |
7453a54e | 233 | } |
7453a54e SL |
234 | } |
235 | ||
3b2f2976 XL |
236 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
237 | struct StdLink { | |
238 | pub compiler: Compiler, | |
239 | pub target_compiler: Compiler, | |
240 | pub target: Interned<String>, | |
54a0048b SL |
241 | } |
242 | ||
3b2f2976 XL |
243 | impl Step for StdLink { |
244 | type Output = (); | |
245 | ||
9fa01778 | 246 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
247 | run.never() |
248 | } | |
249 | ||
250 | /// Link all libstd rlibs/dylibs into the sysroot location. | |
251 | /// | |
a1dfa0c6 | 252 | /// Links those artifacts generated by `compiler` to the `stage` compiler's |
3b2f2976 XL |
253 | /// sysroot for the specified `host` and `target`. |
254 | /// | |
255 | /// Note that this assumes that `compiler` has already generated the libstd | |
256 | /// libraries for `target`, and this method will find them in the relevant | |
257 | /// output directory. | |
9fa01778 | 258 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
259 | let compiler = self.compiler; |
260 | let target_compiler = self.target_compiler; | |
261 | let target = self.target; | |
83c7162d | 262 | builder.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})", |
3b2f2976 XL |
263 | target_compiler.stage, |
264 | compiler.stage, | |
265 | &compiler.host, | |
266 | target_compiler.host, | |
83c7162d | 267 | target)); |
3b2f2976 | 268 | let libdir = builder.sysroot_libdir(target_compiler, target); |
532ac7d7 XL |
269 | let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); |
270 | add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); | |
3b2f2976 | 271 | |
83c7162d | 272 | if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { |
3b2f2976 XL |
273 | // The sanitizers are only built in stage1 or above, so the dylibs will |
274 | // be missing in stage0 and causes panic. See the `std()` function above | |
275 | // for reason why the sanitizers are not built in stage0. | |
83c7162d | 276 | copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir); |
3b2f2976 XL |
277 | } |
278 | ||
b7449926 | 279 | builder.cargo(target_compiler, Mode::ToolStd, target, "clean"); |
54a0048b | 280 | } |
7453a54e SL |
281 | } |
282 | ||
9fa01778 XL |
283 | fn copy_apple_sanitizer_dylibs( |
284 | builder: &Builder<'_>, | |
285 | native_dir: &Path, | |
286 | platform: &str, | |
287 | into: &Path, | |
288 | ) { | |
7cac9316 | 289 | for &sanitizer in &["asan", "tsan"] { |
0bf4aa26 | 290 | let filename = format!("lib__rustc__clang_rt.{}_{}_dynamic.dylib", sanitizer, platform); |
7cac9316 XL |
291 | let mut src_path = native_dir.join(sanitizer); |
292 | src_path.push("build"); | |
293 | src_path.push("lib"); | |
294 | src_path.push("darwin"); | |
295 | src_path.push(&filename); | |
83c7162d | 296 | builder.copy(&src_path, &into.join(filename)); |
7cac9316 XL |
297 | } |
298 | } | |
299 | ||
3b2f2976 XL |
300 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
301 | pub struct StartupObjects { | |
302 | pub compiler: Compiler, | |
303 | pub target: Interned<String>, | |
304 | } | |
305 | ||
306 | impl Step for StartupObjects { | |
307 | type Output = (); | |
308 | ||
9fa01778 | 309 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
310 | run.path("src/rtstartup") |
311 | } | |
312 | ||
9fa01778 | 313 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
314 | run.builder.ensure(StartupObjects { |
315 | compiler: run.builder.compiler(run.builder.top_stage, run.host), | |
316 | target: run.target, | |
317 | }); | |
318 | } | |
319 | ||
9fa01778 | 320 | /// Builds and prepare startup objects like rsbegin.o and rsend.o |
3b2f2976 XL |
321 | /// |
322 | /// These are primarily used on Windows right now for linking executables/dlls. | |
323 | /// They don't require any library support as they're just plain old object | |
324 | /// files, so we just use the nightly snapshot compiler to always build them (as | |
325 | /// no other compilers are guaranteed to be available). | |
9fa01778 | 326 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
327 | let for_compiler = self.compiler; |
328 | let target = self.target; | |
329 | if !target.contains("pc-windows-gnu") { | |
330 | return | |
8bb4bdeb | 331 | } |
7453a54e | 332 | |
83c7162d XL |
333 | let src_dir = &builder.src.join("src/rtstartup"); |
334 | let dst_dir = &builder.native_dir(target).join("rtstartup"); | |
3b2f2976 XL |
335 | let sysroot_dir = &builder.sysroot_libdir(for_compiler, target); |
336 | t!(fs::create_dir_all(dst_dir)); | |
337 | ||
338 | for file in &["rsbegin", "rsend"] { | |
339 | let src_file = &src_dir.join(file.to_string() + ".rs"); | |
340 | let dst_file = &dst_dir.join(file.to_string() + ".o"); | |
341 | if !up_to_date(src_file, dst_file) { | |
83c7162d XL |
342 | let mut cmd = Command::new(&builder.initial_rustc); |
343 | builder.run(cmd.env("RUSTC_BOOTSTRAP", "1") | |
dc9dc135 | 344 | .arg("--cfg").arg("bootstrap") |
3b2f2976 XL |
345 | .arg("--target").arg(target) |
346 | .arg("--emit=obj") | |
347 | .arg("-o").arg(dst_file) | |
348 | .arg(src_file)); | |
349 | } | |
350 | ||
83c7162d | 351 | builder.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o")); |
3b2f2976 XL |
352 | } |
353 | ||
354 | for obj in ["crt2.o", "dllcrt2.o"].iter() { | |
83c7162d XL |
355 | let src = compiler_file(builder, |
356 | builder.cc(target), | |
2c00a5a8 XL |
357 | target, |
358 | obj); | |
83c7162d | 359 | builder.copy(&src, &sysroot_dir.join(obj)); |
3b2f2976 | 360 | } |
7453a54e | 361 | } |
3b2f2976 XL |
362 | } |
363 | ||
83c7162d | 364 | #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] |
3b2f2976 | 365 | pub struct Test { |
3b2f2976 | 366 | pub target: Interned<String>, |
83c7162d | 367 | pub compiler: Compiler, |
3b2f2976 | 368 | } |
7453a54e | 369 | |
3b2f2976 XL |
370 | impl Step for Test { |
371 | type Output = (); | |
372 | const DEFAULT: bool = true; | |
373 | ||
9fa01778 | 374 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
2c00a5a8 | 375 | run.all_krates("test") |
3b2f2976 XL |
376 | } |
377 | ||
9fa01778 | 378 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
379 | run.builder.ensure(Test { |
380 | compiler: run.builder.compiler(run.builder.top_stage, run.host), | |
381 | target: run.target, | |
382 | }); | |
383 | } | |
384 | ||
9fa01778 | 385 | /// Builds libtest. |
3b2f2976 XL |
386 | /// |
387 | /// This will build libtest and supporting libraries for a particular stage of | |
388 | /// the build using the `compiler` targeting the `target` architecture. The | |
389 | /// artifacts created will also be linked into the sysroot directory. | |
9fa01778 | 390 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
391 | let target = self.target; |
392 | let compiler = self.compiler; | |
393 | ||
394 | builder.ensure(Std { compiler, target }); | |
395 | ||
8faf50e0 XL |
396 | if builder.config.keep_stage.contains(&compiler.stage) { |
397 | builder.info("Warning: Using a potentially old libtest. This may not behave well."); | |
398 | builder.ensure(TestLink { | |
a1dfa0c6 | 399 | compiler, |
8faf50e0 XL |
400 | target_compiler: compiler, |
401 | target, | |
402 | }); | |
403 | return; | |
404 | } | |
405 | ||
dc9dc135 XL |
406 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
407 | if compiler_to_use != compiler { | |
3b2f2976 | 408 | builder.ensure(Test { |
dc9dc135 | 409 | compiler: compiler_to_use, |
3b2f2976 XL |
410 | target, |
411 | }); | |
83c7162d XL |
412 | builder.info( |
413 | &format!("Uplifting stage1 test ({} -> {})", builder.config.build, target)); | |
3b2f2976 | 414 | builder.ensure(TestLink { |
dc9dc135 | 415 | compiler: compiler_to_use, |
3b2f2976 XL |
416 | target_compiler: compiler, |
417 | target, | |
418 | }); | |
419 | return; | |
420 | } | |
421 | ||
94b46f34 | 422 | let mut cargo = builder.cargo(compiler, Mode::Test, target, "build"); |
83c7162d | 423 | test_cargo(builder, &compiler, target, &mut cargo); |
0531ce1d | 424 | |
83c7162d XL |
425 | let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); |
426 | builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, | |
427 | &compiler.host, target)); | |
428 | run_cargo(builder, | |
abe05a73 | 429 | &mut cargo, |
dc9dc135 | 430 | vec![], |
83c7162d | 431 | &libtest_stamp(builder, compiler, target), |
2c00a5a8 | 432 | false); |
3b2f2976 XL |
433 | |
434 | builder.ensure(TestLink { | |
83c7162d | 435 | compiler: builder.compiler(compiler.stage, builder.config.build), |
3b2f2976 XL |
436 | target_compiler: compiler, |
437 | target, | |
438 | }); | |
7453a54e SL |
439 | } |
440 | } | |
441 | ||
3b2f2976 | 442 | /// Same as `std_cargo`, but for libtest |
9fa01778 | 443 | pub fn test_cargo(builder: &Builder<'_>, |
3b2f2976 XL |
444 | _compiler: &Compiler, |
445 | _target: Interned<String>, | |
446 | cargo: &mut Command) { | |
041b39d2 | 447 | if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { |
8bb4bdeb XL |
448 | cargo.env("MACOSX_DEPLOYMENT_TARGET", target); |
449 | } | |
54a0048b | 450 | cargo.arg("--manifest-path") |
83c7162d | 451 | .arg(builder.src.join("src/libtest/Cargo.toml")); |
54a0048b SL |
452 | } |
453 | ||
3b2f2976 XL |
454 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
455 | pub struct TestLink { | |
456 | pub compiler: Compiler, | |
457 | pub target_compiler: Compiler, | |
458 | pub target: Interned<String>, | |
54a0048b SL |
459 | } |
460 | ||
3b2f2976 XL |
461 | impl Step for TestLink { |
462 | type Output = (); | |
463 | ||
9fa01778 | 464 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
465 | run.never() |
466 | } | |
467 | ||
468 | /// Same as `std_link`, only for libtest | |
9fa01778 | 469 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
470 | let compiler = self.compiler; |
471 | let target_compiler = self.target_compiler; | |
472 | let target = self.target; | |
83c7162d | 473 | builder.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})", |
3b2f2976 XL |
474 | target_compiler.stage, |
475 | compiler.stage, | |
476 | &compiler.host, | |
477 | target_compiler.host, | |
83c7162d | 478 | target)); |
532ac7d7 XL |
479 | add_to_sysroot( |
480 | builder, | |
481 | &builder.sysroot_libdir(target_compiler, target), | |
482 | &builder.sysroot_libdir(target_compiler, compiler.host), | |
483 | &libtest_stamp(builder, compiler, target) | |
484 | ); | |
b7449926 XL |
485 | |
486 | builder.cargo(target_compiler, Mode::ToolTest, target, "clean"); | |
3b2f2976 XL |
487 | } |
488 | } | |
489 | ||
83c7162d | 490 | #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] |
3b2f2976 | 491 | pub struct Rustc { |
3b2f2976 | 492 | pub target: Interned<String>, |
83c7162d | 493 | pub compiler: Compiler, |
3b2f2976 XL |
494 | } |
495 | ||
496 | impl Step for Rustc { | |
497 | type Output = (); | |
498 | const ONLY_HOSTS: bool = true; | |
499 | const DEFAULT: bool = true; | |
500 | ||
9fa01778 | 501 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
2c00a5a8 | 502 | run.all_krates("rustc-main") |
3b2f2976 XL |
503 | } |
504 | ||
9fa01778 | 505 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
506 | run.builder.ensure(Rustc { |
507 | compiler: run.builder.compiler(run.builder.top_stage, run.host), | |
508 | target: run.target, | |
509 | }); | |
510 | } | |
511 | ||
9fa01778 | 512 | /// Builds the compiler. |
3b2f2976 XL |
513 | /// |
514 | /// This will build the compiler for a particular stage of the build using | |
515 | /// the `compiler` targeting the `target` architecture. The artifacts | |
516 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 517 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
518 | let compiler = self.compiler; |
519 | let target = self.target; | |
520 | ||
521 | builder.ensure(Test { compiler, target }); | |
522 | ||
8faf50e0 XL |
523 | if builder.config.keep_stage.contains(&compiler.stage) { |
524 | builder.info("Warning: Using a potentially old librustc. This may not behave well."); | |
525 | builder.ensure(RustcLink { | |
a1dfa0c6 | 526 | compiler, |
8faf50e0 XL |
527 | target_compiler: compiler, |
528 | target, | |
529 | }); | |
530 | return; | |
531 | } | |
532 | ||
dc9dc135 XL |
533 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
534 | if compiler_to_use != compiler { | |
3b2f2976 | 535 | builder.ensure(Rustc { |
dc9dc135 | 536 | compiler: compiler_to_use, |
3b2f2976 XL |
537 | target, |
538 | }); | |
83c7162d XL |
539 | builder.info(&format!("Uplifting stage1 rustc ({} -> {})", |
540 | builder.config.build, target)); | |
3b2f2976 | 541 | builder.ensure(RustcLink { |
dc9dc135 | 542 | compiler: compiler_to_use, |
3b2f2976 XL |
543 | target_compiler: compiler, |
544 | target, | |
545 | }); | |
546 | return; | |
547 | } | |
548 | ||
532ac7d7 XL |
549 | // Ensure that build scripts and proc macros have a std / libproc_macro to link against. |
550 | builder.ensure(Test { | |
83c7162d XL |
551 | compiler: builder.compiler(self.compiler.stage, builder.config.build), |
552 | target: builder.config.build, | |
3b2f2976 | 553 | }); |
0531ce1d | 554 | |
94b46f34 | 555 | let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build"); |
83c7162d | 556 | rustc_cargo(builder, &mut cargo); |
3b2f2976 | 557 | |
83c7162d XL |
558 | let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); |
559 | builder.info(&format!("Building stage{} compiler artifacts ({} -> {})", | |
560 | compiler.stage, &compiler.host, target)); | |
561 | run_cargo(builder, | |
3b2f2976 | 562 | &mut cargo, |
dc9dc135 | 563 | vec![], |
83c7162d | 564 | &librustc_stamp(builder, compiler, target), |
2c00a5a8 | 565 | false); |
3b2f2976 XL |
566 | |
567 | builder.ensure(RustcLink { | |
83c7162d | 568 | compiler: builder.compiler(compiler.stage, builder.config.build), |
3b2f2976 XL |
569 | target_compiler: compiler, |
570 | target, | |
571 | }); | |
572 | } | |
573 | } | |
574 | ||
9fa01778 | 575 | pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Command) { |
83c7162d | 576 | cargo.arg("--features").arg(builder.rustc_features()) |
7453a54e | 577 | .arg("--manifest-path") |
83c7162d XL |
578 | .arg(builder.src.join("src/rustc/Cargo.toml")); |
579 | rustc_cargo_env(builder, cargo); | |
2c00a5a8 | 580 | } |
7453a54e | 581 | |
9fa01778 | 582 | pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Command) { |
7453a54e SL |
583 | // Set some configuration variables picked up by build scripts and |
584 | // the compiler alike | |
83c7162d XL |
585 | cargo.env("CFG_RELEASE", builder.rust_release()) |
586 | .env("CFG_RELEASE_CHANNEL", &builder.config.channel) | |
587 | .env("CFG_VERSION", builder.rust_version()) | |
588 | .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default()) | |
589 | .env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir); | |
32a655c1 | 590 | |
83c7162d | 591 | let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib")); |
2c00a5a8 | 592 | cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); |
7453a54e | 593 | |
83c7162d | 594 | if let Some(ref ver_date) = builder.rust_info.commit_date() { |
7453a54e SL |
595 | cargo.env("CFG_VER_DATE", ver_date); |
596 | } | |
83c7162d | 597 | if let Some(ref ver_hash) = builder.rust_info.sha() { |
7453a54e SL |
598 | cargo.env("CFG_VER_HASH", ver_hash); |
599 | } | |
83c7162d | 600 | if !builder.unstable_features() { |
7453a54e SL |
601 | cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); |
602 | } | |
83c7162d | 603 | if let Some(ref s) = builder.config.rustc_default_linker { |
7453a54e SL |
604 | cargo.env("CFG_DEFAULT_LINKER", s); |
605 | } | |
9fa01778 XL |
606 | if builder.config.rustc_parallel { |
607 | cargo.env("RUSTC_PARALLEL_COMPILER", "1"); | |
ff7c6d11 | 608 | } |
0bf4aa26 XL |
609 | if builder.config.rust_verify_llvm_ir { |
610 | cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); | |
611 | } | |
7453a54e SL |
612 | } |
613 | ||
3b2f2976 XL |
614 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
615 | struct RustcLink { | |
616 | pub compiler: Compiler, | |
617 | pub target_compiler: Compiler, | |
618 | pub target: Interned<String>, | |
619 | } | |
620 | ||
621 | impl Step for RustcLink { | |
622 | type Output = (); | |
623 | ||
9fa01778 | 624 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
625 | run.never() |
626 | } | |
627 | ||
628 | /// Same as `std_link`, only for librustc | |
9fa01778 | 629 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
630 | let compiler = self.compiler; |
631 | let target_compiler = self.target_compiler; | |
632 | let target = self.target; | |
83c7162d | 633 | builder.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})", |
3b2f2976 XL |
634 | target_compiler.stage, |
635 | compiler.stage, | |
636 | &compiler.host, | |
637 | target_compiler.host, | |
83c7162d | 638 | target)); |
532ac7d7 XL |
639 | add_to_sysroot( |
640 | builder, | |
641 | &builder.sysroot_libdir(target_compiler, target), | |
642 | &builder.sysroot_libdir(target_compiler, compiler.host), | |
643 | &librustc_stamp(builder, compiler, target) | |
644 | ); | |
b7449926 | 645 | builder.cargo(target_compiler, Mode::ToolRustc, target, "clean"); |
3b2f2976 | 646 | } |
7453a54e SL |
647 | } |
648 | ||
2c00a5a8 XL |
649 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
650 | pub struct CodegenBackend { | |
651 | pub compiler: Compiler, | |
652 | pub target: Interned<String>, | |
653 | pub backend: Interned<String>, | |
654 | } | |
655 | ||
656 | impl Step for CodegenBackend { | |
657 | type Output = (); | |
658 | const ONLY_HOSTS: bool = true; | |
659 | const DEFAULT: bool = true; | |
660 | ||
9fa01778 | 661 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
94b46f34 | 662 | run.all_krates("rustc_codegen_llvm") |
2c00a5a8 XL |
663 | } |
664 | ||
9fa01778 | 665 | fn make_run(run: RunConfig<'_>) { |
2c00a5a8 XL |
666 | let backend = run.builder.config.rust_codegen_backends.get(0); |
667 | let backend = backend.cloned().unwrap_or_else(|| { | |
668 | INTERNER.intern_str("llvm") | |
669 | }); | |
670 | run.builder.ensure(CodegenBackend { | |
671 | compiler: run.builder.compiler(run.builder.top_stage, run.host), | |
672 | target: run.target, | |
83c7162d | 673 | backend, |
2c00a5a8 XL |
674 | }); |
675 | } | |
676 | ||
9fa01778 | 677 | fn run(self, builder: &Builder<'_>) { |
2c00a5a8 XL |
678 | let compiler = self.compiler; |
679 | let target = self.target; | |
83c7162d | 680 | let backend = self.backend; |
2c00a5a8 XL |
681 | |
682 | builder.ensure(Rustc { compiler, target }); | |
683 | ||
8faf50e0 XL |
684 | if builder.config.keep_stage.contains(&compiler.stage) { |
685 | builder.info("Warning: Using a potentially old codegen backend. \ | |
686 | This may not behave well."); | |
687 | // Codegen backends are linked separately from this step today, so we don't do | |
688 | // anything here. | |
689 | return; | |
690 | } | |
691 | ||
dc9dc135 XL |
692 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
693 | if compiler_to_use != compiler { | |
2c00a5a8 | 694 | builder.ensure(CodegenBackend { |
dc9dc135 | 695 | compiler: compiler_to_use, |
2c00a5a8 | 696 | target, |
83c7162d | 697 | backend, |
2c00a5a8 XL |
698 | }); |
699 | return; | |
700 | } | |
701 | ||
b7449926 XL |
702 | let out_dir = builder.cargo_out(compiler, Mode::Codegen, target); |
703 | ||
0731742a | 704 | let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build"); |
2c00a5a8 | 705 | cargo.arg("--manifest-path") |
94b46f34 | 706 | .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); |
83c7162d | 707 | rustc_cargo_env(builder, &mut cargo); |
2c00a5a8 | 708 | |
b7449926 XL |
709 | let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); |
710 | ||
b7449926 | 711 | let tmp_stamp = out_dir.join(".tmp.stamp"); |
0531ce1d | 712 | |
94b46f34 | 713 | let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); |
83c7162d | 714 | let files = run_cargo(builder, |
2c00a5a8 | 715 | cargo.arg("--features").arg(features), |
dc9dc135 | 716 | vec![], |
2c00a5a8 XL |
717 | &tmp_stamp, |
718 | false); | |
83c7162d XL |
719 | if builder.config.dry_run { |
720 | return; | |
721 | } | |
2c00a5a8 XL |
722 | let mut files = files.into_iter() |
723 | .filter(|f| { | |
724 | let filename = f.file_name().unwrap().to_str().unwrap(); | |
94b46f34 | 725 | is_dylib(filename) && filename.contains("rustc_codegen_llvm-") |
2c00a5a8 XL |
726 | }); |
727 | let codegen_backend = match files.next() { | |
728 | Some(f) => f, | |
729 | None => panic!("no dylibs built for codegen backend?"), | |
730 | }; | |
731 | if let Some(f) = files.next() { | |
732 | panic!("codegen backend built two dylibs:\n{}\n{}", | |
733 | codegen_backend.display(), | |
734 | f.display()); | |
735 | } | |
83c7162d | 736 | let stamp = codegen_backend_stamp(builder, compiler, target, backend); |
2c00a5a8 | 737 | let codegen_backend = codegen_backend.to_str().unwrap(); |
0731742a | 738 | t!(fs::write(&stamp, &codegen_backend)); |
2c00a5a8 XL |
739 | } |
740 | } | |
741 | ||
9fa01778 | 742 | pub fn build_codegen_backend(builder: &Builder<'_>, |
83c7162d XL |
743 | cargo: &mut Command, |
744 | compiler: &Compiler, | |
745 | target: Interned<String>, | |
746 | backend: Interned<String>) -> String { | |
747 | let mut features = String::new(); | |
748 | ||
749 | match &*backend { | |
750 | "llvm" | "emscripten" => { | |
751 | // Build LLVM for our target. This will implicitly build the | |
752 | // host LLVM if necessary. | |
753 | let llvm_config = builder.ensure(native::Llvm { | |
754 | target, | |
755 | emscripten: backend == "emscripten", | |
756 | }); | |
757 | ||
758 | if backend == "emscripten" { | |
759 | features.push_str(" emscripten"); | |
760 | } | |
761 | ||
762 | builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})", | |
763 | compiler.stage, &compiler.host, target, backend)); | |
764 | ||
765 | // Pass down configuration from the LLVM build into the build of | |
94b46f34 | 766 | // librustc_llvm and librustc_codegen_llvm. |
a1dfa0c6 | 767 | if builder.is_rust_llvm(target) && backend != "emscripten" { |
83c7162d XL |
768 | cargo.env("LLVM_RUSTLLVM", "1"); |
769 | } | |
9fa01778 | 770 | |
83c7162d XL |
771 | cargo.env("LLVM_CONFIG", &llvm_config); |
772 | if backend != "emscripten" { | |
773 | let target_config = builder.config.target_config.get(&target); | |
774 | if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { | |
775 | cargo.env("CFG_LLVM_ROOT", s); | |
776 | } | |
777 | } | |
dc9dc135 XL |
778 | // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. |
779 | if let Some(ref s) = builder.config.llvm_ldflags { | |
780 | cargo.env("LLVM_LINKER_FLAGS", s); | |
781 | } | |
83c7162d XL |
782 | // Building with a static libstdc++ is only supported on linux right now, |
783 | // not for MSVC or macOS | |
784 | if builder.config.llvm_static_stdcpp && | |
785 | !target.contains("freebsd") && | |
786 | !target.contains("windows") && | |
787 | !target.contains("apple") { | |
788 | let file = compiler_file(builder, | |
789 | builder.cxx(target).unwrap(), | |
790 | target, | |
791 | "libstdc++.a"); | |
792 | cargo.env("LLVM_STATIC_STDCPP", file); | |
793 | } | |
0731742a XL |
794 | if builder.config.llvm_link_shared || |
795 | (builder.config.llvm_thin_lto && backend != "emscripten") | |
796 | { | |
83c7162d XL |
797 | cargo.env("LLVM_LINK_SHARED", "1"); |
798 | } | |
0731742a XL |
799 | if builder.config.llvm_use_libcxx { |
800 | cargo.env("LLVM_USE_LIBCXX", "1"); | |
801 | } | |
83c7162d XL |
802 | } |
803 | _ => panic!("unknown backend: {}", backend), | |
804 | } | |
805 | ||
806 | features | |
807 | } | |
808 | ||
2c00a5a8 XL |
809 | /// Creates the `codegen-backends` folder for a compiler that's about to be |
810 | /// assembled as a complete compiler. | |
811 | /// | |
812 | /// This will take the codegen artifacts produced by `compiler` and link them | |
813 | /// into an appropriate location for `target_compiler` to be a functional | |
814 | /// compiler. | |
9fa01778 | 815 | fn copy_codegen_backends_to_sysroot(builder: &Builder<'_>, |
2c00a5a8 XL |
816 | compiler: Compiler, |
817 | target_compiler: Compiler) { | |
2c00a5a8 XL |
818 | let target = target_compiler.host; |
819 | ||
820 | // Note that this step is different than all the other `*Link` steps in | |
821 | // that it's not assembling a bunch of libraries but rather is primarily | |
822 | // moving the codegen backend into place. The codegen backend of rustc is | |
823 | // not linked into the main compiler by default but is rather dynamically | |
824 | // selected at runtime for inclusion. | |
825 | // | |
826 | // Here we're looking for the output dylib of the `CodegenBackend` step and | |
827 | // we're copying that into the `codegen-backends` folder. | |
828 | let dst = builder.sysroot_codegen_backends(target_compiler); | |
829 | t!(fs::create_dir_all(&dst)); | |
830 | ||
83c7162d XL |
831 | if builder.config.dry_run { |
832 | return; | |
833 | } | |
834 | ||
2c00a5a8 | 835 | for backend in builder.config.rust_codegen_backends.iter() { |
83c7162d | 836 | let stamp = codegen_backend_stamp(builder, compiler, target, *backend); |
0731742a | 837 | let dylib = t!(fs::read_to_string(&stamp)); |
2c00a5a8 XL |
838 | let file = Path::new(&dylib); |
839 | let filename = file.file_name().unwrap().to_str().unwrap(); | |
94b46f34 | 840 | // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so` |
2c00a5a8 | 841 | let target_filename = { |
a1dfa0c6 XL |
842 | let dash = filename.find('-').unwrap(); |
843 | let dot = filename.find('.').unwrap(); | |
2c00a5a8 XL |
844 | format!("{}-{}{}", |
845 | &filename[..dash], | |
846 | backend, | |
847 | &filename[dot..]) | |
848 | }; | |
83c7162d | 849 | builder.copy(&file, &dst.join(target_filename)); |
2c00a5a8 XL |
850 | } |
851 | } | |
852 | ||
9fa01778 | 853 | fn copy_lld_to_sysroot(builder: &Builder<'_>, |
0531ce1d XL |
854 | target_compiler: Compiler, |
855 | lld_install_root: &Path) { | |
856 | let target = target_compiler.host; | |
857 | ||
858 | let dst = builder.sysroot_libdir(target_compiler, target) | |
859 | .parent() | |
860 | .unwrap() | |
861 | .join("bin"); | |
862 | t!(fs::create_dir_all(&dst)); | |
863 | ||
8faf50e0 XL |
864 | let src_exe = exe("lld", &target); |
865 | let dst_exe = exe("rust-lld", &target); | |
866 | // we prepend this bin directory to the user PATH when linking Rust binaries. To | |
867 | // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. | |
868 | builder.copy(&lld_install_root.join("bin").join(&src_exe), &dst.join(&dst_exe)); | |
0531ce1d XL |
869 | } |
870 | ||
7453a54e SL |
871 | /// Cargo's output path for the standard library in a given stage, compiled |
872 | /// by a particular compiler for the specified target. | |
9fa01778 XL |
873 | pub fn libstd_stamp( |
874 | builder: &Builder<'_>, | |
875 | compiler: Compiler, | |
876 | target: Interned<String>, | |
877 | ) -> PathBuf { | |
94b46f34 | 878 | builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") |
7453a54e SL |
879 | } |
880 | ||
54a0048b SL |
881 | /// Cargo's output path for libtest in a given stage, compiled by a particular |
882 | /// compiler for the specified target. | |
9fa01778 XL |
883 | pub fn libtest_stamp( |
884 | builder: &Builder<'_>, | |
885 | compiler: Compiler, | |
886 | target: Interned<String>, | |
887 | ) -> PathBuf { | |
94b46f34 | 888 | builder.cargo_out(compiler, Mode::Test, target).join(".libtest.stamp") |
54a0048b SL |
889 | } |
890 | ||
cc61c64b XL |
891 | /// Cargo's output path for librustc in a given stage, compiled by a particular |
892 | /// compiler for the specified target. | |
9fa01778 XL |
893 | pub fn librustc_stamp( |
894 | builder: &Builder<'_>, | |
895 | compiler: Compiler, | |
896 | target: Interned<String>, | |
897 | ) -> PathBuf { | |
94b46f34 | 898 | builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp") |
cc61c64b XL |
899 | } |
900 | ||
94b46f34 | 901 | /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular |
83c7162d | 902 | /// compiler for the specified target and backend. |
9fa01778 | 903 | fn codegen_backend_stamp(builder: &Builder<'_>, |
2c00a5a8 XL |
904 | compiler: Compiler, |
905 | target: Interned<String>, | |
906 | backend: Interned<String>) -> PathBuf { | |
94b46f34 XL |
907 | builder.cargo_out(compiler, Mode::Codegen, target) |
908 | .join(format!(".librustc_codegen_llvm-{}.stamp", backend)) | |
2c00a5a8 XL |
909 | } |
910 | ||
9fa01778 XL |
911 | pub fn compiler_file( |
912 | builder: &Builder<'_>, | |
913 | compiler: &Path, | |
914 | target: Interned<String>, | |
915 | file: &str, | |
916 | ) -> PathBuf { | |
2c00a5a8 | 917 | let mut cmd = Command::new(compiler); |
b7449926 | 918 | cmd.args(builder.cflags(target, GitRepo::Rustc)); |
2c00a5a8 XL |
919 | cmd.arg(format!("-print-file-name={}", file)); |
920 | let out = output(&mut cmd); | |
54a0048b | 921 | PathBuf::from(out.trim()) |
7453a54e SL |
922 | } |
923 | ||
3b2f2976 XL |
924 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
925 | pub struct Sysroot { | |
926 | pub compiler: Compiler, | |
32a655c1 SL |
927 | } |
928 | ||
3b2f2976 XL |
929 | impl Step for Sysroot { |
930 | type Output = Interned<PathBuf>; | |
931 | ||
9fa01778 | 932 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 933 | run.never() |
7453a54e SL |
934 | } |
935 | ||
3b2f2976 XL |
936 | /// Returns the sysroot for the `compiler` specified that *this build system |
937 | /// generates*. | |
938 | /// | |
939 | /// That is, the sysroot for the stage0 compiler is not what the compiler | |
940 | /// thinks it is by default, but it's the same as the default for stages | |
941 | /// 1-3. | |
9fa01778 | 942 | fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> { |
3b2f2976 XL |
943 | let compiler = self.compiler; |
944 | let sysroot = if compiler.stage == 0 { | |
83c7162d | 945 | builder.out.join(&compiler.host).join("stage0-sysroot") |
3b2f2976 | 946 | } else { |
83c7162d | 947 | builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage)) |
3b2f2976 XL |
948 | }; |
949 | let _ = fs::remove_dir_all(&sysroot); | |
950 | t!(fs::create_dir_all(&sysroot)); | |
951 | INTERNER.intern_path(sysroot) | |
952 | } | |
953 | } | |
954 | ||
83c7162d | 955 | #[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] |
3b2f2976 XL |
956 | pub struct Assemble { |
957 | /// The compiler which we will produce in this step. Assemble itself will | |
958 | /// take care of ensuring that the necessary prerequisites to do so exist, | |
959 | /// that is, this target can be a stage2 compiler and Assemble will build | |
960 | /// previous stages for you. | |
961 | pub target_compiler: Compiler, | |
962 | } | |
7453a54e | 963 | |
3b2f2976 XL |
964 | impl Step for Assemble { |
965 | type Output = Compiler; | |
7453a54e | 966 | |
9fa01778 | 967 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
8faf50e0 | 968 | run.never() |
3b2f2976 XL |
969 | } |
970 | ||
971 | /// Prepare a new compiler from the artifacts in `stage` | |
972 | /// | |
973 | /// This will assemble a compiler in `build/$host/stage$stage`. The compiler | |
83c7162d | 974 | /// must have been previously produced by the `stage - 1` builder.build |
3b2f2976 | 975 | /// compiler. |
9fa01778 | 976 | fn run(self, builder: &Builder<'_>) -> Compiler { |
3b2f2976 XL |
977 | let target_compiler = self.target_compiler; |
978 | ||
979 | if target_compiler.stage == 0 { | |
83c7162d | 980 | assert_eq!(builder.config.build, target_compiler.host, |
3b2f2976 XL |
981 | "Cannot obtain compiler for non-native build triple at stage 0"); |
982 | // The stage 0 compiler for the build triple is always pre-built. | |
983 | return target_compiler; | |
984 | } | |
985 | ||
986 | // Get the compiler that we'll use to bootstrap ourselves. | |
2c00a5a8 XL |
987 | // |
988 | // Note that this is where the recursive nature of the bootstrap | |
989 | // happens, as this will request the previous stage's compiler on | |
990 | // downwards to stage 0. | |
991 | // | |
992 | // Also note that we're building a compiler for the host platform. We | |
993 | // only assume that we can run `build` artifacts, which means that to | |
994 | // produce some other architecture compiler we need to start from | |
995 | // `build` to get there. | |
996 | // | |
997 | // FIXME: Perhaps we should download those libraries? | |
998 | // It would make builds faster... | |
999 | // | |
1000 | // FIXME: It may be faster if we build just a stage 1 compiler and then | |
1001 | // use that to bootstrap this compiler forward. | |
1002 | let build_compiler = | |
83c7162d | 1003 | builder.compiler(target_compiler.stage - 1, builder.config.build); |
3b2f2976 XL |
1004 | |
1005 | // Build the libraries for this compiler to link to (i.e., the libraries | |
1006 | // it uses at runtime). NOTE: Crates the target compiler compiles don't | |
1007 | // link to these. (FIXME: Is that correct? It seems to be correct most | |
1008 | // of the time but I think we do link to these for stage2/bin compilers | |
1009 | // when not performing a full bootstrap). | |
8faf50e0 XL |
1010 | builder.ensure(Rustc { |
1011 | compiler: build_compiler, | |
1012 | target: target_compiler.host, | |
1013 | }); | |
1014 | for &backend in builder.config.rust_codegen_backends.iter() { | |
1015 | builder.ensure(CodegenBackend { | |
2c00a5a8 XL |
1016 | compiler: build_compiler, |
1017 | target: target_compiler.host, | |
8faf50e0 | 1018 | backend, |
2c00a5a8 | 1019 | }); |
3b2f2976 XL |
1020 | } |
1021 | ||
83c7162d | 1022 | let lld_install = if builder.config.lld_enabled { |
0531ce1d XL |
1023 | Some(builder.ensure(native::Lld { |
1024 | target: target_compiler.host, | |
1025 | })) | |
1026 | } else { | |
1027 | None | |
1028 | }; | |
1029 | ||
3b2f2976 XL |
1030 | let stage = target_compiler.stage; |
1031 | let host = target_compiler.host; | |
83c7162d | 1032 | builder.info(&format!("Assembling stage{} compiler ({})", stage, host)); |
3b2f2976 XL |
1033 | |
1034 | // Link in all dylibs to the libdir | |
1035 | let sysroot = builder.sysroot(target_compiler); | |
532ac7d7 XL |
1036 | let rustc_libdir = builder.rustc_libdir(target_compiler); |
1037 | t!(fs::create_dir_all(&rustc_libdir)); | |
3b2f2976 | 1038 | let src_libdir = builder.sysroot_libdir(build_compiler, host); |
83c7162d | 1039 | for f in builder.read_dir(&src_libdir) { |
3b2f2976 XL |
1040 | let filename = f.file_name().into_string().unwrap(); |
1041 | if is_dylib(&filename) { | |
532ac7d7 | 1042 | builder.copy(&f.path(), &rustc_libdir.join(&filename)); |
3b2f2976 XL |
1043 | } |
1044 | } | |
1045 | ||
2c00a5a8 XL |
1046 | copy_codegen_backends_to_sysroot(builder, |
1047 | build_compiler, | |
1048 | target_compiler); | |
0531ce1d XL |
1049 | if let Some(lld_install) = lld_install { |
1050 | copy_lld_to_sysroot(builder, target_compiler, &lld_install); | |
1051 | } | |
3b2f2976 | 1052 | |
0731742a XL |
1053 | dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot); |
1054 | ||
3b2f2976 | 1055 | // Link the compiler binary itself into place |
94b46f34 XL |
1056 | let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); |
1057 | let rustc = out_dir.join(exe("rustc_binary", &*host)); | |
3b2f2976 XL |
1058 | let bindir = sysroot.join("bin"); |
1059 | t!(fs::create_dir_all(&bindir)); | |
1060 | let compiler = builder.rustc(target_compiler); | |
1061 | let _ = fs::remove_file(&compiler); | |
83c7162d | 1062 | builder.copy(&rustc, &compiler); |
3b2f2976 XL |
1063 | |
1064 | target_compiler | |
7453a54e SL |
1065 | } |
1066 | } | |
1067 | ||
1068 | /// Link some files into a rustc sysroot. | |
1069 | /// | |
7cac9316 XL |
1070 | /// For a particular stage this will link the file listed in `stamp` into the |
1071 | /// `sysroot_dst` provided. | |
532ac7d7 XL |
1072 | pub fn add_to_sysroot( |
1073 | builder: &Builder<'_>, | |
1074 | sysroot_dst: &Path, | |
1075 | sysroot_host_dst: &Path, | |
1076 | stamp: &Path | |
1077 | ) { | |
7cac9316 | 1078 | t!(fs::create_dir_all(&sysroot_dst)); |
532ac7d7 XL |
1079 | t!(fs::create_dir_all(&sysroot_host_dst)); |
1080 | for (path, host) in builder.read_stamp_file(stamp) { | |
1081 | if host { | |
1082 | builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap())); | |
1083 | } else { | |
1084 | builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); | |
1085 | } | |
7453a54e SL |
1086 | } |
1087 | } | |
54a0048b | 1088 | |
9fa01778 | 1089 | pub fn run_cargo(builder: &Builder<'_>, |
b7449926 | 1090 | cargo: &mut Command, |
dc9dc135 | 1091 | tail_args: Vec<String>, |
b7449926 XL |
1092 | stamp: &Path, |
1093 | is_check: bool) | |
2c00a5a8 XL |
1094 | -> Vec<PathBuf> |
1095 | { | |
83c7162d XL |
1096 | if builder.config.dry_run { |
1097 | return Vec::new(); | |
1098 | } | |
1099 | ||
7cac9316 XL |
1100 | // `target_root_dir` looks like $dir/$target/release |
1101 | let target_root_dir = stamp.parent().unwrap(); | |
1102 | // `target_deps_dir` looks like $dir/$target/release/deps | |
1103 | let target_deps_dir = target_root_dir.join("deps"); | |
1104 | // `host_root_dir` looks like $dir/release | |
1105 | let host_root_dir = target_root_dir.parent().unwrap() // chop off `release` | |
1106 | .parent().unwrap() // chop off `$target` | |
1107 | .join(target_root_dir.file_name().unwrap()); | |
1108 | ||
1109 | // Spawn Cargo slurping up its JSON output. We'll start building up the | |
1110 | // `deps` array of all files it generated along with a `toplevel` array of | |
1111 | // files we need to probe for later. | |
1112 | let mut deps = Vec::new(); | |
1113 | let mut toplevel = Vec::new(); | |
dc9dc135 | 1114 | let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { |
532ac7d7 XL |
1115 | let (filenames, crate_types) = match msg { |
1116 | CargoMessage::CompilerArtifact { | |
1117 | filenames, | |
1118 | target: CargoTarget { | |
1119 | crate_types, | |
1120 | }, | |
1121 | .. | |
1122 | } => (filenames, crate_types), | |
dc9dc135 XL |
1123 | CargoMessage::CompilerMessage { message } => { |
1124 | eprintln!("{}", message.rendered); | |
1125 | return; | |
1126 | } | |
0531ce1d | 1127 | _ => return, |
7cac9316 | 1128 | }; |
0531ce1d | 1129 | for filename in filenames { |
7cac9316 XL |
1130 | // Skip files like executables |
1131 | if !filename.ends_with(".rlib") && | |
1132 | !filename.ends_with(".lib") && | |
2c00a5a8 XL |
1133 | !is_dylib(&filename) && |
1134 | !(is_check && filename.ends_with(".rmeta")) { | |
8faf50e0 | 1135 | continue; |
7cac9316 XL |
1136 | } |
1137 | ||
0531ce1d | 1138 | let filename = Path::new(&*filename); |
7cac9316 XL |
1139 | |
1140 | // If this was an output file in the "host dir" we don't actually | |
532ac7d7 | 1141 | // worry about it, it's not relevant for us |
7cac9316 | 1142 | if filename.starts_with(&host_root_dir) { |
532ac7d7 XL |
1143 | // Unless it's a proc macro used in the compiler |
1144 | if crate_types.iter().any(|t| t == "proc-macro") { | |
1145 | deps.push((filename.to_path_buf(), true)); | |
1146 | } | |
8faf50e0 | 1147 | continue; |
041b39d2 | 1148 | } |
7cac9316 XL |
1149 | |
1150 | // If this was output in the `deps` dir then this is a precise file | |
1151 | // name (hash included) so we start tracking it. | |
041b39d2 | 1152 | if filename.starts_with(&target_deps_dir) { |
532ac7d7 | 1153 | deps.push((filename.to_path_buf(), false)); |
8faf50e0 | 1154 | continue; |
041b39d2 | 1155 | } |
7cac9316 XL |
1156 | |
1157 | // Otherwise this was a "top level artifact" which right now doesn't | |
1158 | // have a hash in the name, but there's a version of this file in | |
1159 | // the `deps` folder which *does* have a hash in the name. That's | |
1160 | // the one we'll want to we'll probe for it later. | |
abe05a73 XL |
1161 | // |
1162 | // We do not use `Path::file_stem` or `Path::extension` here, | |
1163 | // because some generated files may have multiple extensions e.g. | |
1164 | // `std-<hash>.dll.lib` on Windows. The aforementioned methods only | |
1165 | // split the file name by the last extension (`.lib`) while we need | |
1166 | // to split by all extensions (`.dll.lib`). | |
1167 | let expected_len = t!(filename.metadata()).len(); | |
1168 | let filename = filename.file_name().unwrap().to_str().unwrap(); | |
1169 | let mut parts = filename.splitn(2, '.'); | |
1170 | let file_stem = parts.next().unwrap().to_owned(); | |
1171 | let extension = parts.next().unwrap().to_owned(); | |
1172 | ||
1173 | toplevel.push((file_stem, extension, expected_len)); | |
7cac9316 | 1174 | } |
0531ce1d | 1175 | }); |
7cac9316 | 1176 | |
0531ce1d | 1177 | if !ok { |
a1dfa0c6 | 1178 | exit(1); |
7cac9316 XL |
1179 | } |
1180 | ||
1181 | // Ok now we need to actually find all the files listed in `toplevel`. We've | |
1182 | // got a list of prefix/extensions and we basically just need to find the | |
1183 | // most recent file in the `deps` folder corresponding to each one. | |
1184 | let contents = t!(target_deps_dir.read_dir()) | |
1185 | .map(|e| t!(e)) | |
1186 | .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata()))) | |
1187 | .collect::<Vec<_>>(); | |
abe05a73 XL |
1188 | for (prefix, extension, expected_len) in toplevel { |
1189 | let candidates = contents.iter().filter(|&&(_, ref filename, ref meta)| { | |
7cac9316 XL |
1190 | filename.starts_with(&prefix[..]) && |
1191 | filename[prefix.len()..].starts_with("-") && | |
abe05a73 XL |
1192 | filename.ends_with(&extension[..]) && |
1193 | meta.len() == expected_len | |
7cac9316 XL |
1194 | }); |
1195 | let max = candidates.max_by_key(|&&(_, _, ref metadata)| { | |
1196 | FileTime::from_last_modification_time(metadata) | |
1197 | }); | |
1198 | let path_to_add = match max { | |
1199 | Some(triple) => triple.0.to_str().unwrap(), | |
1200 | None => panic!("no output generated for {:?} {:?}", prefix, extension), | |
1201 | }; | |
1202 | if is_dylib(path_to_add) { | |
1203 | let candidate = format!("{}.lib", path_to_add); | |
1204 | let candidate = PathBuf::from(candidate); | |
1205 | if candidate.exists() { | |
532ac7d7 | 1206 | deps.push((candidate, false)); |
7cac9316 XL |
1207 | } |
1208 | } | |
532ac7d7 | 1209 | deps.push((path_to_add.into(), false)); |
7cac9316 XL |
1210 | } |
1211 | ||
1212 | // Now we want to update the contents of the stamp file, if necessary. First | |
1213 | // we read off the previous contents along with its mtime. If our new | |
1214 | // contents (the list of files to copy) is different or if any dep's mtime | |
1215 | // is newer then we rewrite the stamp file. | |
1216 | deps.sort(); | |
0731742a | 1217 | let stamp_contents = fs::read(stamp); |
7cac9316 XL |
1218 | let stamp_mtime = mtime(&stamp); |
1219 | let mut new_contents = Vec::new(); | |
1220 | let mut max = None; | |
1221 | let mut max_path = None; | |
532ac7d7 | 1222 | for (dep, proc_macro) in deps.iter() { |
2c00a5a8 | 1223 | let mtime = mtime(dep); |
7cac9316 XL |
1224 | if Some(mtime) > max { |
1225 | max = Some(mtime); | |
1226 | max_path = Some(dep.clone()); | |
1227 | } | |
532ac7d7 | 1228 | new_contents.extend(if *proc_macro { b"h" } else { b"t" }); |
7cac9316 XL |
1229 | new_contents.extend(dep.to_str().unwrap().as_bytes()); |
1230 | new_contents.extend(b"\0"); | |
1231 | } | |
1232 | let max = max.unwrap(); | |
1233 | let max_path = max_path.unwrap(); | |
0731742a XL |
1234 | let contents_equal = stamp_contents |
1235 | .map(|contents| contents == new_contents) | |
1236 | .unwrap_or_default(); | |
1237 | if contents_equal && max <= stamp_mtime { | |
83c7162d | 1238 | builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", |
abe05a73 | 1239 | stamp, max, stamp_mtime)); |
532ac7d7 | 1240 | return deps.into_iter().map(|(d, _)| d).collect() |
7cac9316 XL |
1241 | } |
1242 | if max > stamp_mtime { | |
83c7162d | 1243 | builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); |
7cac9316 | 1244 | } else { |
83c7162d | 1245 | builder.verbose(&format!("updating {:?} as deps changed", stamp)); |
9e0c209e | 1246 | } |
0731742a | 1247 | t!(fs::write(&stamp, &new_contents)); |
532ac7d7 | 1248 | deps.into_iter().map(|(d, _)| d).collect() |
9e0c209e | 1249 | } |
0531ce1d XL |
1250 | |
1251 | pub fn stream_cargo( | |
9fa01778 | 1252 | builder: &Builder<'_>, |
0531ce1d | 1253 | cargo: &mut Command, |
dc9dc135 | 1254 | tail_args: Vec<String>, |
9fa01778 | 1255 | cb: &mut dyn FnMut(CargoMessage<'_>), |
0531ce1d | 1256 | ) -> bool { |
83c7162d XL |
1257 | if builder.config.dry_run { |
1258 | return true; | |
1259 | } | |
0531ce1d XL |
1260 | // Instruct Cargo to give us json messages on stdout, critically leaving |
1261 | // stderr as piped so we can get those pretty colors. | |
1262 | cargo.arg("--message-format").arg("json") | |
1263 | .stdout(Stdio::piped()); | |
1264 | ||
dc9dc135 XL |
1265 | for arg in tail_args { |
1266 | cargo.arg(arg); | |
1267 | } | |
1268 | ||
83c7162d | 1269 | builder.verbose(&format!("running: {:?}", cargo)); |
0531ce1d XL |
1270 | let mut child = match cargo.spawn() { |
1271 | Ok(child) => child, | |
1272 | Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e), | |
1273 | }; | |
1274 | ||
1275 | // Spawn Cargo slurping up its JSON output. We'll start building up the | |
1276 | // `deps` array of all files it generated along with a `toplevel` array of | |
1277 | // files we need to probe for later. | |
1278 | let stdout = BufReader::new(child.stdout.take().unwrap()); | |
1279 | for line in stdout.lines() { | |
1280 | let line = t!(line); | |
9fa01778 | 1281 | match serde_json::from_str::<CargoMessage<'_>>(&line) { |
0531ce1d XL |
1282 | Ok(msg) => cb(msg), |
1283 | // If this was informational, just print it out and continue | |
1284 | Err(_) => println!("{}", line) | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | // Make sure Cargo actually succeeded after we read all of its stdout. | |
1289 | let status = t!(child.wait()); | |
1290 | if !status.success() { | |
83c7162d | 1291 | eprintln!("command did not execute successfully: {:?}\n\ |
0531ce1d XL |
1292 | expected success, got: {}", |
1293 | cargo, | |
1294 | status); | |
1295 | } | |
1296 | status.success() | |
1297 | } | |
1298 | ||
532ac7d7 XL |
1299 | #[derive(Deserialize)] |
1300 | pub struct CargoTarget<'a> { | |
1301 | crate_types: Vec<Cow<'a, str>>, | |
1302 | } | |
1303 | ||
0531ce1d XL |
1304 | #[derive(Deserialize)] |
1305 | #[serde(tag = "reason", rename_all = "kebab-case")] | |
1306 | pub enum CargoMessage<'a> { | |
1307 | CompilerArtifact { | |
1308 | package_id: Cow<'a, str>, | |
1309 | features: Vec<Cow<'a, str>>, | |
1310 | filenames: Vec<Cow<'a, str>>, | |
532ac7d7 | 1311 | target: CargoTarget<'a>, |
0531ce1d XL |
1312 | }, |
1313 | BuildScriptExecuted { | |
1314 | package_id: Cow<'a, str>, | |
dc9dc135 XL |
1315 | }, |
1316 | CompilerMessage { | |
1317 | message: ClippyMessage<'a> | |
0531ce1d XL |
1318 | } |
1319 | } | |
dc9dc135 XL |
1320 | |
1321 | #[derive(Deserialize)] | |
1322 | pub struct ClippyMessage<'a> { | |
1323 | rendered: Cow<'a, str>, | |
1324 | } |