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