]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/lib.rs
Ensure StorageDead is created even if variable initialization fails
[rust.git] / src / bootstrap / lib.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 rustbuild, the Rust build system.
12 //!
13 //! This module, and its descendants, are the implementation of the Rust build
14 //! system. Most of this build system is backed by Cargo but the outer layer
15 //! here serves as the ability to orchestrate calling Cargo, sequencing Cargo
16 //! builds, building artifacts like LLVM, etc. The goals of rustbuild are:
17 //!
18 //! * To be an easily understandable, easily extensible, and maintainable build
19 //!   system.
20 //! * Leverage standard tools in the Rust ecosystem to build the compiler, aka
21 //!   crates.io and Cargo.
22 //! * A standard interface to build across all platforms, including MSVC
23 //!
24 //! ## Architecture
25 //!
26 //! The build system defers most of the complicated logic managing invocations
27 //! of rustc and rustdoc to Cargo itself. However, moving through various stages
28 //! and copying artifacts is still necessary for it to do. Each time rustbuild
29 //! is invoked, it will iterate through the list of predefined steps and execute
30 //! each serially in turn if it matches the paths passed or is a default rule.
31 //! For each step rustbuild relies on the step internally being incremental and
32 //! parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded
33 //! to appropriate test harnesses and such.
34 //!
35 //! Most of the "meaty" steps that matter are backed by Cargo, which does indeed
36 //! have its own parallelism and incremental management. Later steps, like
37 //! tests, aren't incremental and simply run the entire suite currently.
38 //! However, compiletest itself tries to avoid running tests when the artifacts
39 //! that are involved (mainly the compiler) haven't changed.
40 //!
41 //! When you execute `x.py build`, the steps which are executed are:
42 //!
43 //! * First, the python script is run. This will automatically download the
44 //!   stage0 rustc and cargo according to `src/stage0.txt`, or use the cached
45 //!   versions if they're available. These are then used to compile rustbuild
46 //!   itself (using Cargo). Finally, control is then transferred to rustbuild.
47 //!
48 //! * Rustbuild takes over, performs sanity checks, probes the environment,
49 //!   reads configuration, and starts executing steps as it reads the command
50 //!   line arguments (paths) or going through the default rules.
51 //!
52 //!   The build output will be something like the following:
53 //!
54 //!   Building stage0 std artifacts
55 //!   Copying stage0 std
56 //!   Building stage0 test artifacts
57 //!   Copying stage0 test
58 //!   Building stage0 compiler artifacts
59 //!   Copying stage0 rustc
60 //!   Assembling stage1 compiler
61 //!   Building stage1 std artifacts
62 //!   Copying stage1 std
63 //!   Building stage1 test artifacts
64 //!   Copying stage1 test
65 //!   Building stage1 compiler artifacts
66 //!   Copying stage1 rustc
67 //!   Assembling stage2 compiler
68 //!   Uplifting stage1 std
69 //!   Uplifting stage1 test
70 //!   Uplifting stage1 rustc
71 //!
72 //! Let's disect that a little:
73 //!
74 //! ## Building stage0 {std,test,compiler} artifacts
75 //!
76 //! These steps use the provided (downloaded, usually) compiler to compile the
77 //! local Rust source into libraries we can use.
78 //!
79 //! ## Copying stage0 {std,test,rustc}
80 //!
81 //! This copies the build output from Cargo into
82 //! `build/$HOST/stage0-sysroot/lib/rustlib/$ARCH/lib`. FIXME: This step's
83 //! documentation should be expanded -- the information already here may be
84 //! incorrect.
85 //!
86 //! ## Assembling stage1 compiler
87 //!
88 //! This copies the libraries we built in "building stage0 ... artifacts" into
89 //! the stage1 compiler's lib directory. These are the host libraries that the
90 //! compiler itself uses to run. These aren't actually used by artifacts the new
91 //! compiler generates. This step also copies the rustc and rustdoc binaries we
92 //! generated into build/$HOST/stage/bin.
93 //!
94 //! The stage1/bin/rustc is a fully functional compiler, but it doesn't yet have
95 //! any libraries to link built binaries or libraries to. The next 3 steps will
96 //! provide those libraries for it; they are mostly equivalent to constructing
97 //! the stage1/bin compiler so we don't go through them individually.
98 //!
99 //! ## Uplifting stage1 {std,test,rustc}
100 //!
101 //! This step copies the libraries from the stage1 compiler sysroot into the
102 //! stage2 compiler. This is done to avoid rebuilding the compiler; libraries
103 //! we'd build in this step should be identical (in function, if not necessarily
104 //! identical on disk) so there's no need to recompile the compiler again. Note
105 //! that if you want to, you can enable the full-bootstrap option to change this
106 //! behavior.
107 //!
108 //! Each step is driven by a separate Cargo project and rustbuild orchestrates
109 //! copying files between steps and otherwise preparing for Cargo to run.
110 //!
111 //! ## Further information
112 //!
113 //! More documentation can be found in each respective module below, and you can
114 //! also check out the `src/bootstrap/README.md` file for more information.
115
116 #![deny(warnings)]
117 #![feature(core_intrinsics)]
118
119 #[macro_use]
120 extern crate build_helper;
121 #[macro_use]
122 extern crate serde_derive;
123 #[macro_use]
124 extern crate lazy_static;
125 extern crate serde_json;
126 extern crate cmake;
127 extern crate filetime;
128 extern crate cc;
129 extern crate getopts;
130 extern crate num_cpus;
131 extern crate toml;
132 extern crate time;
133 extern crate petgraph;
134
135 #[cfg(test)]
136 #[macro_use]
137 extern crate pretty_assertions;
138
139 #[cfg(unix)]
140 extern crate libc;
141
142 use std::cell::{RefCell, Cell};
143 use std::collections::{HashSet, HashMap};
144 use std::env;
145 use std::fs::{self, OpenOptions, File};
146 use std::io::{self, Seek, SeekFrom, Write, Read};
147 use std::path::{PathBuf, Path};
148 use std::process::{self, Command};
149 use std::slice;
150 use std::str;
151
152 use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
153 use filetime::FileTime;
154
155 use util::{exe, libdir, OutputFolder, CiEnv};
156
157 mod cc_detect;
158 mod channel;
159 mod check;
160 mod test;
161 mod clean;
162 mod compile;
163 mod metadata;
164 mod config;
165 mod dist;
166 mod doc;
167 mod flags;
168 mod install;
169 mod native;
170 mod sanity;
171 pub mod util;
172 mod builder;
173 mod cache;
174 mod tool;
175 mod toolstate;
176
177 #[cfg(windows)]
178 mod job;
179
180 #[cfg(unix)]
181 mod job {
182     use libc;
183
184     pub unsafe fn setup(build: &mut ::Build) {
185         if build.config.low_priority {
186             libc::setpriority(libc::PRIO_PGRP as _, 0, 10);
187         }
188     }
189 }
190
191 #[cfg(not(any(unix, windows)))]
192 mod job {
193     pub unsafe fn setup(_build: &mut ::Build) {
194     }
195 }
196
197 pub use config::Config;
198 use flags::Subcommand;
199 use cache::{Interned, INTERNER};
200 use toolstate::ToolState;
201
202 const LLVM_TOOLS: &[&str] = &[
203     "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
204     "llvm-objcopy", // used to transform ELFs into binary format which flashing tools consume
205     "llvm-objdump", // used to disassemble programs
206     "llvm-profdata", // used to inspect and merge files generated by profiles
207     "llvm-size", // prints the size of the linker sections of a program
208 ];
209
210 /// A structure representing a Rust compiler.
211 ///
212 /// Each compiler has a `stage` that it is associated with and a `host` that
213 /// corresponds to the platform the compiler runs on. This structure is used as
214 /// a parameter to many methods below.
215 #[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)]
216 pub struct Compiler {
217     stage: u32,
218     host: Interned<String>,
219 }
220
221 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
222 pub enum DocTests {
223     // Default, run normal tests and doc tests.
224     Yes,
225     // Do not run any doc tests.
226     No,
227     // Only run doc tests.
228     Only,
229 }
230
231 /// Global configuration for the build system.
232 ///
233 /// This structure transitively contains all configuration for the build system.
234 /// All filesystem-encoded configuration is in `config`, all flags are in
235 /// `flags`, and then parsed or probed information is listed in the keys below.
236 ///
237 /// This structure is a parameter of almost all methods in the build system,
238 /// although most functions are implemented as free functions rather than
239 /// methods specifically on this structure itself (to make it easier to
240 /// organize).
241 pub struct Build {
242     // User-specified configuration via config.toml
243     config: Config,
244
245     // Derived properties from the above two configurations
246     src: PathBuf,
247     out: PathBuf,
248     rust_info: channel::GitInfo,
249     cargo_info: channel::GitInfo,
250     rls_info: channel::GitInfo,
251     clippy_info: channel::GitInfo,
252     rustfmt_info: channel::GitInfo,
253     local_rebuild: bool,
254     fail_fast: bool,
255     doc_tests: DocTests,
256     verbosity: usize,
257
258     // Targets for which to build.
259     build: Interned<String>,
260     hosts: Vec<Interned<String>>,
261     targets: Vec<Interned<String>>,
262
263     // Stage 0 (downloaded) compiler and cargo or their local rust equivalents.
264     initial_rustc: PathBuf,
265     initial_cargo: PathBuf,
266
267     // Probed tools at runtime
268     lldb_version: Option<String>,
269     lldb_python_dir: Option<String>,
270
271     // Runtime state filled in later on
272     // C/C++ compilers and archiver for all targets
273     cc: HashMap<Interned<String>, cc::Tool>,
274     cxx: HashMap<Interned<String>, cc::Tool>,
275     ar: HashMap<Interned<String>, PathBuf>,
276     // Misc
277     crates: HashMap<Interned<String>, Crate>,
278     is_sudo: bool,
279     ci_env: CiEnv,
280     delayed_failures: RefCell<Vec<String>>,
281     prerelease_version: Cell<Option<u32>>,
282     tool_artifacts: RefCell<HashMap<
283         Interned<String>,
284         HashMap<String, (&'static str, PathBuf, Vec<String>)>
285     >>,
286 }
287
288 #[derive(Debug)]
289 struct Crate {
290     name: Interned<String>,
291     version: String,
292     deps: HashSet<Interned<String>>,
293     id: String,
294     path: PathBuf,
295     doc_step: String,
296     build_step: String,
297     test_step: String,
298     bench_step: String,
299 }
300
301 impl Crate {
302     fn is_local(&self, build: &Build) -> bool {
303         self.path.starts_with(&build.config.src) &&
304         !self.path.to_string_lossy().ends_with("_shim")
305     }
306
307     fn local_path(&self, build: &Build) -> PathBuf {
308         assert!(self.is_local(build));
309         self.path.strip_prefix(&build.config.src).unwrap().into()
310     }
311 }
312
313 /// The various "modes" of invoking Cargo.
314 ///
315 /// These entries currently correspond to the various output directories of the
316 /// build system, with each mod generating output in a different directory.
317 #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
318 pub enum Mode {
319     /// Build the standard library, placing output in the "stageN-std" directory.
320     Std,
321
322     /// Build libtest, placing output in the "stageN-test" directory.
323     Test,
324
325     /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory.
326     Rustc,
327
328     /// Build codegen libraries, placing output in the "stageN-codegen" directory
329     Codegen,
330
331     /// Build some tools, placing output in the "stageN-tools" directory.
332     ToolStd,
333     ToolTest,
334     ToolRustc,
335 }
336
337 impl Mode {
338     pub fn is_tool(&self) -> bool {
339         match self {
340             Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => true,
341             _ => false
342         }
343     }
344 }
345
346 impl Build {
347     /// Creates a new set of build configuration from the `flags` on the command
348     /// line and the filesystem `config`.
349     ///
350     /// By default all build output will be placed in the current directory.
351     pub fn new(config: Config) -> Build {
352         let src = config.src.clone();
353         let out = config.out.clone();
354
355         let is_sudo = match env::var_os("SUDO_USER") {
356             Some(sudo_user) => {
357                 match env::var_os("USER") {
358                     Some(user) => user != sudo_user,
359                     None => false,
360                 }
361             }
362             None => false,
363         };
364         let rust_info = channel::GitInfo::new(&config, &src);
365         let cargo_info = channel::GitInfo::new(&config, &src.join("src/tools/cargo"));
366         let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls"));
367         let clippy_info = channel::GitInfo::new(&config, &src.join("src/tools/clippy"));
368         let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt"));
369
370         let mut build = Build {
371             initial_rustc: config.initial_rustc.clone(),
372             initial_cargo: config.initial_cargo.clone(),
373             local_rebuild: config.local_rebuild,
374             fail_fast: config.cmd.fail_fast(),
375             doc_tests: config.cmd.doc_tests(),
376             verbosity: config.verbose,
377
378             build: config.build,
379             hosts: config.hosts.clone(),
380             targets: config.targets.clone(),
381
382             config,
383             src,
384             out,
385
386             rust_info,
387             cargo_info,
388             rls_info,
389             clippy_info,
390             rustfmt_info,
391             cc: HashMap::new(),
392             cxx: HashMap::new(),
393             ar: HashMap::new(),
394             crates: HashMap::new(),
395             lldb_version: None,
396             lldb_python_dir: None,
397             is_sudo,
398             ci_env: CiEnv::current(),
399             delayed_failures: RefCell::new(Vec::new()),
400             prerelease_version: Cell::new(None),
401             tool_artifacts: Default::default(),
402         };
403
404         build.verbose("finding compilers");
405         cc_detect::find(&mut build);
406         build.verbose("running sanity check");
407         sanity::check(&mut build);
408
409         // If local-rust is the same major.minor as the current version, then force a
410         // local-rebuild
411         let local_version_verbose = output(
412             Command::new(&build.initial_rustc).arg("--version").arg("--verbose"));
413         let local_release = local_version_verbose
414             .lines().filter(|x| x.starts_with("release:"))
415             .next().unwrap().trim_left_matches("release:").trim();
416         let my_version = channel::CFG_RELEASE_NUM;
417         if local_release.split('.').take(2).eq(my_version.split('.').take(2)) {
418             build.verbose(&format!("auto-detected local-rebuild {}", local_release));
419             build.local_rebuild = true;
420         }
421
422         build.verbose("learning about cargo");
423         metadata::build(&mut build);
424
425         build
426     }
427
428     pub fn build_triple(&self) -> &[Interned<String>] {
429         unsafe {
430             slice::from_raw_parts(&self.build, 1)
431         }
432     }
433
434     /// Executes the entire build, as configured by the flags and configuration.
435     pub fn build(&mut self) {
436         unsafe {
437             job::setup(self);
438         }
439
440         if let Subcommand::Clean { all } = self.config.cmd {
441             return clean::clean(self, all);
442         }
443
444         {
445             let builder = builder::Builder::new(&self);
446             if let Some(path) = builder.paths.get(0) {
447                 if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
448                     return;
449                 }
450             }
451         }
452
453         if !self.config.dry_run {
454             {
455                 self.config.dry_run = true;
456                 let builder = builder::Builder::new(&self);
457                 builder.execute_cli();
458             }
459             self.config.dry_run = false;
460             let builder = builder::Builder::new(&self);
461             builder.execute_cli();
462         } else {
463             let builder = builder::Builder::new(&self);
464             let _ = builder.execute_cli();
465         }
466
467         // Check for postponed failures from `test --no-fail-fast`.
468         let failures = self.delayed_failures.borrow();
469         if failures.len() > 0 {
470             println!("\n{} command(s) did not execute successfully:\n", failures.len());
471             for failure in failures.iter() {
472                 println!("  - {}\n", failure);
473             }
474             process::exit(1);
475         }
476     }
477
478     /// Clear out `dir` if `input` is newer.
479     ///
480     /// After this executes, it will also ensure that `dir` exists.
481     fn clear_if_dirty(&self, dir: &Path, input: &Path) -> bool {
482         let stamp = dir.join(".stamp");
483         let mut cleared = false;
484         if mtime(&stamp) < mtime(input) {
485             self.verbose(&format!("Dirty - {}", dir.display()));
486             let _ = fs::remove_dir_all(dir);
487             cleared = true;
488         } else if stamp.exists() {
489             return cleared;
490         }
491         t!(fs::create_dir_all(dir));
492         t!(File::create(stamp));
493         cleared
494     }
495
496     /// Get the space-separated set of activated features for the standard
497     /// library.
498     fn std_features(&self) -> String {
499         let mut features = "panic-unwind".to_string();
500
501         if self.config.debug_jemalloc {
502             features.push_str(" debug-jemalloc");
503         }
504         if self.config.use_jemalloc {
505             features.push_str(" jemalloc");
506         }
507         if self.config.backtrace {
508             features.push_str(" backtrace");
509         }
510         if self.config.profiler {
511             features.push_str(" profiler");
512         }
513         if self.config.wasm_syscall {
514             features.push_str(" wasm_syscall");
515         }
516         features
517     }
518
519     /// Get the space-separated set of activated features for the compiler.
520     fn rustc_features(&self) -> String {
521         let mut features = String::new();
522         if self.config.use_jemalloc {
523             features.push_str(" jemalloc");
524         }
525         features
526     }
527
528     /// Component directory that Cargo will produce output into (e.g.
529     /// release/debug)
530     fn cargo_dir(&self) -> &'static str {
531         if self.config.rust_optimize {"release"} else {"debug"}
532     }
533
534     fn tools_dir(&self, compiler: Compiler) -> PathBuf {
535         let out = self.out.join(&*compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
536         t!(fs::create_dir_all(&out));
537         out
538     }
539
540     /// Returns the root directory for all output generated in a particular
541     /// stage when running with a particular host compiler.
542     ///
543     /// The mode indicates what the root directory is for.
544     fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf {
545         let suffix = match mode {
546             Mode::Std => "-std",
547             Mode::Test => "-test",
548             Mode::Codegen => "-rustc",
549             Mode::Rustc => "-rustc",
550             Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => "-tools",
551         };
552         self.out.join(&*compiler.host)
553                 .join(format!("stage{}{}", compiler.stage, suffix))
554     }
555
556     /// Returns the root output directory for all Cargo output in a given stage,
557     /// running a particular compiler, whether or not we're building the
558     /// standard library, and targeting the specified architecture.
559     fn cargo_out(&self,
560                  compiler: Compiler,
561                  mode: Mode,
562                  target: Interned<String>) -> PathBuf {
563         self.stage_out(compiler, mode).join(&*target).join(self.cargo_dir())
564     }
565
566     /// Root output directory for LLVM compiled for `target`
567     ///
568     /// Note that if LLVM is configured externally then the directory returned
569     /// will likely be empty.
570     fn llvm_out(&self, target: Interned<String>) -> PathBuf {
571         self.out.join(&*target).join("llvm")
572     }
573
574     fn emscripten_llvm_out(&self, target: Interned<String>) -> PathBuf {
575         self.out.join(&*target).join("llvm-emscripten")
576     }
577
578     fn lld_out(&self, target: Interned<String>) -> PathBuf {
579         self.out.join(&*target).join("lld")
580     }
581
582     /// Output directory for all documentation for a target
583     fn doc_out(&self, target: Interned<String>) -> PathBuf {
584         self.out.join(&*target).join("doc")
585     }
586
587     /// Output directory for all documentation for a target
588     fn compiler_doc_out(&self, target: Interned<String>) -> PathBuf {
589         self.out.join(&*target).join("compiler-doc")
590     }
591
592     /// Output directory for some generated md crate documentation for a target (temporary)
593     fn md_doc_out(&self, target: Interned<String>) -> Interned<PathBuf> {
594         INTERNER.intern_path(self.out.join(&*target).join("md-doc"))
595     }
596
597     /// Output directory for all crate documentation for a target (temporary)
598     ///
599     /// The artifacts here are then copied into `doc_out` above.
600     fn crate_doc_out(&self, target: Interned<String>) -> PathBuf {
601         self.out.join(&*target).join("crate-docs")
602     }
603
604     /// Returns true if no custom `llvm-config` is set for the specified target.
605     ///
606     /// If no custom `llvm-config` was specified then Rust's llvm will be used.
607     fn is_rust_llvm(&self, target: Interned<String>) -> bool {
608         match self.config.target_config.get(&target) {
609             Some(ref c) => c.llvm_config.is_none(),
610             None => true
611         }
612     }
613
614     /// Returns the path to `FileCheck` binary for the specified target
615     fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
616         let target_config = self.config.target_config.get(&target);
617         if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
618             let llvm_bindir = output(Command::new(s).arg("--bindir"));
619             Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
620         } else {
621             let base = self.llvm_out(self.config.build).join("build");
622             let base = if !self.config.ninja && self.config.build.contains("msvc") {
623                 if self.config.llvm_optimize {
624                     if self.config.llvm_release_debuginfo {
625                         base.join("RelWithDebInfo")
626                     } else {
627                         base.join("Release")
628                     }
629                 } else {
630                     base.join("Debug")
631                 }
632             } else {
633                 base
634             };
635             base.join("bin").join(exe("FileCheck", &*target))
636         }
637     }
638
639     /// Directory for libraries built from C/C++ code and shared between stages.
640     fn native_dir(&self, target: Interned<String>) -> PathBuf {
641         self.out.join(&*target).join("native")
642     }
643
644     /// Root output directory for rust_test_helpers library compiled for
645     /// `target`
646     fn test_helpers_out(&self, target: Interned<String>) -> PathBuf {
647         self.native_dir(target).join("rust-test-helpers")
648     }
649
650     /// Adds the `RUST_TEST_THREADS` env var if necessary
651     fn add_rust_test_threads(&self, cmd: &mut Command) {
652         if env::var_os("RUST_TEST_THREADS").is_none() {
653             cmd.env("RUST_TEST_THREADS", self.jobs().to_string());
654         }
655     }
656
657     /// Returns the libdir of the snapshot compiler.
658     fn rustc_snapshot_libdir(&self) -> PathBuf {
659         self.initial_rustc.parent().unwrap().parent().unwrap()
660             .join(libdir(&self.config.build))
661     }
662
663     /// Runs a command, printing out nice contextual information if it fails.
664     fn run(&self, cmd: &mut Command) {
665         if self.config.dry_run { return; }
666         self.verbose(&format!("running: {:?}", cmd));
667         run_silent(cmd)
668     }
669
670     /// Runs a command, printing out nice contextual information if it fails.
671     fn run_quiet(&self, cmd: &mut Command) {
672         if self.config.dry_run { return; }
673         self.verbose(&format!("running: {:?}", cmd));
674         run_suppressed(cmd)
675     }
676
677     /// Runs a command, printing out nice contextual information if it fails.
678     /// Exits if the command failed to execute at all, otherwise returns its
679     /// `status.success()`.
680     fn try_run(&self, cmd: &mut Command) -> bool {
681         if self.config.dry_run { return true; }
682         self.verbose(&format!("running: {:?}", cmd));
683         try_run_silent(cmd)
684     }
685
686     /// Runs a command, printing out nice contextual information if it fails.
687     /// Exits if the command failed to execute at all, otherwise returns its
688     /// `status.success()`.
689     fn try_run_quiet(&self, cmd: &mut Command) -> bool {
690         if self.config.dry_run { return true; }
691         self.verbose(&format!("running: {:?}", cmd));
692         try_run_suppressed(cmd)
693     }
694
695     pub fn is_verbose(&self) -> bool {
696         self.verbosity > 0
697     }
698
699     /// Prints a message if this build is configured in verbose mode.
700     fn verbose(&self, msg: &str) {
701         if self.is_verbose() {
702             println!("{}", msg);
703         }
704     }
705
706     fn info(&self, msg: &str) {
707         if self.config.dry_run { return; }
708         println!("{}", msg);
709     }
710
711     /// Returns the number of parallel jobs that have been configured for this
712     /// build.
713     fn jobs(&self) -> u32 {
714         self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32)
715     }
716
717     /// Returns the path to the C compiler for the target specified.
718     fn cc(&self, target: Interned<String>) -> &Path {
719         self.cc[&target].path()
720     }
721
722     /// Returns a list of flags to pass to the C compiler for the target
723     /// specified.
724     fn cflags(&self, target: Interned<String>) -> Vec<String> {
725         // Filter out -O and /O (the optimization flags) that we picked up from
726         // cc-rs because the build scripts will determine that for themselves.
727         let mut base = self.cc[&target].args().iter()
728                            .map(|s| s.to_string_lossy().into_owned())
729                            .filter(|s| !s.starts_with("-O") && !s.starts_with("/O"))
730                            .collect::<Vec<_>>();
731
732         // If we're compiling on macOS then we add a few unconditional flags
733         // indicating that we want libc++ (more filled out than libstdc++) and
734         // we want to compile for 10.7. This way we can ensure that
735         // LLVM/jemalloc/etc are all properly compiled.
736         if target.contains("apple-darwin") {
737             base.push("-stdlib=libc++".into());
738         }
739
740         // Work around an apparently bad MinGW / GCC optimization,
741         // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html
742         // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936
743         if &*target == "i686-pc-windows-gnu" {
744             base.push("-fno-omit-frame-pointer".into());
745         }
746         base
747     }
748
749     /// Returns the path to the `ar` archive utility for the target specified.
750     fn ar(&self, target: Interned<String>) -> Option<&Path> {
751         self.ar.get(&target).map(|p| &**p)
752     }
753
754     /// Returns the path to the C++ compiler for the target specified.
755     fn cxx(&self, target: Interned<String>) -> Result<&Path, String> {
756         match self.cxx.get(&target) {
757             Some(p) => Ok(p.path()),
758             None => Err(format!(
759                     "target `{}` is not configured as a host, only as a target",
760                     target))
761         }
762     }
763
764     /// Returns the path to the linker for the given target if it needs to be overridden.
765     fn linker(&self, target: Interned<String>) -> Option<&Path> {
766         if let Some(linker) = self.config.target_config.get(&target)
767                                                        .and_then(|c| c.linker.as_ref()) {
768             Some(linker)
769         } else if target != self.config.build &&
770                   !target.contains("msvc") &&
771                   !target.contains("emscripten") &&
772                   !target.contains("wasm32") {
773             Some(self.cc(target))
774         } else {
775             None
776         }
777     }
778
779     /// Returns if this target should statically link the C runtime, if specified
780     fn crt_static(&self, target: Interned<String>) -> Option<bool> {
781         if target.contains("pc-windows-msvc") {
782             Some(true)
783         } else {
784             self.config.target_config.get(&target)
785                 .and_then(|t| t.crt_static)
786         }
787     }
788
789     /// Returns the "musl root" for this `target`, if defined
790     fn musl_root(&self, target: Interned<String>) -> Option<&Path> {
791         self.config.target_config.get(&target)
792             .and_then(|t| t.musl_root.as_ref())
793             .or(self.config.musl_root.as_ref())
794             .map(|p| &**p)
795     }
796
797     /// Returns true if this is a no-std `target`, if defined
798     fn no_std(&self, target: Interned<String>) -> Option<bool> {
799         self.config.target_config.get(&target)
800             .map(|t| t.no_std)
801     }
802
803     /// Returns whether the target will be tested using the `remote-test-client`
804     /// and `remote-test-server` binaries.
805     fn remote_tested(&self, target: Interned<String>) -> bool {
806         self.qemu_rootfs(target).is_some() || target.contains("android") ||
807         env::var_os("TEST_DEVICE_ADDR").is_some()
808     }
809
810     /// Returns the root of the "rootfs" image that this target will be using,
811     /// if one was configured.
812     ///
813     /// If `Some` is returned then that means that tests for this target are
814     /// emulated with QEMU and binaries will need to be shipped to the emulator.
815     fn qemu_rootfs(&self, target: Interned<String>) -> Option<&Path> {
816         self.config.target_config.get(&target)
817             .and_then(|t| t.qemu_rootfs.as_ref())
818             .map(|p| &**p)
819     }
820
821     /// Path to the python interpreter to use
822     fn python(&self) -> &Path {
823         self.config.python.as_ref().unwrap()
824     }
825
826     /// Temporary directory that extended error information is emitted to.
827     fn extended_error_dir(&self) -> PathBuf {
828         self.out.join("tmp/extended-error-metadata")
829     }
830
831     /// Tests whether the `compiler` compiling for `target` should be forced to
832     /// use a stage1 compiler instead.
833     ///
834     /// Currently, by default, the build system does not perform a "full
835     /// bootstrap" by default where we compile the compiler three times.
836     /// Instead, we compile the compiler two times. The final stage (stage2)
837     /// just copies the libraries from the previous stage, which is what this
838     /// method detects.
839     ///
840     /// Here we return `true` if:
841     ///
842     /// * The build isn't performing a full bootstrap
843     /// * The `compiler` is in the final stage, 2
844     /// * We're not cross-compiling, so the artifacts are already available in
845     ///   stage1
846     ///
847     /// When all of these conditions are met the build will lift artifacts from
848     /// the previous stage forward.
849     fn force_use_stage1(&self, compiler: Compiler, target: Interned<String>) -> bool {
850         !self.config.full_bootstrap &&
851             compiler.stage >= 2 &&
852             (self.hosts.iter().any(|h| *h == target) || target == self.build)
853     }
854
855     /// Returns the directory that OpenSSL artifacts are compiled into if
856     /// configured to do so.
857     fn openssl_dir(&self, target: Interned<String>) -> Option<PathBuf> {
858         // OpenSSL not used on Windows
859         if target.contains("windows") {
860             None
861         } else if self.config.openssl_static {
862             Some(self.out.join(&*target).join("openssl"))
863         } else {
864             None
865         }
866     }
867
868     /// Returns the directory that OpenSSL artifacts are installed into if
869     /// configured as such.
870     fn openssl_install_dir(&self, target: Interned<String>) -> Option<PathBuf> {
871         self.openssl_dir(target).map(|p| p.join("install"))
872     }
873
874     /// Given `num` in the form "a.b.c" return a "release string" which
875     /// describes the release version number.
876     ///
877     /// For example on nightly this returns "a.b.c-nightly", on beta it returns
878     /// "a.b.c-beta.1" and on stable it just returns "a.b.c".
879     fn release(&self, num: &str) -> String {
880         match &self.config.channel[..] {
881             "stable" => num.to_string(),
882             "beta" => if self.rust_info.is_git() {
883                 format!("{}-beta.{}", num, self.beta_prerelease_version())
884             } else {
885                 format!("{}-beta", num)
886             },
887             "nightly" => format!("{}-nightly", num),
888             _ => format!("{}-dev", num),
889         }
890     }
891
892     fn beta_prerelease_version(&self) -> u32 {
893         if let Some(s) = self.prerelease_version.get() {
894             return s
895         }
896
897         let beta = output(
898             Command::new("git")
899                 .arg("ls-remote")
900                 .arg("origin")
901                 .arg("beta")
902                 .current_dir(&self.src)
903         );
904         let beta = beta.trim().split_whitespace().next().unwrap();
905         let master = output(
906             Command::new("git")
907                 .arg("ls-remote")
908                 .arg("origin")
909                 .arg("master")
910                 .current_dir(&self.src)
911         );
912         let master = master.trim().split_whitespace().next().unwrap();
913
914         // Figure out where the current beta branch started.
915         let base = output(
916             Command::new("git")
917                 .arg("merge-base")
918                 .arg(beta)
919                 .arg(master)
920                 .current_dir(&self.src),
921         );
922         let base = base.trim();
923
924         // Next figure out how many merge commits happened since we branched off
925         // beta. That's our beta number!
926         let count = output(
927             Command::new("git")
928                 .arg("rev-list")
929                 .arg("--count")
930                 .arg("--merges")
931                 .arg(format!("{}...HEAD", base))
932                 .current_dir(&self.src),
933         );
934         let n = count.trim().parse().unwrap();
935         self.prerelease_version.set(Some(n));
936         n
937     }
938
939     /// Returns the value of `release` above for Rust itself.
940     fn rust_release(&self) -> String {
941         self.release(channel::CFG_RELEASE_NUM)
942     }
943
944     /// Returns the "package version" for a component given the `num` release
945     /// number.
946     ///
947     /// The package version is typically what shows up in the names of tarballs.
948     /// For channels like beta/nightly it's just the channel name, otherwise
949     /// it's the `num` provided.
950     fn package_vers(&self, num: &str) -> String {
951         match &self.config.channel[..] {
952             "stable" => num.to_string(),
953             "beta" => "beta".to_string(),
954             "nightly" => "nightly".to_string(),
955             _ => format!("{}-dev", num),
956         }
957     }
958
959     /// Returns the value of `package_vers` above for Rust itself.
960     fn rust_package_vers(&self) -> String {
961         self.package_vers(channel::CFG_RELEASE_NUM)
962     }
963
964     /// Returns the value of `package_vers` above for Cargo
965     fn cargo_package_vers(&self) -> String {
966         self.package_vers(&self.release_num("cargo"))
967     }
968
969     /// Returns the value of `package_vers` above for rls
970     fn rls_package_vers(&self) -> String {
971         self.package_vers(&self.release_num("rls"))
972     }
973
974     /// Returns the value of `package_vers` above for clippy
975     fn clippy_package_vers(&self) -> String {
976         self.package_vers(&self.release_num("clippy"))
977     }
978
979     /// Returns the value of `package_vers` above for rustfmt
980     fn rustfmt_package_vers(&self) -> String {
981         self.package_vers(&self.release_num("rustfmt"))
982     }
983
984     fn llvm_tools_package_vers(&self) -> String {
985         self.package_vers(&self.rust_version())
986     }
987
988     fn llvm_tools_vers(&self) -> String {
989         self.rust_version()
990     }
991
992     /// Returns the `version` string associated with this compiler for Rust
993     /// itself.
994     ///
995     /// Note that this is a descriptive string which includes the commit date,
996     /// sha, version, etc.
997     fn rust_version(&self) -> String {
998         self.rust_info.version(self, channel::CFG_RELEASE_NUM)
999     }
1000
1001     /// Return the full commit hash
1002     fn rust_sha(&self) -> Option<&str> {
1003         self.rust_info.sha()
1004     }
1005
1006     /// Returns the `a.b.c` version that the given package is at.
1007     fn release_num(&self, package: &str) -> String {
1008         let mut toml = String::new();
1009         let toml_file_name = self.src.join(&format!("src/tools/{}/Cargo.toml", package));
1010         t!(t!(File::open(toml_file_name)).read_to_string(&mut toml));
1011         for line in toml.lines() {
1012             let prefix = "version = \"";
1013             let suffix = "\"";
1014             if line.starts_with(prefix) && line.ends_with(suffix) {
1015                 return line[prefix.len()..line.len() - suffix.len()].to_string()
1016             }
1017         }
1018
1019         panic!("failed to find version in {}'s Cargo.toml", package)
1020     }
1021
1022     /// Returns whether unstable features should be enabled for the compiler
1023     /// we're building.
1024     fn unstable_features(&self) -> bool {
1025         match &self.config.channel[..] {
1026             "stable" | "beta" => false,
1027             "nightly" | _ => true,
1028         }
1029     }
1030
1031     /// Fold the output of the commands after this method into a group. The fold
1032     /// ends when the returned object is dropped. Folding can only be used in
1033     /// the Travis CI environment.
1034     pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder>
1035         where D: Into<String>, F: FnOnce() -> D
1036     {
1037         if !self.config.dry_run && self.ci_env == CiEnv::Travis {
1038             Some(OutputFolder::new(name().into()))
1039         } else {
1040             None
1041         }
1042     }
1043
1044     /// Updates the actual toolstate of a tool.
1045     ///
1046     /// The toolstates are saved to the file specified by the key
1047     /// `rust.save-toolstates` in `config.toml`. If unspecified, nothing will be
1048     /// done. The file is updated immediately after this function completes.
1049     pub fn save_toolstate(&self, tool: &str, state: ToolState) {
1050         use std::io::{Seek, SeekFrom};
1051
1052         if let Some(ref path) = self.config.save_toolstates {
1053             let mut file = t!(fs::OpenOptions::new()
1054                 .create(true)
1055                 .read(true)
1056                 .write(true)
1057                 .open(path));
1058
1059             let mut current_toolstates: HashMap<Box<str>, ToolState> =
1060                 serde_json::from_reader(&mut file).unwrap_or_default();
1061             current_toolstates.insert(tool.into(), state);
1062             t!(file.seek(SeekFrom::Start(0)));
1063             t!(file.set_len(0));
1064             t!(serde_json::to_writer(file, &current_toolstates));
1065         }
1066     }
1067
1068     fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
1069         let mut ret = Vec::new();
1070         let mut list = vec![INTERNER.intern_str(root)];
1071         let mut visited = HashSet::new();
1072         while let Some(krate) = list.pop() {
1073             let krate = &self.crates[&krate];
1074             if krate.is_local(self) {
1075                 ret.push(krate);
1076                 for dep in &krate.deps {
1077                     if visited.insert(dep) && dep != "build_helper" {
1078                         list.push(*dep);
1079                     }
1080                 }
1081             }
1082         }
1083         ret
1084     }
1085
1086     fn read_stamp_file(&self, stamp: &Path) -> Vec<PathBuf> {
1087         if self.config.dry_run {
1088             return Vec::new();
1089         }
1090
1091         let mut paths = Vec::new();
1092         let mut contents = Vec::new();
1093         t!(t!(File::open(stamp)).read_to_end(&mut contents));
1094         // This is the method we use for extracting paths from the stamp file passed to us. See
1095         // run_cargo for more information (in compile.rs).
1096         for part in contents.split(|b| *b == 0) {
1097             if part.is_empty() {
1098                 continue
1099             }
1100             let path = PathBuf::from(t!(str::from_utf8(part)));
1101             paths.push(path);
1102         }
1103         paths
1104     }
1105
1106     /// Copies a file from `src` to `dst`
1107     pub fn copy(&self, src: &Path, dst: &Path) {
1108         if self.config.dry_run { return; }
1109         let _ = fs::remove_file(&dst);
1110         // Attempt to "easy copy" by creating a hard link (symlinks don't work on
1111         // windows), but if that fails just fall back to a slow `copy` operation.
1112         if let Ok(()) = fs::hard_link(src, dst) {
1113             return
1114         }
1115         if let Err(e) = fs::copy(src, dst) {
1116             panic!("failed to copy `{}` to `{}`: {}", src.display(),
1117                 dst.display(), e)
1118         }
1119         let metadata = t!(src.metadata());
1120         t!(fs::set_permissions(dst, metadata.permissions()));
1121         let atime = FileTime::from_last_access_time(&metadata);
1122         let mtime = FileTime::from_last_modification_time(&metadata);
1123         t!(filetime::set_file_times(dst, atime, mtime));
1124     }
1125
1126     /// Search-and-replaces within a file. (Not maximally efficiently: allocates a
1127     /// new string for each replacement.)
1128     pub fn replace_in_file(&self, path: &Path, replacements: &[(&str, &str)]) {
1129         if self.config.dry_run { return; }
1130         let mut contents = String::new();
1131         let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
1132         t!(file.read_to_string(&mut contents));
1133         for &(target, replacement) in replacements {
1134             contents = contents.replace(target, replacement);
1135         }
1136         t!(file.seek(SeekFrom::Start(0)));
1137         t!(file.set_len(0));
1138         t!(file.write_all(contents.as_bytes()));
1139     }
1140
1141     /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
1142     /// when this function is called.
1143     pub fn cp_r(&self, src: &Path, dst: &Path) {
1144         if self.config.dry_run { return; }
1145         for f in t!(fs::read_dir(src)) {
1146             let f = t!(f);
1147             let path = f.path();
1148             let name = path.file_name().unwrap();
1149             let dst = dst.join(name);
1150             if t!(f.file_type()).is_dir() {
1151                 t!(fs::create_dir_all(&dst));
1152                 self.cp_r(&path, &dst);
1153             } else {
1154                 let _ = fs::remove_file(&dst);
1155                 self.copy(&path, &dst);
1156             }
1157         }
1158     }
1159
1160     /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
1161     /// when this function is called. Unwanted files or directories can be skipped
1162     /// by returning `false` from the filter function.
1163     pub fn cp_filtered(&self, src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
1164         // Immediately recurse with an empty relative path
1165         self.recurse_(src, dst, Path::new(""), filter)
1166     }
1167
1168     // Inner function does the actual work
1169     fn recurse_(&self, src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
1170         for f in self.read_dir(src) {
1171             let path = f.path();
1172             let name = path.file_name().unwrap();
1173             let dst = dst.join(name);
1174             let relative = relative.join(name);
1175             // Only copy file or directory if the filter function returns true
1176             if filter(&relative) {
1177                 if t!(f.file_type()).is_dir() {
1178                     let _ = fs::remove_dir_all(&dst);
1179                     self.create_dir(&dst);
1180                     self.recurse_(&path, &dst, &relative, filter);
1181                 } else {
1182                     let _ = fs::remove_file(&dst);
1183                     self.copy(&path, &dst);
1184                 }
1185             }
1186         }
1187     }
1188
1189     fn copy_to_folder(&self, src: &Path, dest_folder: &Path) {
1190         let file_name = src.file_name().unwrap();
1191         let dest = dest_folder.join(file_name);
1192         self.copy(src, &dest);
1193     }
1194
1195     fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
1196         if self.config.dry_run { return; }
1197         let dst = dstdir.join(src.file_name().unwrap());
1198         t!(fs::create_dir_all(dstdir));
1199         drop(fs::remove_file(&dst));
1200         {
1201             let mut s = t!(fs::File::open(&src));
1202             let mut d = t!(fs::File::create(&dst));
1203             io::copy(&mut s, &mut d).expect("failed to copy");
1204         }
1205         chmod(&dst, perms);
1206     }
1207
1208     fn create(&self, path: &Path, s: &str) {
1209         if self.config.dry_run { return; }
1210         t!(fs::write(path, s));
1211     }
1212
1213     fn read(&self, path: &Path) -> String {
1214         if self.config.dry_run { return String::new(); }
1215         t!(fs::read_to_string(path))
1216     }
1217
1218     fn create_dir(&self, dir: &Path) {
1219         if self.config.dry_run { return; }
1220         t!(fs::create_dir_all(dir))
1221     }
1222
1223     fn remove_dir(&self, dir: &Path) {
1224         if self.config.dry_run { return; }
1225         t!(fs::remove_dir_all(dir))
1226     }
1227
1228     fn read_dir(&self, dir: &Path) -> impl Iterator<Item=fs::DirEntry> {
1229         let iter = match fs::read_dir(dir) {
1230             Ok(v) => v,
1231             Err(_) if self.config.dry_run => return vec![].into_iter(),
1232             Err(err) => panic!("could not read dir {:?}: {:?}", dir, err),
1233         };
1234         iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
1235     }
1236
1237     fn remove(&self, f: &Path) {
1238         if self.config.dry_run { return; }
1239         fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f));
1240     }
1241 }
1242
1243 #[cfg(unix)]
1244 fn chmod(path: &Path, perms: u32) {
1245     use std::os::unix::fs::*;
1246     t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
1247 }
1248 #[cfg(windows)]
1249 fn chmod(_path: &Path, _perms: u32) {}
1250
1251
1252 impl<'a> Compiler {
1253     pub fn with_stage(mut self, stage: u32) -> Compiler {
1254         self.stage = stage;
1255         self
1256     }
1257
1258     /// Returns whether this is a snapshot compiler for `build`'s configuration
1259     pub fn is_snapshot(&self, build: &Build) -> bool {
1260         self.stage == 0 && self.host == build.build
1261     }
1262
1263     /// Returns if this compiler should be treated as a final stage one in the
1264     /// current build session.
1265     /// This takes into account whether we're performing a full bootstrap or
1266     /// not; don't directly compare the stage with `2`!
1267     pub fn is_final_stage(&self, build: &Build) -> bool {
1268         let final_stage = if build.config.full_bootstrap { 2 } else { 1 };
1269         self.stage >= final_stage
1270     }
1271 }