]>
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 | 12 | use std::io::prelude::*; |
dfeec247 | 13 | use std::io::BufReader; |
7453a54e | 14 | use std::path::{Path, PathBuf}; |
dfeec247 | 15 | use std::process::{exit, Command, Stdio}; |
7cac9316 | 16 | use std::str; |
7453a54e | 17 | |
e1599b0c | 18 | use build_helper::{output, t, up_to_date}; |
9e0c209e | 19 | use filetime::FileTime; |
48663c56 | 20 | use serde::Deserialize; |
7453a54e | 21 | |
e1599b0c | 22 | use crate::builder::Cargo; |
f035d41b XL |
23 | use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; |
24 | use crate::cache::{Interned, INTERNER}; | |
3dfed10e | 25 | use crate::config::TargetSelection; |
dfeec247 | 26 | use crate::dist; |
0731742a | 27 | use crate::native; |
f035d41b | 28 | use crate::tool::SourceType; |
ba9703b0 | 29 | use crate::util::{exe, is_dylib, symlink_dir}; |
f035d41b | 30 | use crate::{Compiler, DependencyType, GitRepo, Mode}; |
3b2f2976 | 31 | |
83c7162d | 32 | #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] |
3b2f2976 | 33 | pub struct Std { |
3dfed10e | 34 | pub target: TargetSelection, |
3b2f2976 XL |
35 | pub compiler: Compiler, |
36 | } | |
37 | ||
38 | impl Step for Std { | |
39 | type Output = (); | |
40 | const DEFAULT: bool = true; | |
41 | ||
9fa01778 | 42 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
e1599b0c | 43 | run.all_krates("test") |
3b2f2976 XL |
44 | } |
45 | ||
9fa01778 | 46 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 47 | run.builder.ensure(Std { |
1b1a35ee | 48 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), |
3b2f2976 XL |
49 | target: run.target, |
50 | }); | |
51 | } | |
52 | ||
9fa01778 | 53 | /// Builds the standard library. |
3b2f2976 XL |
54 | /// |
55 | /// This will build the standard library for a particular stage of the build | |
56 | /// using the `compiler` targeting the `target` architecture. The artifacts | |
57 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 58 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
59 | let target = self.target; |
60 | let compiler = self.compiler; | |
61 | ||
1b1a35ee XL |
62 | if builder.config.keep_stage.contains(&compiler.stage) |
63 | || builder.config.keep_stage_std.contains(&compiler.stage) | |
64 | { | |
8faf50e0 | 65 | builder.info("Warning: Using a potentially old libstd. This may not behave well."); |
dfeec247 | 66 | builder.ensure(StdLink { compiler, target_compiler: compiler, target }); |
8faf50e0 XL |
67 | return; |
68 | } | |
69 | ||
e74abb32 | 70 | let mut target_deps = builder.ensure(StartupObjects { compiler, target }); |
3b2f2976 | 71 | |
dc9dc135 XL |
72 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
73 | if compiler_to_use != compiler { | |
dfeec247 | 74 | builder.ensure(Std { compiler: compiler_to_use, target }); |
dc9dc135 | 75 | builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target)); |
3b2f2976 XL |
76 | |
77 | // Even if we're not building std this stage, the new sysroot must | |
0731742a XL |
78 | // still contain the third party objects needed by various targets. |
79 | copy_third_party_objects(builder, &compiler, target); | |
f035d41b | 80 | copy_self_contained_objects(builder, &compiler, target); |
3b2f2976 XL |
81 | |
82 | builder.ensure(StdLink { | |
dc9dc135 | 83 | compiler: compiler_to_use, |
3b2f2976 XL |
84 | target_compiler: compiler, |
85 | target, | |
86 | }); | |
87 | return; | |
88 | } | |
89 | ||
f035d41b XL |
90 | target_deps.extend(copy_third_party_objects(builder, &compiler, target)); |
91 | target_deps.extend(copy_self_contained_objects(builder, &compiler, target)); | |
3b2f2976 | 92 | |
f035d41b | 93 | let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build"); |
f9f354fc | 94 | std_cargo(builder, target, compiler.stage, &mut cargo); |
0531ce1d | 95 | |
dfeec247 XL |
96 | builder.info(&format!( |
97 | "Building stage{} std artifacts ({} -> {})", | |
98 | compiler.stage, &compiler.host, target | |
99 | )); | |
100 | run_cargo( | |
101 | builder, | |
102 | cargo, | |
103 | vec![], | |
104 | &libstd_stamp(builder, compiler, target), | |
105 | target_deps, | |
106 | false, | |
107 | ); | |
3b2f2976 XL |
108 | |
109 | builder.ensure(StdLink { | |
83c7162d | 110 | compiler: builder.compiler(compiler.stage, builder.config.build), |
3b2f2976 XL |
111 | target_compiler: compiler, |
112 | target, | |
113 | }); | |
114 | } | |
115 | } | |
116 | ||
f035d41b XL |
117 | fn copy_and_stamp( |
118 | builder: &Builder<'_>, | |
119 | libdir: &Path, | |
120 | sourcedir: &Path, | |
121 | name: &str, | |
122 | target_deps: &mut Vec<(PathBuf, DependencyType)>, | |
123 | dependency_type: DependencyType, | |
124 | ) { | |
125 | let target = libdir.join(name); | |
126 | builder.copy(&sourcedir.join(name), &target); | |
127 | ||
128 | target_deps.push((target, dependency_type)); | |
129 | } | |
130 | ||
60c5eb7d | 131 | /// Copies third party objects needed by various targets. |
dfeec247 XL |
132 | fn copy_third_party_objects( |
133 | builder: &Builder<'_>, | |
134 | compiler: &Compiler, | |
3dfed10e | 135 | target: TargetSelection, |
f035d41b | 136 | ) -> Vec<(PathBuf, DependencyType)> { |
e74abb32 XL |
137 | let mut target_deps = vec![]; |
138 | ||
f035d41b XL |
139 | // FIXME: remove this in 2021 |
140 | if target == "x86_64-fortanix-unknown-sgx" { | |
141 | if env::var_os("X86_FORTANIX_SGX_LIBS").is_some() { | |
142 | builder.info("Warning: X86_FORTANIX_SGX_LIBS environment variable is ignored, libunwind is now compiled as part of rustbuild"); | |
143 | } | |
144 | } | |
145 | ||
146 | if builder.config.sanitizers && compiler.stage != 0 { | |
147 | // The sanitizers are only copied in stage1 or above, | |
148 | // to avoid creating dependency on LLVM. | |
149 | target_deps.extend( | |
150 | copy_sanitizers(builder, &compiler, target) | |
151 | .into_iter() | |
152 | .map(|d| (d, DependencyType::Target)), | |
153 | ); | |
154 | } | |
155 | ||
156 | target_deps | |
157 | } | |
158 | ||
159 | /// Copies third party objects needed by various targets for self-contained linkage. | |
160 | fn copy_self_contained_objects( | |
161 | builder: &Builder<'_>, | |
162 | compiler: &Compiler, | |
3dfed10e | 163 | target: TargetSelection, |
f035d41b | 164 | ) -> Vec<(PathBuf, DependencyType)> { |
3dfed10e | 165 | let libdir_self_contained = builder.sysroot_libdir(*compiler, target).join("self-contained"); |
f035d41b XL |
166 | t!(fs::create_dir_all(&libdir_self_contained)); |
167 | let mut target_deps = vec![]; | |
e74abb32 | 168 | |
f9f354fc | 169 | // Copies the CRT objects. |
0731742a | 170 | // |
f9f354fc XL |
171 | // rustc historically provides a more self-contained installation for musl targets |
172 | // not requiring the presence of a native musl toolchain. For example, it can fall back | |
173 | // to using gcc from a glibc-targeting toolchain for linking. | |
174 | // To do that we have to distribute musl startup objects as a part of Rust toolchain | |
175 | // and link with them manually in the self-contained mode. | |
0731742a | 176 | if target.contains("musl") { |
f035d41b | 177 | let srcdir = builder.musl_libdir(target).unwrap(); |
f9f354fc | 178 | for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { |
f035d41b XL |
179 | copy_and_stamp( |
180 | builder, | |
181 | &libdir_self_contained, | |
182 | &srcdir, | |
183 | obj, | |
184 | &mut target_deps, | |
185 | DependencyType::TargetSelfContained, | |
186 | ); | |
0731742a | 187 | } |
532ac7d7 | 188 | } else if target.ends_with("-wasi") { |
e74abb32 | 189 | let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi"); |
f035d41b XL |
190 | copy_and_stamp( |
191 | builder, | |
192 | &libdir_self_contained, | |
193 | &srcdir, | |
194 | "crt1.o", | |
195 | &mut target_deps, | |
196 | DependencyType::TargetSelfContained, | |
197 | ); | |
198 | } else if target.contains("windows-gnu") { | |
199 | for obj in ["crt2.o", "dllcrt2.o"].iter() { | |
200 | let src = compiler_file(builder, builder.cc(target), target, obj); | |
201 | let target = libdir_self_contained.join(obj); | |
202 | builder.copy(&src, &target); | |
203 | target_deps.push((target, DependencyType::TargetSelfContained)); | |
204 | } | |
dfeec247 XL |
205 | } |
206 | ||
e74abb32 | 207 | target_deps |
3b2f2976 XL |
208 | } |
209 | ||
210 | /// Configure cargo to compile the standard library, adding appropriate env vars | |
211 | /// and such. | |
3dfed10e | 212 | pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) { |
041b39d2 | 213 | if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { |
8bb4bdeb XL |
214 | cargo.env("MACOSX_DEPLOYMENT_TARGET", target); |
215 | } | |
216 | ||
dc9dc135 XL |
217 | // Determine if we're going to compile in optimized C intrinsics to |
218 | // the `compiler-builtins` crate. These intrinsics live in LLVM's | |
219 | // `compiler-rt` repository, but our `src/llvm-project` submodule isn't | |
220 | // always checked out, so we need to conditionally look for this. (e.g. if | |
221 | // an external LLVM is used we skip the LLVM submodule checkout). | |
222 | // | |
223 | // Note that this shouldn't affect the correctness of `compiler-builtins`, | |
224 | // but only its speed. Some intrinsics in C haven't been translated to Rust | |
225 | // yet but that's pretty rare. Other intrinsics have optimized | |
226 | // implementations in C which have only had slower versions ported to Rust, | |
227 | // so we favor the C version where we can, but it's not critical. | |
228 | // | |
229 | // If `compiler-rt` is available ensure that the `c` feature of the | |
230 | // `compiler-builtins` crate is enabled and it's configured to learn where | |
231 | // `compiler-rt` is located. | |
232 | let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); | |
233 | let compiler_builtins_c_feature = if compiler_builtins_root.exists() { | |
ba9703b0 XL |
234 | // Note that `libprofiler_builtins/build.rs` also computes this so if |
235 | // you're changing something here please also change that. | |
dc9dc135 XL |
236 | cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); |
237 | " compiler-builtins-c".to_string() | |
238 | } else { | |
239 | String::new() | |
240 | }; | |
241 | ||
83c7162d | 242 | if builder.no_std(target) == Some(true) { |
dc9dc135 XL |
243 | let mut features = "compiler-builtins-mem".to_string(); |
244 | features.push_str(&compiler_builtins_c_feature); | |
245 | ||
83c7162d | 246 | // for no-std targets we only compile a few no_std crates |
0731742a | 247 | cargo |
83c7162d | 248 | .args(&["-p", "alloc"]) |
83c7162d | 249 | .arg("--manifest-path") |
3dfed10e | 250 | .arg(builder.src.join("library/alloc/Cargo.toml")) |
0731742a | 251 | .arg("--features") |
48663c56 | 252 | .arg("compiler-builtins-mem compiler-builtins-c"); |
83c7162d | 253 | } else { |
dc9dc135 XL |
254 | let mut features = builder.std_features(); |
255 | features.push_str(&compiler_builtins_c_feature); | |
8bb4bdeb | 256 | |
dfeec247 XL |
257 | cargo |
258 | .arg("--features") | |
259 | .arg(features) | |
83c7162d | 260 | .arg("--manifest-path") |
3dfed10e | 261 | .arg(builder.src.join("library/test/Cargo.toml")); |
7453a54e | 262 | |
e1599b0c XL |
263 | // Help the libc crate compile by assisting it in finding various |
264 | // sysroot native libraries. | |
83c7162d | 265 | if target.contains("musl") { |
f035d41b XL |
266 | if let Some(p) = builder.musl_libdir(target) { |
267 | let root = format!("native={}", p.to_str().unwrap()); | |
e1599b0c | 268 | cargo.rustflag("-L").rustflag(&root); |
83c7162d | 269 | } |
7453a54e | 270 | } |
532ac7d7 XL |
271 | |
272 | if target.ends_with("-wasi") { | |
273 | if let Some(p) = builder.wasi_root(target) { | |
e1599b0c XL |
274 | let root = format!("native={}/lib/wasm32-wasi", p.to_str().unwrap()); |
275 | cargo.rustflag("-L").rustflag(&root); | |
532ac7d7 XL |
276 | } |
277 | } | |
7453a54e | 278 | } |
f9f354fc XL |
279 | |
280 | // By default, rustc uses `-Cembed-bitcode=yes`, and Cargo overrides that | |
281 | // with `-Cembed-bitcode=no` for non-LTO builds. However, libstd must be | |
282 | // built with bitcode so that the produced rlibs can be used for both LTO | |
283 | // builds (which use bitcode) and non-LTO builds (which use object code). | |
284 | // So we override the override here! | |
285 | // | |
286 | // But we don't bother for the stage 0 compiler because it's never used | |
287 | // with LTO. | |
288 | if stage >= 1 { | |
289 | cargo.rustflag("-Cembed-bitcode=yes"); | |
290 | } | |
f035d41b XL |
291 | |
292 | // By default, rustc does not include unwind tables unless they are required | |
293 | // for a particular target. They are not required by RISC-V targets, but | |
294 | // compiling the standard library with them means that users can get | |
295 | // backtraces without having to recompile the standard library themselves. | |
296 | // | |
297 | // This choice was discussed in https://github.com/rust-lang/rust/pull/69890 | |
298 | if target.contains("riscv") { | |
299 | cargo.rustflag("-Cforce-unwind-tables=yes"); | |
300 | } | |
7453a54e SL |
301 | } |
302 | ||
3b2f2976 XL |
303 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
304 | struct StdLink { | |
305 | pub compiler: Compiler, | |
306 | pub target_compiler: Compiler, | |
3dfed10e | 307 | pub target: TargetSelection, |
54a0048b SL |
308 | } |
309 | ||
3b2f2976 XL |
310 | impl Step for StdLink { |
311 | type Output = (); | |
312 | ||
9fa01778 | 313 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
314 | run.never() |
315 | } | |
316 | ||
317 | /// Link all libstd rlibs/dylibs into the sysroot location. | |
318 | /// | |
a1dfa0c6 | 319 | /// Links those artifacts generated by `compiler` to the `stage` compiler's |
3b2f2976 XL |
320 | /// sysroot for the specified `host` and `target`. |
321 | /// | |
322 | /// Note that this assumes that `compiler` has already generated the libstd | |
323 | /// libraries for `target`, and this method will find them in the relevant | |
324 | /// output directory. | |
9fa01778 | 325 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
326 | let compiler = self.compiler; |
327 | let target_compiler = self.target_compiler; | |
328 | let target = self.target; | |
dfeec247 XL |
329 | builder.info(&format!( |
330 | "Copying stage{} std from stage{} ({} -> {} / {})", | |
331 | target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target | |
332 | )); | |
3b2f2976 | 333 | let libdir = builder.sysroot_libdir(target_compiler, target); |
532ac7d7 XL |
334 | let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); |
335 | add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); | |
54a0048b | 336 | } |
7453a54e SL |
337 | } |
338 | ||
dfeec247 XL |
339 | /// Copies sanitizer runtime libraries into target libdir. |
340 | fn copy_sanitizers( | |
9fa01778 | 341 | builder: &Builder<'_>, |
dfeec247 | 342 | compiler: &Compiler, |
3dfed10e | 343 | target: TargetSelection, |
dfeec247 XL |
344 | ) -> Vec<PathBuf> { |
345 | let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target }); | |
346 | ||
347 | if builder.config.dry_run { | |
348 | return Vec::new(); | |
349 | } | |
350 | ||
351 | let mut target_deps = Vec::new(); | |
352 | let libdir = builder.sysroot_libdir(*compiler, target); | |
353 | ||
354 | for runtime in &runtimes { | |
355 | let dst = libdir.join(&runtime.name); | |
356 | builder.copy(&runtime.path, &dst); | |
357 | ||
358 | if target == "x86_64-apple-darwin" { | |
359 | // Update the library install name reflect the fact it has been renamed. | |
360 | let status = Command::new("install_name_tool") | |
361 | .arg("-id") | |
362 | .arg(format!("@rpath/{}", runtime.name)) | |
363 | .arg(&dst) | |
364 | .status() | |
365 | .expect("failed to execute `install_name_tool`"); | |
366 | assert!(status.success()); | |
367 | } | |
368 | ||
369 | target_deps.push(dst); | |
7cac9316 | 370 | } |
dfeec247 XL |
371 | |
372 | target_deps | |
7cac9316 XL |
373 | } |
374 | ||
3b2f2976 XL |
375 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
376 | pub struct StartupObjects { | |
377 | pub compiler: Compiler, | |
3dfed10e | 378 | pub target: TargetSelection, |
3b2f2976 XL |
379 | } |
380 | ||
381 | impl Step for StartupObjects { | |
f035d41b | 382 | type Output = Vec<(PathBuf, DependencyType)>; |
3b2f2976 | 383 | |
9fa01778 | 384 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3dfed10e | 385 | run.path("library/rtstartup") |
3b2f2976 XL |
386 | } |
387 | ||
9fa01778 | 388 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 389 | run.builder.ensure(StartupObjects { |
1b1a35ee | 390 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), |
3b2f2976 XL |
391 | target: run.target, |
392 | }); | |
393 | } | |
394 | ||
9fa01778 | 395 | /// Builds and prepare startup objects like rsbegin.o and rsend.o |
3b2f2976 XL |
396 | /// |
397 | /// These are primarily used on Windows right now for linking executables/dlls. | |
398 | /// They don't require any library support as they're just plain old object | |
399 | /// files, so we just use the nightly snapshot compiler to always build them (as | |
400 | /// no other compilers are guaranteed to be available). | |
f035d41b | 401 | fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> { |
3b2f2976 XL |
402 | let for_compiler = self.compiler; |
403 | let target = self.target; | |
416331ca | 404 | if !target.contains("windows-gnu") { |
dfeec247 | 405 | return vec![]; |
8bb4bdeb | 406 | } |
7453a54e | 407 | |
e74abb32 XL |
408 | let mut target_deps = vec![]; |
409 | ||
3dfed10e | 410 | let src_dir = &builder.src.join("library").join("rtstartup"); |
83c7162d | 411 | let dst_dir = &builder.native_dir(target).join("rtstartup"); |
3b2f2976 XL |
412 | let sysroot_dir = &builder.sysroot_libdir(for_compiler, target); |
413 | t!(fs::create_dir_all(dst_dir)); | |
414 | ||
415 | for file in &["rsbegin", "rsend"] { | |
416 | let src_file = &src_dir.join(file.to_string() + ".rs"); | |
417 | let dst_file = &dst_dir.join(file.to_string() + ".o"); | |
418 | if !up_to_date(src_file, dst_file) { | |
83c7162d | 419 | let mut cmd = Command::new(&builder.initial_rustc); |
dfeec247 XL |
420 | builder.run( |
421 | cmd.env("RUSTC_BOOTSTRAP", "1") | |
422 | .arg("--cfg") | |
423 | .arg("bootstrap") | |
424 | .arg("--target") | |
3dfed10e | 425 | .arg(target.rustc_target_arg()) |
dfeec247 XL |
426 | .arg("--emit=obj") |
427 | .arg("-o") | |
428 | .arg(dst_file) | |
429 | .arg(src_file), | |
430 | ); | |
3b2f2976 XL |
431 | } |
432 | ||
74b04a01 | 433 | let target = sysroot_dir.join((*file).to_string() + ".o"); |
e74abb32 | 434 | builder.copy(dst_file, &target); |
f035d41b | 435 | target_deps.push((target, DependencyType::Target)); |
3b2f2976 | 436 | } |
e74abb32 XL |
437 | |
438 | target_deps | |
7453a54e | 439 | } |
3b2f2976 XL |
440 | } |
441 | ||
83c7162d | 442 | #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] |
3b2f2976 | 443 | pub struct Rustc { |
3dfed10e | 444 | pub target: TargetSelection, |
83c7162d | 445 | pub compiler: Compiler, |
3b2f2976 XL |
446 | } |
447 | ||
448 | impl Step for Rustc { | |
449 | type Output = (); | |
450 | const ONLY_HOSTS: bool = true; | |
3dfed10e | 451 | const DEFAULT: bool = false; |
3b2f2976 | 452 | |
9fa01778 | 453 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
1b1a35ee | 454 | run.path("compiler/rustc") |
3b2f2976 XL |
455 | } |
456 | ||
9fa01778 | 457 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 458 | run.builder.ensure(Rustc { |
1b1a35ee | 459 | compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), |
3b2f2976 XL |
460 | target: run.target, |
461 | }); | |
462 | } | |
463 | ||
9fa01778 | 464 | /// Builds the compiler. |
3b2f2976 XL |
465 | /// |
466 | /// This will build the compiler for a particular stage of the build using | |
467 | /// the `compiler` targeting the `target` architecture. The artifacts | |
468 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 469 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
470 | let compiler = self.compiler; |
471 | let target = self.target; | |
472 | ||
e1599b0c | 473 | builder.ensure(Std { compiler, target }); |
3b2f2976 | 474 | |
8faf50e0 XL |
475 | if builder.config.keep_stage.contains(&compiler.stage) { |
476 | builder.info("Warning: Using a potentially old librustc. This may not behave well."); | |
1b1a35ee | 477 | builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); |
dfeec247 | 478 | builder.ensure(RustcLink { compiler, target_compiler: compiler, target }); |
8faf50e0 XL |
479 | return; |
480 | } | |
481 | ||
dc9dc135 XL |
482 | let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); |
483 | if compiler_to_use != compiler { | |
dfeec247 XL |
484 | builder.ensure(Rustc { compiler: compiler_to_use, target }); |
485 | builder | |
486 | .info(&format!("Uplifting stage1 rustc ({} -> {})", builder.config.build, target)); | |
3b2f2976 | 487 | builder.ensure(RustcLink { |
dc9dc135 | 488 | compiler: compiler_to_use, |
3b2f2976 XL |
489 | target_compiler: compiler, |
490 | target, | |
491 | }); | |
492 | return; | |
493 | } | |
494 | ||
532ac7d7 | 495 | // Ensure that build scripts and proc macros have a std / libproc_macro to link against. |
e1599b0c | 496 | builder.ensure(Std { |
83c7162d XL |
497 | compiler: builder.compiler(self.compiler.stage, builder.config.build), |
498 | target: builder.config.build, | |
3b2f2976 | 499 | }); |
0531ce1d | 500 | |
f035d41b | 501 | let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build"); |
60c5eb7d | 502 | rustc_cargo(builder, &mut cargo, target); |
3b2f2976 | 503 | |
dfeec247 XL |
504 | builder.info(&format!( |
505 | "Building stage{} compiler artifacts ({} -> {})", | |
506 | compiler.stage, &compiler.host, target | |
507 | )); | |
508 | run_cargo( | |
509 | builder, | |
510 | cargo, | |
511 | vec![], | |
512 | &librustc_stamp(builder, compiler, target), | |
513 | vec![], | |
514 | false, | |
515 | ); | |
3b2f2976 XL |
516 | |
517 | builder.ensure(RustcLink { | |
83c7162d | 518 | compiler: builder.compiler(compiler.stage, builder.config.build), |
3b2f2976 XL |
519 | target_compiler: compiler, |
520 | target, | |
521 | }); | |
522 | } | |
523 | } | |
524 | ||
3dfed10e | 525 | pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { |
dfeec247 XL |
526 | cargo |
527 | .arg("--features") | |
528 | .arg(builder.rustc_features()) | |
529 | .arg("--manifest-path") | |
1b1a35ee | 530 | .arg(builder.src.join("compiler/rustc/Cargo.toml")); |
60c5eb7d | 531 | rustc_cargo_env(builder, cargo, target); |
2c00a5a8 | 532 | } |
7453a54e | 533 | |
3dfed10e | 534 | pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { |
7453a54e SL |
535 | // Set some configuration variables picked up by build scripts and |
536 | // the compiler alike | |
dfeec247 XL |
537 | cargo |
538 | .env("CFG_RELEASE", builder.rust_release()) | |
539 | .env("CFG_RELEASE_CHANNEL", &builder.config.channel) | |
540 | .env("CFG_VERSION", builder.rust_version()) | |
541 | .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default()); | |
32a655c1 | 542 | |
74b04a01 | 543 | let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); |
2c00a5a8 | 544 | cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); |
7453a54e | 545 | |
83c7162d | 546 | if let Some(ref ver_date) = builder.rust_info.commit_date() { |
7453a54e SL |
547 | cargo.env("CFG_VER_DATE", ver_date); |
548 | } | |
83c7162d | 549 | if let Some(ref ver_hash) = builder.rust_info.sha() { |
7453a54e SL |
550 | cargo.env("CFG_VER_HASH", ver_hash); |
551 | } | |
83c7162d | 552 | if !builder.unstable_features() { |
7453a54e SL |
553 | cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); |
554 | } | |
83c7162d | 555 | if let Some(ref s) = builder.config.rustc_default_linker { |
7453a54e SL |
556 | cargo.env("CFG_DEFAULT_LINKER", s); |
557 | } | |
9fa01778 | 558 | if builder.config.rustc_parallel { |
e1599b0c | 559 | cargo.rustflag("--cfg=parallel_compiler"); |
ff7c6d11 | 560 | } |
0bf4aa26 XL |
561 | if builder.config.rust_verify_llvm_ir { |
562 | cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); | |
563 | } | |
60c5eb7d XL |
564 | |
565 | // Pass down configuration from the LLVM build into the build of | |
1b1a35ee | 566 | // rustc_llvm and rustc_codegen_llvm. |
60c5eb7d XL |
567 | // |
568 | // Note that this is disabled if LLVM itself is disabled or we're in a check | |
f9f354fc XL |
569 | // build. If we are in a check build we still go ahead here presuming we've |
570 | // detected that LLVM is alreay built and good to go which helps prevent | |
571 | // busting caches (e.g. like #71152). | |
572 | if builder.config.llvm_enabled() | |
573 | && (builder.kind != Kind::Check | |
574 | || crate::native::prebuilt_llvm_config(builder, target).is_ok()) | |
575 | { | |
60c5eb7d XL |
576 | if builder.is_rust_llvm(target) { |
577 | cargo.env("LLVM_RUSTLLVM", "1"); | |
578 | } | |
579 | let llvm_config = builder.ensure(native::Llvm { target }); | |
580 | cargo.env("LLVM_CONFIG", &llvm_config); | |
581 | let target_config = builder.config.target_config.get(&target); | |
582 | if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { | |
583 | cargo.env("CFG_LLVM_ROOT", s); | |
584 | } | |
1b1a35ee | 585 | // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm. |
60c5eb7d XL |
586 | if let Some(ref s) = builder.config.llvm_ldflags { |
587 | cargo.env("LLVM_LINKER_FLAGS", s); | |
588 | } | |
589 | // Building with a static libstdc++ is only supported on linux right now, | |
590 | // not for MSVC or macOS | |
dfeec247 XL |
591 | if builder.config.llvm_static_stdcpp |
592 | && !target.contains("freebsd") | |
593 | && !target.contains("msvc") | |
594 | && !target.contains("apple") | |
595 | { | |
596 | let file = compiler_file(builder, builder.cxx(target).unwrap(), target, "libstdc++.a"); | |
60c5eb7d XL |
597 | cargo.env("LLVM_STATIC_STDCPP", file); |
598 | } | |
1b1a35ee | 599 | if builder.config.llvm_link_shared { |
60c5eb7d XL |
600 | cargo.env("LLVM_LINK_SHARED", "1"); |
601 | } | |
602 | if builder.config.llvm_use_libcxx { | |
603 | cargo.env("LLVM_USE_LIBCXX", "1"); | |
604 | } | |
605 | if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo { | |
606 | cargo.env("LLVM_NDEBUG", "1"); | |
607 | } | |
608 | } | |
7453a54e SL |
609 | } |
610 | ||
3b2f2976 XL |
611 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
612 | struct RustcLink { | |
613 | pub compiler: Compiler, | |
614 | pub target_compiler: Compiler, | |
3dfed10e | 615 | pub target: TargetSelection, |
3b2f2976 XL |
616 | } |
617 | ||
618 | impl Step for RustcLink { | |
619 | type Output = (); | |
620 | ||
9fa01778 | 621 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
622 | run.never() |
623 | } | |
624 | ||
625 | /// Same as `std_link`, only for librustc | |
9fa01778 | 626 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
627 | let compiler = self.compiler; |
628 | let target_compiler = self.target_compiler; | |
629 | let target = self.target; | |
dfeec247 XL |
630 | builder.info(&format!( |
631 | "Copying stage{} rustc from stage{} ({} -> {} / {})", | |
632 | target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target | |
633 | )); | |
532ac7d7 XL |
634 | add_to_sysroot( |
635 | builder, | |
636 | &builder.sysroot_libdir(target_compiler, target), | |
637 | &builder.sysroot_libdir(target_compiler, compiler.host), | |
dfeec247 | 638 | &librustc_stamp(builder, compiler, target), |
532ac7d7 | 639 | ); |
3b2f2976 | 640 | } |
7453a54e SL |
641 | } |
642 | ||
643 | /// Cargo's output path for the standard library in a given stage, compiled | |
644 | /// by a particular compiler for the specified target. | |
3dfed10e | 645 | pub fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { |
94b46f34 | 646 | builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") |
7453a54e SL |
647 | } |
648 | ||
cc61c64b XL |
649 | /// Cargo's output path for librustc in a given stage, compiled by a particular |
650 | /// compiler for the specified target. | |
9fa01778 XL |
651 | pub fn librustc_stamp( |
652 | builder: &Builder<'_>, | |
653 | compiler: Compiler, | |
3dfed10e | 654 | target: TargetSelection, |
9fa01778 | 655 | ) -> PathBuf { |
94b46f34 | 656 | builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp") |
cc61c64b XL |
657 | } |
658 | ||
9fa01778 XL |
659 | pub fn compiler_file( |
660 | builder: &Builder<'_>, | |
661 | compiler: &Path, | |
3dfed10e | 662 | target: TargetSelection, |
9fa01778 XL |
663 | file: &str, |
664 | ) -> PathBuf { | |
2c00a5a8 | 665 | let mut cmd = Command::new(compiler); |
b7449926 | 666 | cmd.args(builder.cflags(target, GitRepo::Rustc)); |
2c00a5a8 XL |
667 | cmd.arg(format!("-print-file-name={}", file)); |
668 | let out = output(&mut cmd); | |
54a0048b | 669 | PathBuf::from(out.trim()) |
7453a54e SL |
670 | } |
671 | ||
3b2f2976 XL |
672 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
673 | pub struct Sysroot { | |
674 | pub compiler: Compiler, | |
32a655c1 SL |
675 | } |
676 | ||
3b2f2976 XL |
677 | impl Step for Sysroot { |
678 | type Output = Interned<PathBuf>; | |
679 | ||
9fa01778 | 680 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 681 | run.never() |
7453a54e SL |
682 | } |
683 | ||
3b2f2976 XL |
684 | /// Returns the sysroot for the `compiler` specified that *this build system |
685 | /// generates*. | |
686 | /// | |
687 | /// That is, the sysroot for the stage0 compiler is not what the compiler | |
688 | /// thinks it is by default, but it's the same as the default for stages | |
689 | /// 1-3. | |
9fa01778 | 690 | fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> { |
3b2f2976 XL |
691 | let compiler = self.compiler; |
692 | let sysroot = if compiler.stage == 0 { | |
3dfed10e | 693 | builder.out.join(&compiler.host.triple).join("stage0-sysroot") |
3b2f2976 | 694 | } else { |
3dfed10e | 695 | builder.out.join(&compiler.host.triple).join(format!("stage{}", compiler.stage)) |
3b2f2976 XL |
696 | }; |
697 | let _ = fs::remove_dir_all(&sysroot); | |
698 | t!(fs::create_dir_all(&sysroot)); | |
ba9703b0 XL |
699 | |
700 | // Symlink the source root into the same location inside the sysroot, | |
701 | // where `rust-src` component would go (`$sysroot/lib/rustlib/src/rust`), | |
702 | // so that any tools relying on `rust-src` also work for local builds, | |
703 | // and also for translating the virtual `/rustc/$hash` back to the real | |
704 | // directory (for running tests with `rust.remap-debuginfo = true`). | |
705 | let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src"); | |
706 | t!(fs::create_dir_all(&sysroot_lib_rustlib_src)); | |
707 | let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust"); | |
708 | if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) { | |
709 | eprintln!( | |
710 | "warning: creating symbolic link `{}` to `{}` failed with {}", | |
711 | sysroot_lib_rustlib_src_rust.display(), | |
712 | builder.src.display(), | |
713 | e, | |
714 | ); | |
715 | if builder.config.rust_remap_debuginfo { | |
716 | eprintln!( | |
717 | "warning: some `src/test/ui` tests will fail when lacking `{}`", | |
718 | sysroot_lib_rustlib_src_rust.display(), | |
719 | ); | |
720 | } | |
721 | } | |
722 | ||
3b2f2976 XL |
723 | INTERNER.intern_path(sysroot) |
724 | } | |
725 | } | |
726 | ||
83c7162d | 727 | #[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] |
3b2f2976 XL |
728 | pub struct Assemble { |
729 | /// The compiler which we will produce in this step. Assemble itself will | |
730 | /// take care of ensuring that the necessary prerequisites to do so exist, | |
731 | /// that is, this target can be a stage2 compiler and Assemble will build | |
732 | /// previous stages for you. | |
733 | pub target_compiler: Compiler, | |
734 | } | |
7453a54e | 735 | |
3b2f2976 XL |
736 | impl Step for Assemble { |
737 | type Output = Compiler; | |
7453a54e | 738 | |
9fa01778 | 739 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
8faf50e0 | 740 | run.never() |
3b2f2976 XL |
741 | } |
742 | ||
743 | /// Prepare a new compiler from the artifacts in `stage` | |
744 | /// | |
745 | /// This will assemble a compiler in `build/$host/stage$stage`. The compiler | |
83c7162d | 746 | /// must have been previously produced by the `stage - 1` builder.build |
3b2f2976 | 747 | /// compiler. |
9fa01778 | 748 | fn run(self, builder: &Builder<'_>) -> Compiler { |
3b2f2976 XL |
749 | let target_compiler = self.target_compiler; |
750 | ||
751 | if target_compiler.stage == 0 { | |
dfeec247 XL |
752 | assert_eq!( |
753 | builder.config.build, target_compiler.host, | |
754 | "Cannot obtain compiler for non-native build triple at stage 0" | |
755 | ); | |
3b2f2976 XL |
756 | // The stage 0 compiler for the build triple is always pre-built. |
757 | return target_compiler; | |
758 | } | |
759 | ||
760 | // Get the compiler that we'll use to bootstrap ourselves. | |
2c00a5a8 XL |
761 | // |
762 | // Note that this is where the recursive nature of the bootstrap | |
763 | // happens, as this will request the previous stage's compiler on | |
764 | // downwards to stage 0. | |
765 | // | |
766 | // Also note that we're building a compiler for the host platform. We | |
767 | // only assume that we can run `build` artifacts, which means that to | |
768 | // produce some other architecture compiler we need to start from | |
769 | // `build` to get there. | |
770 | // | |
771 | // FIXME: Perhaps we should download those libraries? | |
772 | // It would make builds faster... | |
773 | // | |
774 | // FIXME: It may be faster if we build just a stage 1 compiler and then | |
775 | // use that to bootstrap this compiler forward. | |
dfeec247 | 776 | let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); |
3b2f2976 XL |
777 | |
778 | // Build the libraries for this compiler to link to (i.e., the libraries | |
779 | // it uses at runtime). NOTE: Crates the target compiler compiles don't | |
780 | // link to these. (FIXME: Is that correct? It seems to be correct most | |
781 | // of the time but I think we do link to these for stage2/bin compilers | |
782 | // when not performing a full bootstrap). | |
dfeec247 | 783 | builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host }); |
3b2f2976 | 784 | |
83c7162d | 785 | let lld_install = if builder.config.lld_enabled { |
dfeec247 | 786 | Some(builder.ensure(native::Lld { target: target_compiler.host })) |
0531ce1d XL |
787 | } else { |
788 | None | |
789 | }; | |
790 | ||
3b2f2976 XL |
791 | let stage = target_compiler.stage; |
792 | let host = target_compiler.host; | |
83c7162d | 793 | builder.info(&format!("Assembling stage{} compiler ({})", stage, host)); |
3b2f2976 XL |
794 | |
795 | // Link in all dylibs to the libdir | |
796 | let sysroot = builder.sysroot(target_compiler); | |
532ac7d7 XL |
797 | let rustc_libdir = builder.rustc_libdir(target_compiler); |
798 | t!(fs::create_dir_all(&rustc_libdir)); | |
3b2f2976 | 799 | let src_libdir = builder.sysroot_libdir(build_compiler, host); |
83c7162d | 800 | for f in builder.read_dir(&src_libdir) { |
3b2f2976 XL |
801 | let filename = f.file_name().into_string().unwrap(); |
802 | if is_dylib(&filename) { | |
532ac7d7 | 803 | builder.copy(&f.path(), &rustc_libdir.join(&filename)); |
3b2f2976 XL |
804 | } |
805 | } | |
806 | ||
60c5eb7d | 807 | let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); |
0531ce1d | 808 | if let Some(lld_install) = lld_install { |
3dfed10e XL |
809 | let src_exe = exe("lld", target_compiler.host); |
810 | let dst_exe = exe("rust-lld", target_compiler.host); | |
60c5eb7d XL |
811 | // we prepend this bin directory to the user PATH when linking Rust binaries. To |
812 | // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. | |
813 | let dst = libdir.parent().unwrap().join("bin"); | |
814 | t!(fs::create_dir_all(&dst)); | |
815 | builder.copy(&lld_install.join("bin").join(&src_exe), &dst.join(&dst_exe)); | |
0531ce1d | 816 | } |
3b2f2976 | 817 | |
60c5eb7d XL |
818 | // Ensure that `libLLVM.so` ends up in the newly build compiler directory, |
819 | // so that it can be found when the newly built `rustc` is run. | |
f9f354fc XL |
820 | dist::maybe_install_llvm_runtime(builder, target_compiler.host, &sysroot); |
821 | dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot); | |
0731742a | 822 | |
3b2f2976 | 823 | // Link the compiler binary itself into place |
94b46f34 | 824 | let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); |
1b1a35ee | 825 | let rustc = out_dir.join(exe("rustc-main", host)); |
3b2f2976 XL |
826 | let bindir = sysroot.join("bin"); |
827 | t!(fs::create_dir_all(&bindir)); | |
828 | let compiler = builder.rustc(target_compiler); | |
83c7162d | 829 | builder.copy(&rustc, &compiler); |
3b2f2976 XL |
830 | |
831 | target_compiler | |
7453a54e SL |
832 | } |
833 | } | |
834 | ||
835 | /// Link some files into a rustc sysroot. | |
836 | /// | |
7cac9316 XL |
837 | /// For a particular stage this will link the file listed in `stamp` into the |
838 | /// `sysroot_dst` provided. | |
532ac7d7 XL |
839 | pub fn add_to_sysroot( |
840 | builder: &Builder<'_>, | |
841 | sysroot_dst: &Path, | |
842 | sysroot_host_dst: &Path, | |
dfeec247 | 843 | stamp: &Path, |
532ac7d7 | 844 | ) { |
f035d41b | 845 | let self_contained_dst = &sysroot_dst.join("self-contained"); |
7cac9316 | 846 | t!(fs::create_dir_all(&sysroot_dst)); |
532ac7d7 | 847 | t!(fs::create_dir_all(&sysroot_host_dst)); |
f035d41b XL |
848 | t!(fs::create_dir_all(&self_contained_dst)); |
849 | for (path, dependency_type) in builder.read_stamp_file(stamp) { | |
850 | let dst = match dependency_type { | |
851 | DependencyType::Host => sysroot_host_dst, | |
852 | DependencyType::Target => sysroot_dst, | |
853 | DependencyType::TargetSelfContained => self_contained_dst, | |
854 | }; | |
855 | builder.copy(&path, &dst.join(path.file_name().unwrap())); | |
7453a54e SL |
856 | } |
857 | } | |
54a0048b | 858 | |
dfeec247 XL |
859 | pub fn run_cargo( |
860 | builder: &Builder<'_>, | |
861 | cargo: Cargo, | |
862 | tail_args: Vec<String>, | |
863 | stamp: &Path, | |
f035d41b | 864 | additional_target_deps: Vec<(PathBuf, DependencyType)>, |
dfeec247 XL |
865 | is_check: bool, |
866 | ) -> Vec<PathBuf> { | |
83c7162d XL |
867 | if builder.config.dry_run { |
868 | return Vec::new(); | |
869 | } | |
870 | ||
7cac9316 XL |
871 | // `target_root_dir` looks like $dir/$target/release |
872 | let target_root_dir = stamp.parent().unwrap(); | |
873 | // `target_deps_dir` looks like $dir/$target/release/deps | |
874 | let target_deps_dir = target_root_dir.join("deps"); | |
875 | // `host_root_dir` looks like $dir/release | |
dfeec247 XL |
876 | let host_root_dir = target_root_dir |
877 | .parent() | |
878 | .unwrap() // chop off `release` | |
879 | .parent() | |
880 | .unwrap() // chop off `$target` | |
881 | .join(target_root_dir.file_name().unwrap()); | |
7cac9316 XL |
882 | |
883 | // Spawn Cargo slurping up its JSON output. We'll start building up the | |
884 | // `deps` array of all files it generated along with a `toplevel` array of | |
885 | // files we need to probe for later. | |
886 | let mut deps = Vec::new(); | |
887 | let mut toplevel = Vec::new(); | |
dc9dc135 | 888 | let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { |
532ac7d7 XL |
889 | let (filenames, crate_types) = match msg { |
890 | CargoMessage::CompilerArtifact { | |
891 | filenames, | |
dfeec247 | 892 | target: CargoTarget { crate_types }, |
532ac7d7 XL |
893 | .. |
894 | } => (filenames, crate_types), | |
0531ce1d | 895 | _ => return, |
7cac9316 | 896 | }; |
0531ce1d | 897 | for filename in filenames { |
7cac9316 | 898 | // Skip files like executables |
74b04a01 XL |
899 | if !(filename.ends_with(".rlib") |
900 | || filename.ends_with(".lib") | |
901 | || filename.ends_with(".a") | |
902 | || is_dylib(&filename) | |
903 | || (is_check && filename.ends_with(".rmeta"))) | |
dfeec247 | 904 | { |
8faf50e0 | 905 | continue; |
7cac9316 XL |
906 | } |
907 | ||
0531ce1d | 908 | let filename = Path::new(&*filename); |
7cac9316 XL |
909 | |
910 | // If this was an output file in the "host dir" we don't actually | |
532ac7d7 | 911 | // worry about it, it's not relevant for us |
7cac9316 | 912 | if filename.starts_with(&host_root_dir) { |
532ac7d7 XL |
913 | // Unless it's a proc macro used in the compiler |
914 | if crate_types.iter().any(|t| t == "proc-macro") { | |
f035d41b | 915 | deps.push((filename.to_path_buf(), DependencyType::Host)); |
532ac7d7 | 916 | } |
8faf50e0 | 917 | continue; |
041b39d2 | 918 | } |
7cac9316 XL |
919 | |
920 | // If this was output in the `deps` dir then this is a precise file | |
921 | // name (hash included) so we start tracking it. | |
041b39d2 | 922 | if filename.starts_with(&target_deps_dir) { |
f035d41b | 923 | deps.push((filename.to_path_buf(), DependencyType::Target)); |
8faf50e0 | 924 | continue; |
041b39d2 | 925 | } |
7cac9316 XL |
926 | |
927 | // Otherwise this was a "top level artifact" which right now doesn't | |
928 | // have a hash in the name, but there's a version of this file in | |
929 | // the `deps` folder which *does* have a hash in the name. That's | |
930 | // the one we'll want to we'll probe for it later. | |
abe05a73 XL |
931 | // |
932 | // We do not use `Path::file_stem` or `Path::extension` here, | |
933 | // because some generated files may have multiple extensions e.g. | |
934 | // `std-<hash>.dll.lib` on Windows. The aforementioned methods only | |
935 | // split the file name by the last extension (`.lib`) while we need | |
936 | // to split by all extensions (`.dll.lib`). | |
937 | let expected_len = t!(filename.metadata()).len(); | |
938 | let filename = filename.file_name().unwrap().to_str().unwrap(); | |
939 | let mut parts = filename.splitn(2, '.'); | |
940 | let file_stem = parts.next().unwrap().to_owned(); | |
941 | let extension = parts.next().unwrap().to_owned(); | |
942 | ||
943 | toplevel.push((file_stem, extension, expected_len)); | |
7cac9316 | 944 | } |
0531ce1d | 945 | }); |
7cac9316 | 946 | |
0531ce1d | 947 | if !ok { |
a1dfa0c6 | 948 | exit(1); |
7cac9316 XL |
949 | } |
950 | ||
951 | // Ok now we need to actually find all the files listed in `toplevel`. We've | |
952 | // got a list of prefix/extensions and we basically just need to find the | |
953 | // most recent file in the `deps` folder corresponding to each one. | |
954 | let contents = t!(target_deps_dir.read_dir()) | |
955 | .map(|e| t!(e)) | |
956 | .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata()))) | |
957 | .collect::<Vec<_>>(); | |
abe05a73 XL |
958 | for (prefix, extension, expected_len) in toplevel { |
959 | let candidates = contents.iter().filter(|&&(_, ref filename, ref meta)| { | |
f035d41b XL |
960 | meta.len() == expected_len |
961 | && filename | |
962 | .strip_prefix(&prefix[..]) | |
963 | .map(|s| s.starts_with('-') && s.ends_with(&extension[..])) | |
964 | .unwrap_or(false) | |
7cac9316 | 965 | }); |
dfeec247 XL |
966 | let max = candidates |
967 | .max_by_key(|&&(_, _, ref metadata)| FileTime::from_last_modification_time(metadata)); | |
7cac9316 XL |
968 | let path_to_add = match max { |
969 | Some(triple) => triple.0.to_str().unwrap(), | |
970 | None => panic!("no output generated for {:?} {:?}", prefix, extension), | |
971 | }; | |
972 | if is_dylib(path_to_add) { | |
973 | let candidate = format!("{}.lib", path_to_add); | |
974 | let candidate = PathBuf::from(candidate); | |
975 | if candidate.exists() { | |
f035d41b | 976 | deps.push((candidate, DependencyType::Target)); |
7cac9316 XL |
977 | } |
978 | } | |
f035d41b | 979 | deps.push((path_to_add.into(), DependencyType::Target)); |
7cac9316 XL |
980 | } |
981 | ||
f035d41b | 982 | deps.extend(additional_target_deps); |
7cac9316 | 983 | deps.sort(); |
7cac9316 | 984 | let mut new_contents = Vec::new(); |
f035d41b XL |
985 | for (dep, dependency_type) in deps.iter() { |
986 | new_contents.extend(match *dependency_type { | |
987 | DependencyType::Host => b"h", | |
988 | DependencyType::Target => b"t", | |
989 | DependencyType::TargetSelfContained => b"s", | |
990 | }); | |
7cac9316 XL |
991 | new_contents.extend(dep.to_str().unwrap().as_bytes()); |
992 | new_contents.extend(b"\0"); | |
993 | } | |
0731742a | 994 | t!(fs::write(&stamp, &new_contents)); |
532ac7d7 | 995 | deps.into_iter().map(|(d, _)| d).collect() |
9e0c209e | 996 | } |
0531ce1d XL |
997 | |
998 | pub fn stream_cargo( | |
9fa01778 | 999 | builder: &Builder<'_>, |
e1599b0c | 1000 | cargo: Cargo, |
dc9dc135 | 1001 | tail_args: Vec<String>, |
9fa01778 | 1002 | cb: &mut dyn FnMut(CargoMessage<'_>), |
0531ce1d | 1003 | ) -> bool { |
e1599b0c | 1004 | let mut cargo = Command::from(cargo); |
83c7162d XL |
1005 | if builder.config.dry_run { |
1006 | return true; | |
1007 | } | |
0531ce1d XL |
1008 | // Instruct Cargo to give us json messages on stdout, critically leaving |
1009 | // stderr as piped so we can get those pretty colors. | |
ba9703b0 XL |
1010 | let mut message_format = if builder.config.json_output { |
1011 | String::from("json") | |
1012 | } else { | |
1013 | String::from("json-render-diagnostics") | |
1014 | }; | |
dfeec247 | 1015 | if let Some(s) = &builder.config.rustc_error_format { |
e1599b0c XL |
1016 | message_format.push_str(",json-diagnostic-"); |
1017 | message_format.push_str(s); | |
1018 | } | |
1019 | cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped()); | |
0531ce1d | 1020 | |
dc9dc135 XL |
1021 | for arg in tail_args { |
1022 | cargo.arg(arg); | |
1023 | } | |
1024 | ||
83c7162d | 1025 | builder.verbose(&format!("running: {:?}", cargo)); |
0531ce1d XL |
1026 | let mut child = match cargo.spawn() { |
1027 | Ok(child) => child, | |
1028 | Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e), | |
1029 | }; | |
1030 | ||
1031 | // Spawn Cargo slurping up its JSON output. We'll start building up the | |
1032 | // `deps` array of all files it generated along with a `toplevel` array of | |
1033 | // files we need to probe for later. | |
1034 | let stdout = BufReader::new(child.stdout.take().unwrap()); | |
1035 | for line in stdout.lines() { | |
1036 | let line = t!(line); | |
9fa01778 | 1037 | match serde_json::from_str::<CargoMessage<'_>>(&line) { |
f035d41b XL |
1038 | Ok(msg) => { |
1039 | if builder.config.json_output { | |
1040 | // Forward JSON to stdout. | |
1041 | println!("{}", line); | |
1042 | } | |
1043 | cb(msg) | |
1044 | } | |
0531ce1d | 1045 | // If this was informational, just print it out and continue |
dfeec247 | 1046 | Err(_) => println!("{}", line), |
0531ce1d XL |
1047 | } |
1048 | } | |
1049 | ||
1050 | // Make sure Cargo actually succeeded after we read all of its stdout. | |
1051 | let status = t!(child.wait()); | |
1052 | if !status.success() { | |
dfeec247 XL |
1053 | eprintln!( |
1054 | "command did not execute successfully: {:?}\n\ | |
0531ce1d | 1055 | expected success, got: {}", |
dfeec247 XL |
1056 | cargo, status |
1057 | ); | |
0531ce1d XL |
1058 | } |
1059 | status.success() | |
1060 | } | |
1061 | ||
532ac7d7 XL |
1062 | #[derive(Deserialize)] |
1063 | pub struct CargoTarget<'a> { | |
1064 | crate_types: Vec<Cow<'a, str>>, | |
1065 | } | |
1066 | ||
0531ce1d XL |
1067 | #[derive(Deserialize)] |
1068 | #[serde(tag = "reason", rename_all = "kebab-case")] | |
1069 | pub enum CargoMessage<'a> { | |
1070 | CompilerArtifact { | |
1071 | package_id: Cow<'a, str>, | |
1072 | features: Vec<Cow<'a, str>>, | |
1073 | filenames: Vec<Cow<'a, str>>, | |
532ac7d7 | 1074 | target: CargoTarget<'a>, |
0531ce1d XL |
1075 | }, |
1076 | BuildScriptExecuted { | |
1077 | package_id: Cow<'a, str>, | |
dc9dc135 | 1078 | }, |
f9f354fc XL |
1079 | BuildFinished { |
1080 | success: bool, | |
1081 | }, | |
dc9dc135 | 1082 | } |