]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/compile.rs
cf1e11f7ac8205f943c48d2749f61a5756939130
[rust.git] / src / bootstrap / compile.rs
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.
4 //
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.
10
11 //! Implementation of compiling various phases of the compiler and standard
12 //! library.
13 //!
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.
18
19 use std::env;
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};
25 use std::str;
26
27 use build_helper::{output, mtime, up_to_date};
28 use filetime::FileTime;
29 use rustc_serialize::json;
30
31 use channel::GitInfo;
32 use util::{exe, libdir, is_dylib, copy};
33 use {Build, Compiler, Mode};
34
35 //
36 //    // Crates which have build scripts need to rely on this rule to ensure that
37 //    // the necessary prerequisites for a build script are linked and located in
38 //    // place.
39 //    rules.build("may-run-build-script", "path/to/nowhere")
40 //         .dep(move |s| {
41 //             s.name("libstd-link")
42 //              .host(&build.build)
43 //              .target(&build.build)
44 //         });
45
46 //    // ========================================================================
47 //    // Crate compilations
48 //    //
49 //    // Tools used during the build system but not shipped
50 //    // These rules are "pseudo rules" that don't actually do any work
51 //    // themselves, but represent a complete sysroot with the relevant compiler
52 //    // linked into place.
53 //    //
54 //    // That is, depending on "libstd" means that when the rule is completed then
55 //    // the `stage` sysroot for the compiler `host` will be available with a
56 //    // standard library built for `target` linked in place. Not all rules need
57 //    // the compiler itself to be available, just the standard library, so
58 //    // there's a distinction between the two.
59 //    rules.build("libstd", "src/libstd")
60 //         .dep(|s| s.name("rustc").target(s.host))
61 //         .dep(|s| s.name("libstd-link"));
62 //    rules.build("libtest", "src/libtest")
63 //         .dep(|s| s.name("libstd"))
64 //         .dep(|s| s.name("libtest-link"))
65 //         .default(true);
66 //    rules.build("librustc", "src/librustc")
67 //         .dep(|s| s.name("libtest"))
68 //         .dep(|s| s.name("librustc-link"))
69 //         .host(true)
70 //         .default(true);
71
72 // Helper method to define the rules to link a crate into its place in the
73 // sysroot.
74 //
75 // The logic here is a little subtle as there's a few cases to consider.
76 // Not all combinations of (stage, host, target) actually require something
77 // to be compiled, but rather libraries could get propagated from a
78 // different location. For example:
79 //
80 // * Any crate with a `host` that's not the build triple will not actually
81 //   compile something. A different `host` means that the build triple will
82 //   actually compile the libraries, and then we'll copy them over from the
83 //   build triple to the `host` directory.
84 //
85 // * Some crates aren't even compiled by the build triple, but may be copied
86 //   from previous stages. For example if we're not doing a full bootstrap
87 //   then we may just depend on the stage1 versions of libraries to be
88 //   available to get linked forward.
89 //
90 // * Finally, there are some cases, however, which do indeed comiple crates
91 //   and link them into place afterwards.
92 //
93 // The rule definition below mirrors these three cases. The `dep` method
94 // calculates the correct dependency which either comes from stage1, a
95 // different compiler, or from actually building the crate itself (the `dep`
96 // rule). The `run` rule then mirrors these three cases and links the cases
97 // forward into the compiler sysroot specified from the correct location.
98 fn crate_rule<'a, 'b>(build: &'a Build,
99                         rules: &'b mut Rules<'a>,
100                         krate: &'a str,
101                         dep: &'a str,
102                         link: fn(&Build, &Compiler, &Compiler, &str))
103                         -> RuleBuilder<'a, 'b> {
104     let mut rule = rules.build(&krate, "path/to/nowhere");
105     rule.dep(move |s| {
106             if build.force_use_stage1(&s.compiler(), s.target) {
107                 s.host(&build.build).stage(1)
108             } else if s.host == build.build {
109                 s.name(dep)
110             } else {
111                 s.host(&build.build)
112             }
113         })
114         .run(move |s| {
115             if build.force_use_stage1(&s.compiler(), s.target) {
116                 link(build,
117                         &s.stage(1).host(&build.build).compiler(),
118                         &s.compiler(),
119                         s.target)
120             } else if s.host == build.build {
121                 link(build, &s.compiler(), &s.compiler(), s.target)
122             } else {
123                 link(build,
124                         &s.host(&build.build).compiler(),
125                         &s.compiler(),
126                         s.target)
127             }
128         });
129         rule
130 }
131
132 //    for (krate, path, _default) in krates("std") {
133 //        rules.build(&krate.build_step, path)
134 //             .dep(|s| s.name("startup-objects"))
135 //             .dep(move |s| s.name("rustc").host(&build.build).target(s.host))
136 //             .run(move |s| compile::std(build, s.target, &s.compiler()));
137 //    }
138 #[derive(Serialize)]
139 pub struct Std<'a> {
140     pub target: &'a str,
141     pub compiler: &'a Compiler<'a>,
142 }
143
144 impl<'a> Step<'a> for Std<'a> {
145     type Output = ();
146
147     /// Build the standard library.
148     ///
149     /// This will build the standard library for a particular stage of the build
150     /// using the `compiler` targeting the `target` architecture. The artifacts
151     /// created will also be linked into the sysroot directory.
152     fn run(self, builder: &Builder) {
153         let build = builder.build;
154         let target = self.target;
155         let compiler = self.compiler;
156         let libdir = build.sysroot_libdir(compiler, target);
157         t!(fs::create_dir_all(&libdir));
158
159         let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
160         println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
161                 compiler.host, target);
162
163         let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
164         build.clear_if_dirty(&out_dir, &build.compiler_path(compiler));
165         let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build");
166         let mut features = build.std_features();
167
168         if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
169             cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
170         }
171
172         // When doing a local rebuild we tell cargo that we're stage1 rather than
173         // stage0. This works fine if the local rust and being-built rust have the
174         // same view of what the default allocator is, but fails otherwise. Since
175         // we don't have a way to express an allocator preference yet, work
176         // around the issue in the case of a local rebuild with jemalloc disabled.
177         if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
178             features.push_str(" force_alloc_system");
179         }
180
181         if compiler.stage != 0 && build.config.sanitizers {
182             // This variable is used by the sanitizer runtime crates, e.g.
183             // rustc_lsan, to build the sanitizer runtime from C code
184             // When this variable is missing, those crates won't compile the C code,
185             // so we don't set this variable during stage0 where llvm-config is
186             // missing
187             // We also only build the runtimes when --enable-sanitizers (or its
188             // config.toml equivalent) is used
189             cargo.env("LLVM_CONFIG", build.llvm_config(target));
190         }
191         cargo.arg("--features").arg(features)
192             .arg("--manifest-path")
193             .arg(build.src.join("src/libstd/Cargo.toml"));
194
195         if let Some(target) = build.config.target_config.get(target) {
196             if let Some(ref jemalloc) = target.jemalloc {
197                 cargo.env("JEMALLOC_OVERRIDE", jemalloc);
198             }
199         }
200         if target.contains("musl") {
201             if let Some(p) = build.musl_root(target) {
202                 cargo.env("MUSL_ROOT", p);
203             }
204         }
205
206         run_cargo(build,
207                 &mut cargo,
208                 &libstd_stamp(build, &compiler, target));
209     }
210 }
211
212
213 // crate_rule(build,
214 //            &mut rules,
215 //            "libstd-link",
216 //            "build-crate-std",
217 //            compile::std_link)
218 //     .dep(|s| s.name("startup-objects"))
219 //     .dep(|s| s.name("create-sysroot").target(s.host));
220
221 #[derive(Serialize)]
222 pub struct StdLink<'a> {
223     pub compiler: Compiler<'a>,
224     pub target_compiler: Compiler<'a>,
225     pub target: &'a str,
226 }
227
228 impl<'a> Step<'a> for StdLink<'a> {
229     type Output = ();
230
231     /// Link all libstd rlibs/dylibs into the sysroot location.
232     ///
233     /// Links those artifacts generated by `compiler` to a the `stage` compiler's
234     /// sysroot for the specified `host` and `target`.
235     ///
236     /// Note that this assumes that `compiler` has already generated the libstd
237     /// libraries for `target`, and this method will find them in the relevant
238     /// output directory.
239     fn run(self, builder: &Builder) {
240         let build = builder.build;
241         let compiler = self.compiler;
242         let target_compiler = self.target_compiler;
243         let target = self.target;
244         println!("Copying stage{} std from stage{} ({} -> {} / {})",
245                 target_compiler.stage,
246                 compiler.stage,
247                 compiler.host,
248                 target_compiler.host,
249                 target);
250         let libdir = build.sysroot_libdir(target_compiler, target);
251         add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
252
253         if target.contains("musl") && !target.contains("mips") {
254             copy_musl_third_party_objects(build, target, &libdir);
255         }
256
257         if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
258             // The sanitizers are only built in stage1 or above, so the dylibs will
259             // be missing in stage0 and causes panic. See the `std()` function above
260             // for reason why the sanitizers are not built in stage0.
261             copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir);
262         }
263     }
264 }
265
266 /// Copies the crt(1,i,n).o startup objects
267 ///
268 /// Only required for musl targets that statically link to libc
269 fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) {
270     for &obj in &["crt1.o", "crti.o", "crtn.o"] {
271         copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
272     }
273 }
274
275 fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
276     for &sanitizer in &["asan", "tsan"] {
277         let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
278         let mut src_path = native_dir.join(sanitizer);
279         src_path.push("build");
280         src_path.push("lib");
281         src_path.push("darwin");
282         src_path.push(&filename);
283         copy(&src_path, &into.join(filename));
284     }
285 }
286
287 // rules.build("startup-objects", "src/rtstartup")
288 //      .dep(|s| s.name("create-sysroot").target(s.host))
289 //      .run(move |s| compile::build_startup_objects(build, &s.compiler(), s.target));
290
291 #[derive(Serialize)]
292 pub struct StartupObjects<'a> {
293     pub for_compiler: Compiler<'a>,
294     pub target: &'a str,
295 }
296
297 impl<'a> Step<'a> for StartupObjects<'a> {
298     type Output = ();
299
300     /// Build and prepare startup objects like rsbegin.o and rsend.o
301     ///
302     /// These are primarily used on Windows right now for linking executables/dlls.
303     /// They don't require any library support as they're just plain old object
304     /// files, so we just use the nightly snapshot compiler to always build them (as
305     /// no other compilers are guaranteed to be available).
306     fn run(self, builder: &Builder) {
307         let build = builder.build;
308         let for_compiler = self.for_compiler;
309         let target = self.target;
310         if !target.contains("pc-windows-gnu") {
311             return
312         }
313
314         let compiler = Compiler::new(0, &build.build);
315         let compiler_path = build.compiler_path(&compiler);
316         let src_dir = &build.src.join("src/rtstartup");
317         let dst_dir = &build.native_dir(target).join("rtstartup");
318         let sysroot_dir = &build.sysroot_libdir(for_compiler, target);
319         t!(fs::create_dir_all(dst_dir));
320         t!(fs::create_dir_all(sysroot_dir));
321
322         for file in &["rsbegin", "rsend"] {
323             let src_file = &src_dir.join(file.to_string() + ".rs");
324             let dst_file = &dst_dir.join(file.to_string() + ".o");
325             if !up_to_date(src_file, dst_file) {
326                 let mut cmd = Command::new(&compiler_path);
327                 build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
328                             .arg("--cfg").arg(format!("stage{}", compiler.stage))
329                             .arg("--target").arg(target)
330                             .arg("--emit=obj")
331                             .arg("--out-dir").arg(dst_dir)
332                             .arg(src_file));
333             }
334
335             copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
336         }
337
338         for obj in ["crt2.o", "dllcrt2.o"].iter() {
339             copy(&compiler_file(build.cc(target), obj), &sysroot_dir.join(obj));
340         }
341     }
342 }
343
344 //    for (krate, path, _default) in krates("test") {
345 //        rules.build(&krate.build_step, path)
346 //             .dep(|s| s.name("libstd-link"))
347 //             .run(move |s| compile::test(build, s.target, &s.compiler()));
348 //    }
349 #[derive(Serialize)]
350 pub struct Test<'a> {
351     pub compiler: Compiler<'a>,
352     pub target: &'a str,
353 }
354
355 impl<'a> Step<'a> for Test<'a> {
356     type Output = ();
357
358     /// Build libtest.
359     ///
360     /// This will build libtest and supporting libraries for a particular stage of
361     /// the build using the `compiler` targeting the `target` architecture. The
362     /// artifacts created will also be linked into the sysroot directory.
363     fn run(self, builder: &Builder) {
364         let build = builder.build;
365         let target = self.target;
366         let compiler = self.compiler;
367         let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
368         println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
369                 compiler.host, target);
370         let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
371         build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
372         let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
373         if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
374             cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
375         }
376         cargo.arg("--manifest-path")
377             .arg(build.src.join("src/libtest/Cargo.toml"));
378         run_cargo(build,
379                 &mut cargo,
380                 &libtest_stamp(build, compiler, target));
381     }
382 }
383
384
385 // crate_rule(build,
386 //            &mut rules,
387 //            "libtest-link",
388 //            "build-crate-test",
389 //            compile::test_link)
390 //     .dep(|s| s.name("libstd-link"));
391
392 #[derive(Serialize)]
393 pub struct TestLink<'a> {
394     pub compiler: Compiler<'a>,
395     pub target_compiler: Compiler<'a>,
396     pub target: &'a str,
397 }
398
399 impl<'a> Step<'a> for Step<'a> {
400     type Output = ();
401
402     /// Same as `std_link`, only for libtest
403     fn run(self, builder: &Builder) {
404         let build = builder.build;
405         let compiler = self.compiler;
406         let target_compiler = self.target_compiler;
407         let target = self.target;
408         println!("Copying stage{} test from stage{} ({} -> {} / {})",
409                 target_compiler.stage,
410                 compiler.stage,
411                 compiler.host,
412                 target_compiler.host,
413                 target);
414         add_to_sysroot(&build.sysroot_libdir(target_compiler, target),
415                     &libtest_stamp(build, compiler, target));
416     }
417 }
418
419 //    for (krate, path, _default) in krates("rustc-main") {
420 //        rules.build(&krate.build_step, path)
421 //             .dep(|s| s.name("libtest-link"))
422 //             .dep(move |s| s.name("llvm").host(&build.build).stage(0))
423 //             .dep(|s| s.name("may-run-build-script"))
424 //             .run(move |s| compile::rustc(build, s.target, &s.compiler()));
425 //    }
426
427 #[derive(Serialize)]
428 pub struct Rustc<'a> {
429     pub compiler: Compiler<'a>,
430     pub target: &'a str,
431 }
432
433 impl<'a> Step<'a> for Rustc<'a> {
434     type Output = ();
435
436     /// Build the compiler.
437     ///
438     /// This will build the compiler for a particular stage of the build using
439     /// the `compiler` targeting the `target` architecture. The artifacts
440     /// created will also be linked into the sysroot directory.
441     fn run(self, builder: &Builder) {
442         let build = builder.build;
443         let compiler = self.compiler;
444         let target = self.target;
445         let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
446         println!("Building stage{} compiler artifacts ({} -> {})",
447                  compiler.stage, compiler.host, target);
448
449         let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
450         build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target));
451
452         let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build");
453         cargo.arg("--features").arg(build.rustc_features())
454              .arg("--manifest-path")
455              .arg(build.src.join("src/rustc/Cargo.toml"));
456
457         // Set some configuration variables picked up by build scripts and
458         // the compiler alike
459         cargo.env("CFG_RELEASE", build.rust_release())
460              .env("CFG_RELEASE_CHANNEL", &build.config.channel)
461              .env("CFG_VERSION", build.rust_version())
462              .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
463
464         if compiler.stage == 0 {
465             cargo.env("CFG_LIBDIR_RELATIVE", "lib");
466         } else {
467             let libdir_relative = build.config.libdir_relative.clone().unwrap_or(PathBuf::from("lib"));
468             cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
469         }
470
471         // If we're not building a compiler with debugging information then remove
472         // these two env vars which would be set otherwise.
473         if build.config.rust_debuginfo_only_std {
474             cargo.env_remove("RUSTC_DEBUGINFO");
475             cargo.env_remove("RUSTC_DEBUGINFO_LINES");
476         }
477
478         if let Some(ref ver_date) = build.rust_info.commit_date() {
479             cargo.env("CFG_VER_DATE", ver_date);
480         }
481         if let Some(ref ver_hash) = build.rust_info.sha() {
482             cargo.env("CFG_VER_HASH", ver_hash);
483         }
484         if !build.unstable_features() {
485             cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
486         }
487         // Flag that rust llvm is in use
488         if build.is_rust_llvm(target) {
489             cargo.env("LLVM_RUSTLLVM", "1");
490         }
491         cargo.env("LLVM_CONFIG", build.llvm_config(target));
492         let target_config = build.config.target_config.get(target);
493         if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
494             cargo.env("CFG_LLVM_ROOT", s);
495         }
496         // Building with a static libstdc++ is only supported on linux right now,
497         // not for MSVC or macOS
498         if build.config.llvm_static_stdcpp &&
499            !target.contains("windows") &&
500            !target.contains("apple") {
501             cargo.env("LLVM_STATIC_STDCPP",
502                       compiler_file(build.cxx(target).unwrap(), "libstdc++.a"));
503         }
504         if build.config.llvm_link_shared {
505             cargo.env("LLVM_LINK_SHARED", "1");
506         }
507         if let Some(ref s) = build.config.rustc_default_linker {
508             cargo.env("CFG_DEFAULT_LINKER", s);
509         }
510         if let Some(ref s) = build.config.rustc_default_ar {
511             cargo.env("CFG_DEFAULT_AR", s);
512         }
513         run_cargo(build,
514                   &mut cargo,
515                   &librustc_stamp(build, compiler, target));
516     }
517 }
518
519 // crate_rule(build,
520 //            &mut rules,
521 //            "librustc-link",
522 //            "build-crate-rustc-main",
523 //            compile::rustc_link)
524 //     .dep(|s| s.name("libtest-link"));
525 #[derive(Serialize)]
526 pub struct RustcLink<'a> {
527     pub compiler: Compiler<'a>,
528     pub target_compiler: Compiler<'a>,
529     pub target: &'a str,
530 }
531
532 impl<'a> Step<'a> for RustcLink<'a> {
533     type Output = ();
534
535     /// Same as `std_link`, only for librustc
536     fn run(self, builder: &Builder) {
537         let build = builder.build;
538         let compiler = self.compiler;
539         let target_compiler = self.target_compiler;
540         let target = self.target;
541         println!("Copying stage{} rustc from stage{} ({} -> {} / {})",
542                  target_compiler.stage,
543                  compiler.stage,
544                  compiler.host,
545                  target_compiler.host,
546                  target);
547         add_to_sysroot(&build.sysroot_libdir(target_compiler, target),
548                        &librustc_stamp(build, compiler, target));
549     }
550 }
551
552 /// Cargo's output path for the standard library in a given stage, compiled
553 /// by a particular compiler for the specified target.
554 fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
555     build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
556 }
557
558 /// Cargo's output path for libtest in a given stage, compiled by a particular
559 /// compiler for the specified target.
560 fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
561     build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
562 }
563
564 /// Cargo's output path for librustc in a given stage, compiled by a particular
565 /// compiler for the specified target.
566 fn librustc_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
567     build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
568 }
569
570 fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
571     let out = output(Command::new(compiler)
572                             .arg(format!("-print-file-name={}", file)));
573     PathBuf::from(out.trim())
574 }
575
576 // rules.build("create-sysroot", "path/to/nowhere")
577 //      .run(move |s| compile::create_sysroot(build, &s.compiler()));
578
579 #[derive(Serialize)]
580 pub struct Sysroot<'a> {
581     pub compiler: Compiler<'a>,
582 }
583
584 impl<'a> Step<'a> for Sysroot<'a> {
585     type Output = ();
586
587     /// Returns the sysroot for the `compiler` specified that *this build system
588     /// generates*.
589     ///
590     /// That is, the sysroot for the stage0 compiler is not what the compiler
591     /// thinks it is by default, but it's the same as the default for stages
592     /// 1-3.
593     fn run(self, builder: &Builder) {
594         let build = builder.build;
595         let compiler = self.compiler;
596         let sysroot = build.sysroot(compiler);
597         let _ = fs::remove_dir_all(&sysroot);
598         t!(fs::create_dir_all(&sysroot));
599     }
600 }
601
602 // the compiler with no target libraries ready to go
603 // rules.build("rustc", "src/rustc")
604 //      .dep(|s| s.name("create-sysroot").target(s.host))
605 //      .dep(move |s| {
606 //          if s.stage == 0 {
607 //              Step::noop()
608 //          } else {
609 //              s.name("librustc")
610 //               .host(&build.build)
611 //               .stage(s.stage - 1)
612 //          }
613 //      })
614 //      .run(move |s| compile::assemble_rustc(build, s.stage, s.target));
615
616 #[derive(Serialize)]
617 pub struct Assemble<'a> {
618     pub stage: u32,
619     pub host: &'a str,
620 }
621
622 impl<'a> Step<'a> for Assemble<'a> {
623     type Output = ();
624
625     /// Prepare a new compiler from the artifacts in `stage`
626     ///
627     /// This will assemble a compiler in `build/$host/stage$stage`. The compiler
628     /// must have been previously produced by the `stage - 1` build.build
629     /// compiler.
630     fn run(self, builder: &Builder) {
631         let build = builder.build;
632         let stage = self.stage;
633         let host = self.host;
634         // nothing to do in stage0
635         if stage == 0 {
636             return
637         }
638
639         println!("Copying stage{} compiler ({})", stage, host);
640
641         // The compiler that we're assembling
642         let target_compiler = Compiler::new(stage, host);
643
644         // The compiler that compiled the compiler we're assembling
645         let build_compiler = Compiler::new(stage - 1, &build.build);
646
647         // Link in all dylibs to the libdir
648         let sysroot = build.sysroot(&target_compiler);
649         let sysroot_libdir = sysroot.join(libdir(host));
650         t!(fs::create_dir_all(&sysroot_libdir));
651         let src_libdir = build.sysroot_libdir(&build_compiler, host);
652         for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
653             let filename = f.file_name().into_string().unwrap();
654             if is_dylib(&filename) {
655                 copy(&f.path(), &sysroot_libdir.join(&filename));
656             }
657         }
658
659         let out_dir = build.cargo_out(&build_compiler, Mode::Librustc, host);
660
661         // Link the compiler binary itself into place
662         let rustc = out_dir.join(exe("rustc", host));
663         let bindir = sysroot.join("bin");
664         t!(fs::create_dir_all(&bindir));
665         let compiler = build.compiler_path(&target_compiler);
666         let _ = fs::remove_file(&compiler);
667         copy(&rustc, &compiler);
668
669         // See if rustdoc exists to link it into place
670         let rustdoc = exe("rustdoc", host);
671         let rustdoc_src = out_dir.join(&rustdoc);
672         let rustdoc_dst = bindir.join(&rustdoc);
673         if fs::metadata(&rustdoc_src).is_ok() {
674             let _ = fs::remove_file(&rustdoc_dst);
675             copy(&rustdoc_src, &rustdoc_dst);
676         }
677     }
678 }
679
680 /// Link some files into a rustc sysroot.
681 ///
682 /// For a particular stage this will link the file listed in `stamp` into the
683 /// `sysroot_dst` provided.
684 fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
685     t!(fs::create_dir_all(&sysroot_dst));
686     let mut contents = Vec::new();
687     t!(t!(File::open(stamp)).read_to_end(&mut contents));
688     // This is the method we use for extracting paths from the stamp file passed to us. See
689     // run_cargo for more information (in this file).
690     for part in contents.split(|b| *b == 0) {
691         if part.is_empty() {
692             continue
693         }
694         let path = Path::new(t!(str::from_utf8(part)));
695         copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
696     }
697 }
698
699 // Avoiding a dependency on winapi to keep compile times down
700 #[cfg(unix)]
701 fn stderr_isatty() -> bool {
702     use libc;
703     unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
704 }
705 #[cfg(windows)]
706 fn stderr_isatty() -> bool {
707     type DWORD = u32;
708     type BOOL = i32;
709     type HANDLE = *mut u8;
710     const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
711     extern "system" {
712         fn GetStdHandle(which: DWORD) -> HANDLE;
713         fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: *mut DWORD) -> BOOL;
714     }
715     unsafe {
716         let handle = GetStdHandle(STD_ERROR_HANDLE);
717         let mut out = 0;
718         GetConsoleMode(handle, &mut out) != 0
719     }
720 }
721
722 fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) {
723     // Instruct Cargo to give us json messages on stdout, critically leaving
724     // stderr as piped so we can get those pretty colors.
725     cargo.arg("--message-format").arg("json")
726          .stdout(Stdio::piped());
727
728     if stderr_isatty() {
729         // since we pass message-format=json to cargo, we need to tell the rustc
730         // wrapper to give us colored output if necessary. This is because we
731         // only want Cargo's JSON output, not rustcs.
732         cargo.env("RUSTC_COLOR", "1");
733     }
734
735     build.verbose(&format!("running: {:?}", cargo));
736     let mut child = match cargo.spawn() {
737         Ok(child) => child,
738         Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
739     };
740
741     // `target_root_dir` looks like $dir/$target/release
742     let target_root_dir = stamp.parent().unwrap();
743     // `target_deps_dir` looks like $dir/$target/release/deps
744     let target_deps_dir = target_root_dir.join("deps");
745     // `host_root_dir` looks like $dir/release
746     let host_root_dir = target_root_dir.parent().unwrap() // chop off `release`
747                                        .parent().unwrap() // chop off `$target`
748                                        .join(target_root_dir.file_name().unwrap());
749
750     // Spawn Cargo slurping up its JSON output. We'll start building up the
751     // `deps` array of all files it generated along with a `toplevel` array of
752     // files we need to probe for later.
753     let mut deps = Vec::new();
754     let mut toplevel = Vec::new();
755     let stdout = BufReader::new(child.stdout.take().unwrap());
756     for line in stdout.lines() {
757         let line = t!(line);
758         let json = if line.starts_with("{") {
759             t!(line.parse::<json::Json>())
760         } else {
761             // If this was informational, just print it out and continue
762             println!("{}", line);
763             continue
764         };
765         if json.find("reason").and_then(|j| j.as_string()) != Some("compiler-artifact") {
766             continue
767         }
768         for filename in json["filenames"].as_array().unwrap() {
769             let filename = filename.as_string().unwrap();
770             // Skip files like executables
771             if !filename.ends_with(".rlib") &&
772                !filename.ends_with(".lib") &&
773                !is_dylib(&filename) {
774                 continue
775             }
776
777             let filename = Path::new(filename);
778
779             // If this was an output file in the "host dir" we don't actually
780             // worry about it, it's not relevant for us.
781             if filename.starts_with(&host_root_dir) {
782                 continue;
783             }
784
785             // If this was output in the `deps` dir then this is a precise file
786             // name (hash included) so we start tracking it.
787             if filename.starts_with(&target_deps_dir) {
788                 deps.push(filename.to_path_buf());
789                 continue;
790             }
791
792             // Otherwise this was a "top level artifact" which right now doesn't
793             // have a hash in the name, but there's a version of this file in
794             // the `deps` folder which *does* have a hash in the name. That's
795             // the one we'll want to we'll probe for it later.
796             toplevel.push((filename.file_stem().unwrap()
797                                     .to_str().unwrap().to_string(),
798                             filename.extension().unwrap().to_owned()
799                                     .to_str().unwrap().to_string()));
800         }
801     }
802
803     // Make sure Cargo actually succeeded after we read all of its stdout.
804     let status = t!(child.wait());
805     if !status.success() {
806         panic!("command did not execute successfully: {:?}\n\
807                 expected success, got: {}",
808                cargo,
809                status);
810     }
811
812     // Ok now we need to actually find all the files listed in `toplevel`. We've
813     // got a list of prefix/extensions and we basically just need to find the
814     // most recent file in the `deps` folder corresponding to each one.
815     let contents = t!(target_deps_dir.read_dir())
816         .map(|e| t!(e))
817         .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata())))
818         .collect::<Vec<_>>();
819     for (prefix, extension) in toplevel {
820         let candidates = contents.iter().filter(|&&(_, ref filename, _)| {
821             filename.starts_with(&prefix[..]) &&
822                 filename[prefix.len()..].starts_with("-") &&
823                 filename.ends_with(&extension[..])
824         });
825         let max = candidates.max_by_key(|&&(_, _, ref metadata)| {
826             FileTime::from_last_modification_time(metadata)
827         });
828         let path_to_add = match max {
829             Some(triple) => triple.0.to_str().unwrap(),
830             None => panic!("no output generated for {:?} {:?}", prefix, extension),
831         };
832         if is_dylib(path_to_add) {
833             let candidate = format!("{}.lib", path_to_add);
834             let candidate = PathBuf::from(candidate);
835             if candidate.exists() {
836                 deps.push(candidate);
837             }
838         }
839         deps.push(path_to_add.into());
840     }
841
842     // Now we want to update the contents of the stamp file, if necessary. First
843     // we read off the previous contents along with its mtime. If our new
844     // contents (the list of files to copy) is different or if any dep's mtime
845     // is newer then we rewrite the stamp file.
846     deps.sort();
847     let mut stamp_contents = Vec::new();
848     if let Ok(mut f) = File::open(stamp) {
849         t!(f.read_to_end(&mut stamp_contents));
850     }
851     let stamp_mtime = mtime(&stamp);
852     let mut new_contents = Vec::new();
853     let mut max = None;
854     let mut max_path = None;
855     for dep in deps {
856         let mtime = mtime(&dep);
857         if Some(mtime) > max {
858             max = Some(mtime);
859             max_path = Some(dep.clone());
860         }
861         new_contents.extend(dep.to_str().unwrap().as_bytes());
862         new_contents.extend(b"\0");
863     }
864     let max = max.unwrap();
865     let max_path = max_path.unwrap();
866     if stamp_contents == new_contents && max <= stamp_mtime {
867         return
868     }
869     if max > stamp_mtime {
870         build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
871     } else {
872         build.verbose(&format!("updating {:?} as deps changed", stamp));
873     }
874     t!(t!(File::create(stamp)).write_all(&new_contents));
875 }