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