1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Implementation of compiling various phases of the compiler and standard
14 //! This module contains some of the real meat in the rustbuild build system
15 //! which is where Cargo is used to compiler the standard library, libtest, and
16 //! compiler. This module is also responsible for assembling the sysroot as it
17 //! goes along from the output of the previous stage.
20 use std
::fs
::{self, File}
;
21 use std
::io
::BufReader
;
22 use std
::io
::prelude
::*;
23 use std
::path
::{Path, PathBuf}
;
24 use std
::process
::{Command, Stdio}
;
28 use build_helper
::{output, mtime, up_to_date}
;
29 use filetime
::FileTime
;
32 use util
::{exe, libdir, is_dylib, copy, read_stamp_file, CiEnv}
;
33 use {Build, Compiler, Mode}
;
37 use cache
::{INTERNER, Interned}
;
38 use builder
::{Step, RunConfig, ShouldRun, Builder}
;
40 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
42 pub target
: Interned
<String
>,
43 pub compiler
: Compiler
,
48 const DEFAULT
: bool
= true;
50 fn should_run(run
: ShouldRun
) -> ShouldRun
{
51 run
.path("src/libstd").krate("std")
54 fn make_run(run
: RunConfig
) {
55 run
.builder
.ensure(Std
{
56 compiler
: run
.builder
.compiler(run
.builder
.top_stage
, run
.host
),
61 /// Build the standard library.
63 /// This will build the standard library for a particular stage of the build
64 /// using the `compiler` targeting the `target` architecture. The artifacts
65 /// created will also be linked into the sysroot directory.
66 fn run(self, builder
: &Builder
) {
67 let build
= builder
.build
;
68 let target
= self.target
;
69 let compiler
= self.compiler
;
71 builder
.ensure(StartupObjects { compiler, target }
);
73 if build
.force_use_stage1(compiler
, target
) {
74 let from
= builder
.compiler(1, build
.build
);
79 println
!("Uplifting stage1 std ({} -> {})", from
.host
, target
);
81 // Even if we're not building std this stage, the new sysroot must
82 // still contain the musl startup objects.
83 if target
.contains("musl") && !target
.contains("mips") {
84 let libdir
= builder
.sysroot_libdir(compiler
, target
);
85 copy_musl_third_party_objects(build
, target
, &libdir
);
88 builder
.ensure(StdLink
{
90 target_compiler
: compiler
,
96 let _folder
= build
.fold_output(|| format
!("stage{}-std", compiler
.stage
));
97 println
!("Building stage{} std artifacts ({} -> {})", compiler
.stage
,
98 &compiler
.host
, target
);
100 if target
.contains("musl") && !target
.contains("mips") {
101 let libdir
= builder
.sysroot_libdir(compiler
, target
);
102 copy_musl_third_party_objects(build
, target
, &libdir
);
105 let out_dir
= build
.stage_out(compiler
, Mode
::Libstd
);
106 build
.clear_if_dirty(&out_dir
, &builder
.rustc(compiler
));
107 let mut cargo
= builder
.cargo(compiler
, Mode
::Libstd
, target
, "build");
108 std_cargo(build
, &compiler
, target
, &mut cargo
);
111 &libstd_stamp(build
, compiler
, target
));
113 builder
.ensure(StdLink
{
114 compiler
: builder
.compiler(compiler
.stage
, build
.build
),
115 target_compiler
: compiler
,
121 /// Copies the crt(1,i,n).o startup objects
123 /// Since musl supports fully static linking, we can cross link for it even
124 /// with a glibc-targeting toolchain, given we have the appropriate startup
125 /// files. As those shipped with glibc won't work, copy the ones provided by
126 /// musl so we have them on linux-gnu hosts.
127 fn copy_musl_third_party_objects(build
: &Build
,
128 target
: Interned
<String
>,
130 for &obj
in &["crt1.o", "crti.o", "crtn.o"] {
131 copy(&build
.musl_root(target
).unwrap().join("lib").join(obj
), &into
.join(obj
));
135 /// Configure cargo to compile the standard library, adding appropriate env vars
137 pub fn std_cargo(build
: &Build
,
139 target
: Interned
<String
>,
140 cargo
: &mut Command
) {
141 let mut features
= build
.std_features();
143 if let Some(target
) = env
::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
144 cargo
.env("MACOSX_DEPLOYMENT_TARGET", target
);
147 // When doing a local rebuild we tell cargo that we're stage1 rather than
148 // stage0. This works fine if the local rust and being-built rust have the
149 // same view of what the default allocator is, but fails otherwise. Since
150 // we don't have a way to express an allocator preference yet, work
151 // around the issue in the case of a local rebuild with jemalloc disabled.
152 if compiler
.stage
== 0 && build
.local_rebuild
&& !build
.config
.use_jemalloc
{
153 features
.push_str(" force_alloc_system");
156 if compiler
.stage
!= 0 && build
.config
.sanitizers
{
157 // This variable is used by the sanitizer runtime crates, e.g.
158 // rustc_lsan, to build the sanitizer runtime from C code
159 // When this variable is missing, those crates won't compile the C code,
160 // so we don't set this variable during stage0 where llvm-config is
162 // We also only build the runtimes when --enable-sanitizers (or its
163 // config.toml equivalent) is used
164 cargo
.env("LLVM_CONFIG", build
.llvm_config(target
));
167 cargo
.arg("--features").arg(features
)
168 .arg("--manifest-path")
169 .arg(build
.src
.join("src/libstd/Cargo.toml"));
171 if let Some(target
) = build
.config
.target_config
.get(&target
) {
172 if let Some(ref jemalloc
) = target
.jemalloc
{
173 cargo
.env("JEMALLOC_OVERRIDE", jemalloc
);
176 if target
.contains("musl") {
177 if let Some(p
) = build
.musl_root(target
) {
178 cargo
.env("MUSL_ROOT", p
);
183 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
185 pub compiler
: Compiler
,
186 pub target_compiler
: Compiler
,
187 pub target
: Interned
<String
>,
190 impl Step
for StdLink
{
193 fn should_run(run
: ShouldRun
) -> ShouldRun
{
197 /// Link all libstd rlibs/dylibs into the sysroot location.
199 /// Links those artifacts generated by `compiler` to a the `stage` compiler's
200 /// sysroot for the specified `host` and `target`.
202 /// Note that this assumes that `compiler` has already generated the libstd
203 /// libraries for `target`, and this method will find them in the relevant
204 /// output directory.
205 fn run(self, builder
: &Builder
) {
206 let build
= builder
.build
;
207 let compiler
= self.compiler
;
208 let target_compiler
= self.target_compiler
;
209 let target
= self.target
;
210 println
!("Copying stage{} std from stage{} ({} -> {} / {})",
211 target_compiler
.stage
,
214 target_compiler
.host
,
216 let libdir
= builder
.sysroot_libdir(target_compiler
, target
);
217 add_to_sysroot(&libdir
, &libstd_stamp(build
, compiler
, target
));
219 if build
.config
.sanitizers
&& compiler
.stage
!= 0 && target
== "x86_64-apple-darwin" {
220 // The sanitizers are only built in stage1 or above, so the dylibs will
221 // be missing in stage0 and causes panic. See the `std()` function above
222 // for reason why the sanitizers are not built in stage0.
223 copy_apple_sanitizer_dylibs(&build
.native_dir(target
), "osx", &libdir
);
226 builder
.ensure(tool
::CleanTools
{
227 compiler
: target_compiler
,
234 fn copy_apple_sanitizer_dylibs(native_dir
: &Path
, platform
: &str, into
: &Path
) {
235 for &sanitizer
in &["asan", "tsan"] {
236 let filename
= format
!("libclang_rt.{}_{}_dynamic.dylib", sanitizer
, platform
);
237 let mut src_path
= native_dir
.join(sanitizer
);
238 src_path
.push("build");
239 src_path
.push("lib");
240 src_path
.push("darwin");
241 src_path
.push(&filename
);
242 copy(&src_path
, &into
.join(filename
));
246 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
247 pub struct StartupObjects
{
248 pub compiler
: Compiler
,
249 pub target
: Interned
<String
>,
252 impl Step
for StartupObjects
{
255 fn should_run(run
: ShouldRun
) -> ShouldRun
{
256 run
.path("src/rtstartup")
259 fn make_run(run
: RunConfig
) {
260 run
.builder
.ensure(StartupObjects
{
261 compiler
: run
.builder
.compiler(run
.builder
.top_stage
, run
.host
),
266 /// Build and prepare startup objects like rsbegin.o and rsend.o
268 /// These are primarily used on Windows right now for linking executables/dlls.
269 /// They don't require any library support as they're just plain old object
270 /// files, so we just use the nightly snapshot compiler to always build them (as
271 /// no other compilers are guaranteed to be available).
272 fn run(self, builder
: &Builder
) {
273 let build
= builder
.build
;
274 let for_compiler
= self.compiler
;
275 let target
= self.target
;
276 if !target
.contains("pc-windows-gnu") {
280 let src_dir
= &build
.src
.join("src/rtstartup");
281 let dst_dir
= &build
.native_dir(target
).join("rtstartup");
282 let sysroot_dir
= &builder
.sysroot_libdir(for_compiler
, target
);
283 t
!(fs
::create_dir_all(dst_dir
));
285 for file
in &["rsbegin", "rsend"] {
286 let src_file
= &src_dir
.join(file
.to_string() + ".rs");
287 let dst_file
= &dst_dir
.join(file
.to_string() + ".o");
288 if !up_to_date(src_file
, dst_file
) {
289 let mut cmd
= Command
::new(&build
.initial_rustc
);
290 build
.run(cmd
.env("RUSTC_BOOTSTRAP", "1")
291 .arg("--cfg").arg("stage0")
292 .arg("--target").arg(target
)
294 .arg("-o").arg(dst_file
)
298 copy(dst_file
, &sysroot_dir
.join(file
.to_string() + ".o"));
301 for obj
in ["crt2.o", "dllcrt2.o"].iter() {
302 copy(&compiler_file(build
.cc(target
), obj
), &sysroot_dir
.join(obj
));
307 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
309 pub compiler
: Compiler
,
310 pub target
: Interned
<String
>,
315 const DEFAULT
: bool
= true;
317 fn should_run(run
: ShouldRun
) -> ShouldRun
{
318 run
.path("src/libtest").krate("test")
321 fn make_run(run
: RunConfig
) {
322 run
.builder
.ensure(Test
{
323 compiler
: run
.builder
.compiler(run
.builder
.top_stage
, run
.host
),
330 /// This will build libtest and supporting libraries for a particular stage of
331 /// the build using the `compiler` targeting the `target` architecture. The
332 /// artifacts created will also be linked into the sysroot directory.
333 fn run(self, builder
: &Builder
) {
334 let build
= builder
.build
;
335 let target
= self.target
;
336 let compiler
= self.compiler
;
338 builder
.ensure(Std { compiler, target }
);
340 if build
.force_use_stage1(compiler
, target
) {
341 builder
.ensure(Test
{
342 compiler
: builder
.compiler(1, build
.build
),
345 println
!("Uplifting stage1 test ({} -> {})", &build
.build
, target
);
346 builder
.ensure(TestLink
{
347 compiler
: builder
.compiler(1, build
.build
),
348 target_compiler
: compiler
,
354 let _folder
= build
.fold_output(|| format
!("stage{}-test", compiler
.stage
));
355 println
!("Building stage{} test artifacts ({} -> {})", compiler
.stage
,
356 &compiler
.host
, target
);
357 let out_dir
= build
.stage_out(compiler
, Mode
::Libtest
);
358 build
.clear_if_dirty(&out_dir
, &libstd_stamp(build
, compiler
, target
));
359 let mut cargo
= builder
.cargo(compiler
, Mode
::Libtest
, target
, "build");
360 test_cargo(build
, &compiler
, target
, &mut cargo
);
363 &libtest_stamp(build
, compiler
, target
));
365 builder
.ensure(TestLink
{
366 compiler
: builder
.compiler(compiler
.stage
, build
.build
),
367 target_compiler
: compiler
,
373 /// Same as `std_cargo`, but for libtest
374 pub fn test_cargo(build
: &Build
,
375 _compiler
: &Compiler
,
376 _target
: Interned
<String
>,
377 cargo
: &mut Command
) {
378 if let Some(target
) = env
::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
379 cargo
.env("MACOSX_DEPLOYMENT_TARGET", target
);
381 cargo
.arg("--manifest-path")
382 .arg(build
.src
.join("src/libtest/Cargo.toml"));
385 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
386 pub struct TestLink
{
387 pub compiler
: Compiler
,
388 pub target_compiler
: Compiler
,
389 pub target
: Interned
<String
>,
392 impl Step
for TestLink
{
395 fn should_run(run
: ShouldRun
) -> ShouldRun
{
399 /// Same as `std_link`, only for libtest
400 fn run(self, builder
: &Builder
) {
401 let build
= builder
.build
;
402 let compiler
= self.compiler
;
403 let target_compiler
= self.target_compiler
;
404 let target
= self.target
;
405 println
!("Copying stage{} test from stage{} ({} -> {} / {})",
406 target_compiler
.stage
,
409 target_compiler
.host
,
411 add_to_sysroot(&builder
.sysroot_libdir(target_compiler
, target
),
412 &libtest_stamp(build
, compiler
, target
));
413 builder
.ensure(tool
::CleanTools
{
414 compiler
: target_compiler
,
421 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
423 pub compiler
: Compiler
,
424 pub target
: Interned
<String
>,
427 impl Step
for Rustc
{
429 const ONLY_HOSTS
: bool
= true;
430 const DEFAULT
: bool
= true;
432 fn should_run(run
: ShouldRun
) -> ShouldRun
{
433 run
.path("src/librustc").krate("rustc-main")
436 fn make_run(run
: RunConfig
) {
437 run
.builder
.ensure(Rustc
{
438 compiler
: run
.builder
.compiler(run
.builder
.top_stage
, run
.host
),
443 /// Build the compiler.
445 /// This will build the compiler for a particular stage of the build using
446 /// the `compiler` targeting the `target` architecture. The artifacts
447 /// created will also be linked into the sysroot directory.
448 fn run(self, builder
: &Builder
) {
449 let build
= builder
.build
;
450 let compiler
= self.compiler
;
451 let target
= self.target
;
453 builder
.ensure(Test { compiler, target }
);
455 // Build LLVM for our target. This will implicitly build the host LLVM
457 builder
.ensure(native
::Llvm { target }
);
459 if build
.force_use_stage1(compiler
, target
) {
460 builder
.ensure(Rustc
{
461 compiler
: builder
.compiler(1, build
.build
),
464 println
!("Uplifting stage1 rustc ({} -> {})", &build
.build
, target
);
465 builder
.ensure(RustcLink
{
466 compiler
: builder
.compiler(1, build
.build
),
467 target_compiler
: compiler
,
473 // Ensure that build scripts have a std to link against.
475 compiler
: builder
.compiler(self.compiler
.stage
, build
.build
),
479 let _folder
= build
.fold_output(|| format
!("stage{}-rustc", compiler
.stage
));
480 println
!("Building stage{} compiler artifacts ({} -> {})",
481 compiler
.stage
, &compiler
.host
, target
);
483 let stage_out
= builder
.stage_out(compiler
, Mode
::Librustc
);
484 build
.clear_if_dirty(&stage_out
, &libstd_stamp(build
, compiler
, target
));
485 build
.clear_if_dirty(&stage_out
, &libtest_stamp(build
, compiler
, target
));
487 let mut cargo
= builder
.cargo(compiler
, Mode
::Librustc
, target
, "build");
488 rustc_cargo(build
, &compiler
, target
, &mut cargo
);
491 &librustc_stamp(build
, compiler
, target
));
493 builder
.ensure(RustcLink
{
494 compiler
: builder
.compiler(compiler
.stage
, build
.build
),
495 target_compiler
: compiler
,
501 /// Same as `std_cargo`, but for libtest
502 pub fn rustc_cargo(build
: &Build
,
504 target
: Interned
<String
>,
505 cargo
: &mut Command
) {
506 cargo
.arg("--features").arg(build
.rustc_features())
507 .arg("--manifest-path")
508 .arg(build
.src
.join("src/rustc/Cargo.toml"));
510 // Set some configuration variables picked up by build scripts and
511 // the compiler alike
512 cargo
.env("CFG_RELEASE", build
.rust_release())
513 .env("CFG_RELEASE_CHANNEL", &build
.config
.channel
)
514 .env("CFG_VERSION", build
.rust_version())
515 .env("CFG_PREFIX", build
.config
.prefix
.clone().unwrap_or_default());
517 if compiler
.stage
== 0 {
518 cargo
.env("CFG_LIBDIR_RELATIVE", "lib");
520 let libdir_relative
=
521 build
.config
.libdir_relative
.clone().unwrap_or(PathBuf
::from("lib"));
522 cargo
.env("CFG_LIBDIR_RELATIVE", libdir_relative
);
525 // If we're not building a compiler with debugging information then remove
526 // these two env vars which would be set otherwise.
527 if build
.config
.rust_debuginfo_only_std
{
528 cargo
.env_remove("RUSTC_DEBUGINFO");
529 cargo
.env_remove("RUSTC_DEBUGINFO_LINES");
532 if let Some(ref ver_date
) = build
.rust_info
.commit_date() {
533 cargo
.env("CFG_VER_DATE", ver_date
);
535 if let Some(ref ver_hash
) = build
.rust_info
.sha() {
536 cargo
.env("CFG_VER_HASH", ver_hash
);
538 if !build
.unstable_features() {
539 cargo
.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
541 // Flag that rust llvm is in use
542 if build
.is_rust_llvm(target
) {
543 cargo
.env("LLVM_RUSTLLVM", "1");
545 cargo
.env("LLVM_CONFIG", build
.llvm_config(target
));
546 let target_config
= build
.config
.target_config
.get(&target
);
547 if let Some(s
) = target_config
.and_then(|c
| c
.llvm_config
.as_ref()) {
548 cargo
.env("CFG_LLVM_ROOT", s
);
550 // Building with a static libstdc++ is only supported on linux right now,
551 // not for MSVC or macOS
552 if build
.config
.llvm_static_stdcpp
&&
553 !target
.contains("windows") &&
554 !target
.contains("apple") {
555 cargo
.env("LLVM_STATIC_STDCPP",
556 compiler_file(build
.cxx(target
).unwrap(), "libstdc++.a"));
558 if build
.config
.llvm_link_shared
{
559 cargo
.env("LLVM_LINK_SHARED", "1");
561 if let Some(ref s
) = build
.config
.rustc_default_linker
{
562 cargo
.env("CFG_DEFAULT_LINKER", s
);
566 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
568 pub compiler
: Compiler
,
569 pub target_compiler
: Compiler
,
570 pub target
: Interned
<String
>,
573 impl Step
for RustcLink
{
576 fn should_run(run
: ShouldRun
) -> ShouldRun
{
580 /// Same as `std_link`, only for librustc
581 fn run(self, builder
: &Builder
) {
582 let build
= builder
.build
;
583 let compiler
= self.compiler
;
584 let target_compiler
= self.target_compiler
;
585 let target
= self.target
;
586 println
!("Copying stage{} rustc from stage{} ({} -> {} / {})",
587 target_compiler
.stage
,
590 target_compiler
.host
,
592 add_to_sysroot(&builder
.sysroot_libdir(target_compiler
, target
),
593 &librustc_stamp(build
, compiler
, target
));
594 builder
.ensure(tool
::CleanTools
{
595 compiler
: target_compiler
,
597 mode
: Mode
::Librustc
,
602 /// Cargo's output path for the standard library in a given stage, compiled
603 /// by a particular compiler for the specified target.
604 pub fn libstd_stamp(build
: &Build
, compiler
: Compiler
, target
: Interned
<String
>) -> PathBuf
{
605 build
.cargo_out(compiler
, Mode
::Libstd
, target
).join(".libstd.stamp")
608 /// Cargo's output path for libtest in a given stage, compiled by a particular
609 /// compiler for the specified target.
610 pub fn libtest_stamp(build
: &Build
, compiler
: Compiler
, target
: Interned
<String
>) -> PathBuf
{
611 build
.cargo_out(compiler
, Mode
::Libtest
, target
).join(".libtest.stamp")
614 /// Cargo's output path for librustc in a given stage, compiled by a particular
615 /// compiler for the specified target.
616 pub fn librustc_stamp(build
: &Build
, compiler
: Compiler
, target
: Interned
<String
>) -> PathBuf
{
617 build
.cargo_out(compiler
, Mode
::Librustc
, target
).join(".librustc.stamp")
620 fn compiler_file(compiler
: &Path
, file
: &str) -> PathBuf
{
621 let out
= output(Command
::new(compiler
)
622 .arg(format
!("-print-file-name={}", file
)));
623 PathBuf
::from(out
.trim())
626 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
628 pub compiler
: Compiler
,
631 impl Step
for Sysroot
{
632 type Output
= Interned
<PathBuf
>;
634 fn should_run(run
: ShouldRun
) -> ShouldRun
{
638 /// Returns the sysroot for the `compiler` specified that *this build system
641 /// That is, the sysroot for the stage0 compiler is not what the compiler
642 /// thinks it is by default, but it's the same as the default for stages
644 fn run(self, builder
: &Builder
) -> Interned
<PathBuf
> {
645 let build
= builder
.build
;
646 let compiler
= self.compiler
;
647 let sysroot
= if compiler
.stage
== 0 {
648 build
.out
.join(&compiler
.host
).join("stage0-sysroot")
650 build
.out
.join(&compiler
.host
).join(format
!("stage{}", compiler
.stage
))
652 let _
= fs
::remove_dir_all(&sysroot
);
653 t
!(fs
::create_dir_all(&sysroot
));
654 INTERNER
.intern_path(sysroot
)
658 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
659 pub struct Assemble
{
660 /// The compiler which we will produce in this step. Assemble itself will
661 /// take care of ensuring that the necessary prerequisites to do so exist,
662 /// that is, this target can be a stage2 compiler and Assemble will build
663 /// previous stages for you.
664 pub target_compiler
: Compiler
,
667 impl Step
for Assemble
{
668 type Output
= Compiler
;
670 fn should_run(run
: ShouldRun
) -> ShouldRun
{
671 run
.path("src/rustc")
674 /// Prepare a new compiler from the artifacts in `stage`
676 /// This will assemble a compiler in `build/$host/stage$stage`. The compiler
677 /// must have been previously produced by the `stage - 1` build.build
679 fn run(self, builder
: &Builder
) -> Compiler
{
680 let build
= builder
.build
;
681 let target_compiler
= self.target_compiler
;
683 if target_compiler
.stage
== 0 {
684 assert_eq
!(build
.build
, target_compiler
.host
,
685 "Cannot obtain compiler for non-native build triple at stage 0");
686 // The stage 0 compiler for the build triple is always pre-built.
687 return target_compiler
;
690 // Get the compiler that we'll use to bootstrap ourselves.
691 let build_compiler
= if target_compiler
.host
!= build
.build
{
692 // Build a compiler for the host platform. We cannot use the stage0
693 // compiler for the host platform for this because it doesn't have
694 // the libraries we need. FIXME: Perhaps we should download those
695 // libraries? It would make builds faster...
696 // FIXME: It may be faster if we build just a stage 1
697 // compiler and then use that to bootstrap this compiler
699 builder
.compiler(target_compiler
.stage
- 1, build
.build
)
701 // Build the compiler we'll use to build the stage requested. This
702 // may build more than one compiler (going down to stage 0).
703 builder
.compiler(target_compiler
.stage
- 1, target_compiler
.host
)
706 // Build the libraries for this compiler to link to (i.e., the libraries
707 // it uses at runtime). NOTE: Crates the target compiler compiles don't
708 // link to these. (FIXME: Is that correct? It seems to be correct most
709 // of the time but I think we do link to these for stage2/bin compilers
710 // when not performing a full bootstrap).
711 if builder
.build
.config
.keep_stage
.map_or(false, |s
| target_compiler
.stage
<= s
) {
712 builder
.verbose("skipping compilation of compiler due to --keep-stage");
713 let compiler
= build_compiler
;
714 for stage
in 0..min(target_compiler
.stage
, builder
.config
.keep_stage
.unwrap()) {
715 let target_compiler
= builder
.compiler(stage
, target_compiler
.host
);
716 let target
= target_compiler
.host
;
717 builder
.ensure(StdLink { compiler, target_compiler, target }
);
718 builder
.ensure(TestLink { compiler, target_compiler, target }
);
719 builder
.ensure(RustcLink { compiler, target_compiler, target }
);
722 builder
.ensure(Rustc { compiler: build_compiler, target: target_compiler.host }
);
725 let stage
= target_compiler
.stage
;
726 let host
= target_compiler
.host
;
727 println
!("Assembling stage{} compiler ({})", stage
, host
);
729 // Link in all dylibs to the libdir
730 let sysroot
= builder
.sysroot(target_compiler
);
731 let sysroot_libdir
= sysroot
.join(libdir(&*host
));
732 t
!(fs
::create_dir_all(&sysroot_libdir
));
733 let src_libdir
= builder
.sysroot_libdir(build_compiler
, host
);
734 for f
in t
!(fs
::read_dir(&src_libdir
)).map(|f
| t
!(f
)) {
735 let filename
= f
.file_name().into_string().unwrap();
736 if is_dylib(&filename
) {
737 copy(&f
.path(), &sysroot_libdir
.join(&filename
));
741 let out_dir
= build
.cargo_out(build_compiler
, Mode
::Librustc
, host
);
743 // Link the compiler binary itself into place
744 let rustc
= out_dir
.join(exe("rustc", &*host
));
745 let bindir
= sysroot
.join("bin");
746 t
!(fs
::create_dir_all(&bindir
));
747 let compiler
= builder
.rustc(target_compiler
);
748 let _
= fs
::remove_file(&compiler
);
749 copy(&rustc
, &compiler
);
755 /// Link some files into a rustc sysroot.
757 /// For a particular stage this will link the file listed in `stamp` into the
758 /// `sysroot_dst` provided.
759 fn add_to_sysroot(sysroot_dst
: &Path
, stamp
: &Path
) {
760 t
!(fs
::create_dir_all(&sysroot_dst
));
761 for path
in read_stamp_file(stamp
) {
762 copy(&path
, &sysroot_dst
.join(path
.file_name().unwrap()));
766 // Avoiding a dependency on winapi to keep compile times down
768 fn stderr_isatty() -> bool
{
770 unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
773 fn stderr_isatty() -> bool
{
776 type HANDLE
= *mut u8;
777 const STD_ERROR_HANDLE
: DWORD
= -12i32 as DWORD
;
779 fn GetStdHandle(which
: DWORD
) -> HANDLE
;
780 fn GetConsoleMode(hConsoleHandle
: HANDLE
, lpMode
: *mut DWORD
) -> BOOL
;
783 let handle
= GetStdHandle(STD_ERROR_HANDLE
);
785 GetConsoleMode(handle
, &mut out
) != 0
789 fn run_cargo(build
: &Build
, cargo
: &mut Command
, stamp
: &Path
) {
790 // Instruct Cargo to give us json messages on stdout, critically leaving
791 // stderr as piped so we can get those pretty colors.
792 cargo
.arg("--message-format").arg("json")
793 .stdout(Stdio
::piped());
795 if stderr_isatty() && build
.ci_env
== CiEnv
::None
{
796 // since we pass message-format=json to cargo, we need to tell the rustc
797 // wrapper to give us colored output if necessary. This is because we
798 // only want Cargo's JSON output, not rustcs.
799 cargo
.env("RUSTC_COLOR", "1");
802 build
.verbose(&format
!("running: {:?}", cargo
));
803 let mut child
= match cargo
.spawn() {
805 Err(e
) => panic
!("failed to execute command: {:?}\nerror: {}", cargo
, e
),
808 // `target_root_dir` looks like $dir/$target/release
809 let target_root_dir
= stamp
.parent().unwrap();
810 // `target_deps_dir` looks like $dir/$target/release/deps
811 let target_deps_dir
= target_root_dir
.join("deps");
812 // `host_root_dir` looks like $dir/release
813 let host_root_dir
= target_root_dir
.parent().unwrap() // chop off `release`
814 .parent().unwrap() // chop off `$target`
815 .join(target_root_dir
.file_name().unwrap());
817 // Spawn Cargo slurping up its JSON output. We'll start building up the
818 // `deps` array of all files it generated along with a `toplevel` array of
819 // files we need to probe for later.
820 let mut deps
= Vec
::new();
821 let mut toplevel
= Vec
::new();
822 let stdout
= BufReader
::new(child
.stdout
.take().unwrap());
823 for line
in stdout
.lines() {
825 let json
: serde_json
::Value
= if line
.starts_with("{") {
826 t
!(serde_json
::from_str(&line
))
828 // If this was informational, just print it out and continue
829 println
!("{}", line
);
832 if json
["reason"].as_str() != Some("compiler-artifact") {
835 for filename
in json
["filenames"].as_array().unwrap() {
836 let filename
= filename
.as_str().unwrap();
837 // Skip files like executables
838 if !filename
.ends_with(".rlib") &&
839 !filename
.ends_with(".lib") &&
840 !is_dylib(&filename
) {
844 let filename
= Path
::new(filename
);
846 // If this was an output file in the "host dir" we don't actually
847 // worry about it, it's not relevant for us.
848 if filename
.starts_with(&host_root_dir
) {
852 // If this was output in the `deps` dir then this is a precise file
853 // name (hash included) so we start tracking it.
854 if filename
.starts_with(&target_deps_dir
) {
855 deps
.push(filename
.to_path_buf());
859 // Otherwise this was a "top level artifact" which right now doesn't
860 // have a hash in the name, but there's a version of this file in
861 // the `deps` folder which *does* have a hash in the name. That's
862 // the one we'll want to we'll probe for it later.
864 // We do not use `Path::file_stem` or `Path::extension` here,
865 // because some generated files may have multiple extensions e.g.
866 // `std-<hash>.dll.lib` on Windows. The aforementioned methods only
867 // split the file name by the last extension (`.lib`) while we need
868 // to split by all extensions (`.dll.lib`).
869 let expected_len
= t
!(filename
.metadata()).len();
870 let filename
= filename
.file_name().unwrap().to_str().unwrap();
871 let mut parts
= filename
.splitn(2, '
.'
);
872 let file_stem
= parts
.next().unwrap().to_owned();
873 let extension
= parts
.next().unwrap().to_owned();
875 toplevel
.push((file_stem
, extension
, expected_len
));
879 // Make sure Cargo actually succeeded after we read all of its stdout.
880 let status
= t
!(child
.wait());
881 if !status
.success() {
882 panic
!("command did not execute successfully: {:?}\n\
883 expected success, got: {}",
888 // Ok now we need to actually find all the files listed in `toplevel`. We've
889 // got a list of prefix/extensions and we basically just need to find the
890 // most recent file in the `deps` folder corresponding to each one.
891 let contents
= t
!(target_deps_dir
.read_dir())
893 .map(|e
| (e
.path(), e
.file_name().into_string().unwrap(), t
!(e
.metadata())))
894 .collect
::<Vec
<_
>>();
895 for (prefix
, extension
, expected_len
) in toplevel
{
896 let candidates
= contents
.iter().filter(|&&(_
, ref filename
, ref meta
)| {
897 filename
.starts_with(&prefix
[..]) &&
898 filename
[prefix
.len()..].starts_with("-") &&
899 filename
.ends_with(&extension
[..]) &&
900 meta
.len() == expected_len
902 let max
= candidates
.max_by_key(|&&(_
, _
, ref metadata
)| {
903 FileTime
::from_last_modification_time(metadata
)
905 let path_to_add
= match max
{
906 Some(triple
) => triple
.0.to_str().unwrap(),
907 None
=> panic
!("no output generated for {:?} {:?}", prefix
, extension
),
909 if is_dylib(path_to_add
) {
910 let candidate
= format
!("{}.lib", path_to_add
);
911 let candidate
= PathBuf
::from(candidate
);
912 if candidate
.exists() {
913 deps
.push(candidate
);
916 deps
.push(path_to_add
.into());
919 // Now we want to update the contents of the stamp file, if necessary. First
920 // we read off the previous contents along with its mtime. If our new
921 // contents (the list of files to copy) is different or if any dep's mtime
922 // is newer then we rewrite the stamp file.
924 let mut stamp_contents
= Vec
::new();
925 if let Ok(mut f
) = File
::open(stamp
) {
926 t
!(f
.read_to_end(&mut stamp_contents
));
928 let stamp_mtime
= mtime(&stamp
);
929 let mut new_contents
= Vec
::new();
931 let mut max_path
= None
;
933 let mtime
= mtime(&dep
);
934 if Some(mtime
) > max
{
936 max_path
= Some(dep
.clone());
938 new_contents
.extend(dep
.to_str().unwrap().as_bytes());
939 new_contents
.extend(b
"\0");
941 let max
= max
.unwrap();
942 let max_path
= max_path
.unwrap();
943 if stamp_contents
== new_contents
&& max
<= stamp_mtime
{
944 build
.verbose(&format
!("not updating {:?}; contents equal and {} <= {}",
945 stamp
, max
, stamp_mtime
));
948 if max
> stamp_mtime
{
949 build
.verbose(&format
!("updating {:?} as {:?} changed", stamp
, max_path
));
951 build
.verbose(&format
!("updating {:?} as deps changed", stamp
));
953 t
!(t
!(File
::create(stamp
)).write_all(&new_contents
));