diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2016-12-27 17:02:52 -0800 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2016-12-27 17:02:52 -0800 |
| commit | e766c465d2e4c4e3c106bfa8343cbe6f9192d445 (patch) | |
| tree | 821a7cf1e0b04ac9c0cddede6eb760bbf2d0ce62 /src/bootstrap | |
| parent | 96c52d4fd86aed6320732a511c04bcbfff7d117f (diff) | |
| parent | 314c28b729ae359b99586cc62c486c28e0d44424 (diff) | |
Merge branch 'master' into escape-reason-docs
Diffstat (limited to 'src/bootstrap')
| -rw-r--r-- | src/bootstrap/README.md | 49 | ||||
| -rw-r--r-- | src/bootstrap/bin/rustc.rs | 55 | ||||
| -rw-r--r-- | src/bootstrap/bin/rustdoc.rs | 2 | ||||
| -rw-r--r-- | src/bootstrap/bootstrap.py | 24 | ||||
| -rw-r--r-- | src/bootstrap/channel.rs | 4 | ||||
| -rw-r--r-- | src/bootstrap/check.rs | 7 | ||||
| -rw-r--r-- | src/bootstrap/config.rs | 55 | ||||
| -rw-r--r-- | src/bootstrap/config.toml.example | 10 | ||||
| -rw-r--r-- | src/bootstrap/dist.rs | 36 | ||||
| -rw-r--r-- | src/bootstrap/flags.rs | 35 | ||||
| -rw-r--r-- | src/bootstrap/lib.rs | 27 | ||||
| -rw-r--r-- | src/bootstrap/mk/Makefile.in | 5 | ||||
| -rw-r--r-- | src/bootstrap/native.rs | 8 | ||||
| -rw-r--r-- | src/bootstrap/sanity.rs | 6 | ||||
| -rw-r--r-- | src/bootstrap/step.rs | 65 | ||||
| -rw-r--r-- | src/bootstrap/util.rs | 6 |
16 files changed, 320 insertions, 74 deletions
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index d0b501e4d89..ac84edb4038 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -22,7 +22,7 @@ Note that if you're on Unix you should be able to execute the script directly: ./x.py build ``` -The script accepts commands, flags, and filters to determine what to do: +The script accepts commands, flags, and arguments to determine what to do: * `build` - a general purpose command for compiling code. Alone `build` will bootstrap the entire compiler, and otherwise arguments passed indicate what to @@ -42,6 +42,15 @@ The script accepts commands, flags, and filters to determine what to do: ./x.py build --stage 0 src/libtest ``` + If files are dirty that would normally be rebuilt from stage 0, that can be + overidden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps + that belong to stage n or earlier: + + ``` + # keep old build products for stage 0 and build stage 1 + ./x.py build --keep-stage 0 --stage 1 + ``` + * `test` - a command for executing unit tests. Like the `build` command this will execute the entire test suite by default, and otherwise it can be used to select which test suite is run: @@ -54,7 +63,7 @@ The script accepts commands, flags, and filters to determine what to do: ./x.py test src/test/run-pass # execute only some tests in the run-pass test suite - ./x.py test src/test/run-pass --filter my-filter + ./x.py test src/test/run-pass --test-args substring-of-test-name # execute tests in the standard library in stage0 ./x.py test --stage 0 src/libstd @@ -107,6 +116,42 @@ compiler. What actually happens when you invoke rustbuild is: The goal of each stage is to (a) leverage Cargo as much as possible and failing that (b) leverage Rust as much as possible! +## Incremental builds + +You can configure rustbuild to use incremental compilation. Because +incremental is new and evolving rapidly, if you want to use it, it is +recommended that you replace the snapshot with a locally installed +nightly build of rustc. You will want to keep this up to date. + +To follow this course of action, first thing you will want to do is to +install a nightly, presumably using `rustup`. You will then want to +configure your directory to use this build, like so: + +``` +# configure to use local rust instead of downloding a beta. +# `--local-rust-root` is optional here. If elided, we will +# use whatever rustc we find on your PATH. +> configure --enable-rustbuild --local-rust-root=~/.cargo/ --enable-local-rebuild +``` + +After that, you can use the `--incremental` flag to actually do +incremental builds: + +``` +> ../x.py build --incremental +``` + +The `--incremental` flag will store incremental compilation artifacts +in `build/<host>/stage0-incremental`. Note that we only use incremental +compilation for the stage0 -> stage1 compilation -- this is because +the stage1 compiler is changing, and we don't try to cache and reuse +incremental artifacts across different versions of the compiler. For +this reason, `--incremental` defaults to `--stage 1` (though you can +manually select a higher stage, if you prefer). + +You can always drop the `--incremental` to build as normal (but you +will still be using the local nightly as your bootstrap). + ## Directory Layout This build system houses all output under the `build` directory, which looks diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 2f674a311fe..9cab6c423f5 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -25,12 +25,17 @@ //! switching compilers for the bootstrap and for build scripts will probably //! never get replaced. +#![deny(warnings)] + extern crate bootstrap; use std::env; use std::ffi::OsString; +use std::io; +use std::io::prelude::*; +use std::str::FromStr; use std::path::PathBuf; -use std::process::Command; +use std::process::{Command, ExitStatus}; fn main() { let args = env::args_os().skip(1).collect::<Vec<_>>(); @@ -41,6 +46,11 @@ fn main() { .and_then(|w| w[1].to_str()); let version = args.iter().find(|w| &**w == "-vV"); + let verbose = match env::var("RUSTC_VERBOSE") { + Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), + Err(_) => 0, + }; + // Build scripts always use the snapshot compiler which is guaranteed to be // able to produce an executable, whereas intermediate compilers may not // have the standard library built yet and may not be able to produce an @@ -95,6 +105,15 @@ fn main() { cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>()); } + // Pass down incremental directory, if any. + if let Ok(dir) = env::var("RUSTC_INCREMENTAL") { + cmd.arg(format!("-Zincremental={}", dir)); + + if verbose > 0 { + cmd.arg("-Zincremental-info"); + } + } + // If we're compiling specifically the `panic_abort` crate then we pass // the `-C panic=abort` option. Note that we do not do this for any // other crate intentionally as this is the only crate for now that we @@ -158,6 +177,15 @@ fn main() { // to change a flag in a binary? if env::var("RUSTC_RPATH") == Ok("true".to_string()) { let rpath = if target.contains("apple") { + + // Note that we need to take one extra step on OSX to also pass + // `-Wl,-instal_name,@rpath/...` to get things to work right. To + // do that we pass a weird flag to the compiler to get it to do + // so. Note that this is definitely a hack, and we should likely + // flesh out rpath support more fully in the future. + if stage != "0" { + cmd.arg("-Z").arg("osx-rpath-install-name"); + } Some("-Wl,-rpath,@loader_path/../lib") } else if !target.contains("windows") { Some("-Wl,-rpath,$ORIGIN/../lib") @@ -167,12 +195,33 @@ fn main() { if let Some(rpath) = rpath { cmd.arg("-C").arg(format!("link-args={}", rpath)); } + + if let Ok(s) = env::var("RUSTFLAGS") { + for flag in s.split_whitespace() { + cmd.arg(flag); + } + } } } + if verbose > 1 { + writeln!(&mut io::stderr(), "rustc command: {:?}", cmd).unwrap(); + } + // Actually run the compiler! - std::process::exit(match cmd.status() { - Ok(s) => s.code().unwrap_or(1), + std::process::exit(match exec_cmd(&mut cmd) { + Ok(s) => s.code().unwrap_or(0xfe), Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), }) } + +#[cfg(unix)] +fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> { + use std::os::unix::process::CommandExt; + Err(cmd.exec()) +} + +#[cfg(not(unix))] +fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> { + cmd.status() +} diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 67358e540da..a53bbe22eb9 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -12,6 +12,8 @@ //! //! See comments in `src/bootstrap/rustc.rs` for more information. +#![deny(warnings)] + extern crate bootstrap; use std::env; diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 0dda7f12007..89d297760e2 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -81,7 +81,7 @@ def verify(path, sha_path, verbose): with open(path, "rb") as f: found = hashlib.sha256(f.read()).hexdigest() with open(sha_path, "r") as f: - expected, _ = f.readline().split() + expected = f.readline().split()[0] verified = found == expected if not verified: print("invalid checksum:\n" @@ -146,7 +146,7 @@ class RustBuild(object): def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date()) - cargo_cache = os.path.join(cache_dst, self.stage0_cargo_date()) + cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev()) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) if not os.path.exists(cargo_cache): @@ -179,21 +179,17 @@ class RustBuild(object): if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() - channel = self.stage0_cargo_channel() - filename = "cargo-{}-{}.tar.gz".format(channel, self.build) - url = "https://static.rust-lang.org/cargo-dist/" + self.stage0_cargo_date() + filename = "cargo-nightly-{}.tar.gz".format(self.build) + url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev() tarball = os.path.join(cargo_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose) with open(self.cargo_stamp(), 'w') as f: - f.write(self.stage0_cargo_date()) + f.write(self.stage0_cargo_rev()) - def stage0_cargo_date(self): - return self._cargo_date - - def stage0_cargo_channel(self): - return self._cargo_channel + def stage0_cargo_rev(self): + return self._cargo_rev def stage0_rustc_date(self): return self._rustc_date @@ -217,7 +213,7 @@ class RustBuild(object): if not os.path.exists(self.cargo_stamp()) or self.clean: return True with open(self.cargo_stamp(), 'r') as f: - return self.stage0_cargo_date() != f.read() + return self.stage0_cargo_rev() != f.read() def bin_root(self): return os.path.join(self.build_dir, self.build, "stage0") @@ -294,6 +290,8 @@ class RustBuild(object): env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] + if not os.path.isfile(self.cargo()): + raise Exception("no cargo executable found at `%s`" % self.cargo()) args = [self.cargo(), "build", "--manifest-path", os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")] if self.use_vendored_sources: @@ -467,7 +465,7 @@ def main(): data = stage0_data(rb.rust_root) rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) - rb._cargo_channel, rb._cargo_date = data['cargo'].split('-', 1) + rb._cargo_rev = data['cargo'] start_time = time() diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index b2341f59787..c38bb33aa02 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -15,7 +15,7 @@ //! `package_vers`, and otherwise indicating to the compiler what it should //! print out as part of its version information. -use std::fs::{self, File}; +use std::fs::File; use std::io::prelude::*; use std::process::Command; @@ -69,7 +69,7 @@ pub fn collect(build: &mut Build) { // If we have a git directory, add in some various SHA information of what // commit this compiler was compiled from. - if fs::metadata(build.src.join(".git")).is_ok() { + if build.src.join(".git").is_dir() { let ver_date = output(Command::new("git").current_dir(&build.src) .arg("log").arg("-1") .arg("--date=short") diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index e0798860275..e7b0afeb8ce 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -13,6 +13,8 @@ //! This file implements the various regression test suites that we execute on //! our CI. +extern crate build_helper; + use std::collections::HashSet; use std::env; use std::fmt; @@ -190,7 +192,7 @@ pub fn compiletest(build: &Build, cmd.args(&build.flags.cmd.test_args()); - if build.config.verbose || build.flags.verbose { + if build.config.verbose() || build.flags.verbose() { cmd.arg("--verbose"); } @@ -299,6 +301,7 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { build.add_rust_test_threads(&mut cmd); cmd.arg("--test"); cmd.arg(markdown); + cmd.env("RUSTC_BOOTSTRAP", "1"); let mut test_args = build.flags.cmd.test_args().join(" "); if build.config.quiet_tests { @@ -542,7 +545,7 @@ pub fn distcheck(build: &Build) { build.run(&mut cmd); build.run(Command::new("./configure") .current_dir(&dir)); - build.run(Command::new("make") + build.run(Command::new(build_helper::make(&build.config.build)) .arg("check") .current_dir(&dir)); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 60f65f62300..6b86e537b7d 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -38,9 +38,9 @@ use util::push_exe_path; /// `src/bootstrap/config.toml.example`. #[derive(Default)] pub struct Config { - pub ccache: bool, + pub ccache: Option<String>, pub ninja: bool, - pub verbose: bool, + pub verbose: usize, pub submodules: bool, pub compiler_docs: bool, pub docs: bool, @@ -113,6 +113,7 @@ pub struct Target { #[derive(RustcDecodable, Default)] struct TomlConfig { build: Option<Build>, + install: Option<Install>, llvm: Option<Llvm>, rust: Option<Rust>, target: Option<HashMap<String, TomlTarget>>, @@ -135,10 +136,16 @@ struct Build { python: Option<String>, } +/// TOML representation of various global install decisions. +#[derive(RustcDecodable, Default, Clone)] +struct Install { + prefix: Option<String>, +} + /// TOML representation of how the LLVM build is configured. #[derive(RustcDecodable, Default)] struct Llvm { - ccache: Option<bool>, + ccache: Option<StringOrBool>, ninja: Option<bool>, assertions: Option<bool>, optimize: Option<bool>, @@ -147,6 +154,18 @@ struct Llvm { static_libstdcpp: Option<bool>, } +#[derive(RustcDecodable)] +enum StringOrBool { + String(String), + Bool(bool), +} + +impl Default for StringOrBool { + fn default() -> StringOrBool { + StringOrBool::Bool(false) + } +} + /// TOML representation of how the Rust build is configured. #[derive(RustcDecodable, Default)] struct Rust { @@ -246,8 +265,20 @@ impl Config { set(&mut config.submodules, build.submodules); set(&mut config.vendor, build.vendor); + if let Some(ref install) = toml.install { + config.prefix = install.prefix.clone(); + } + if let Some(ref llvm) = toml.llvm { - set(&mut config.ccache, llvm.ccache); + match llvm.ccache { + Some(StringOrBool::String(ref s)) => { + config.ccache = Some(s.to_string()) + } + Some(StringOrBool::Bool(true)) => { + config.ccache = Some("ccache".to_string()); + } + Some(StringOrBool::Bool(false)) | None => {} + } set(&mut config.ninja, llvm.ninja); set(&mut config.llvm_assertions, llvm.assertions); set(&mut config.llvm_optimize, llvm.optimize); @@ -255,6 +286,7 @@ impl Config { set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); } + if let Some(ref rust) = toml.rust { set(&mut config.rust_debug_assertions, rust.debug_assertions); set(&mut config.rust_debuginfo, rust.debuginfo); @@ -338,7 +370,6 @@ impl Config { } check! { - ("CCACHE", self.ccache), ("MANAGE_SUBMODULES", self.submodules), ("COMPILER_DOCS", self.compiler_docs), ("DOCS", self.docs), @@ -475,10 +506,24 @@ impl Config { let path = parse_configure_path(value); self.python = Some(path); } + "CFG_ENABLE_CCACHE" if value == "1" => { + self.ccache = Some("ccache".to_string()); + } + "CFG_ENABLE_SCCACHE" if value == "1" => { + self.ccache = Some("sccache".to_string()); + } _ => {} } } } + + pub fn verbose(&self) -> bool { + self.verbose > 0 + } + + pub fn very_verbose(&self) -> bool { + self.verbose > 1 + } } #[cfg(not(windows))] diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index b6774b3af20..5fc095137c7 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -25,6 +25,8 @@ # Indicates whether ccache is used when building LLVM #ccache = false +# or alternatively ... +#ccache = "/path/to/ccache" # If an external LLVM root is specified, we automatically check the version by # default to make sure it's within the range that we're expecting, but setting @@ -99,6 +101,14 @@ #vendor = false # ============================================================================= +# General install configuration options +# ============================================================================= +[install] + +# Instead of installing to /usr/local, install to this path instead. +#prefix = "/path/to/install" + +# ============================================================================= # Options for compiling Rust code itself # ============================================================================= [rust] diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 1d3445a9eac..6e3174ed2f6 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -48,6 +48,11 @@ pub fn tmpdir(build: &Build) -> PathBuf { /// Slurps up documentation from the `stage`'s `host`. pub fn docs(build: &Build, stage: u32, host: &str) { println!("Dist docs stage{} ({})", stage, host); + if !build.config.docs { + println!("\tskipping - docs disabled"); + return + } + let name = format!("rust-docs-{}", package_vers(build)); let image = tmpdir(build).join(format!("{}-{}-image", name, name)); let _ = fs::remove_dir_all(&image); @@ -92,6 +97,7 @@ pub fn mingw(build: &Build, host: &str) { let name = format!("rust-mingw-{}", package_vers(build)); let image = tmpdir(build).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); + t!(fs::create_dir_all(&image)); // The first argument to the script is a "temporary directory" which is just // thrown away (this contains the runtime DLLs included in the rustc package @@ -260,6 +266,14 @@ pub fn debugger_scripts(build: &Build, pub fn std(build: &Build, compiler: &Compiler, target: &str) { println!("Dist std stage{} ({} -> {})", compiler.stage, compiler.host, target); + + // The only true set of target libraries came from the build triple, so + // let's reduce redundant work by only producing archives from that host. + if compiler.host != build.config.build { + println!("\tskipping, not a build host"); + return + } + let name = format!("rust-std-{}", package_vers(build)); let image = tmpdir(build).join(format!("{}-{}-image", name, target)); let _ = fs::remove_dir_all(&image); @@ -294,10 +308,15 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { println!("Dist analysis"); if build.config.channel != "nightly" { - println!("Skipping dist-analysis - not on nightly channel"); + println!("\tskipping - not on nightly channel"); return; } + if compiler.host != build.config.build { + println!("\tskipping - not a build host"); + return + } if compiler.stage != 2 { + println!("\tskipping - not stage2"); return } @@ -324,18 +343,17 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { .arg("--legacy-manifest-dirs=rustlib,cargo"); build.run(&mut cmd); t!(fs::remove_dir_all(&image)); - - // Create plain source tarball - let mut cmd = Command::new("tar"); - cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", name)))) - .arg("analysis") - .current_dir(&src); - build.run(&mut cmd); } /// Creates the `rust-src` installer component and the plain source tarball -pub fn rust_src(build: &Build) { +pub fn rust_src(build: &Build, host: &str) { println!("Dist src"); + + if host != build.config.build { + println!("\tskipping, not a build host"); + return + } + let plain_name = format!("rustc-{}-src", package_vers(build)); let name = format!("rust-src-{}", package_vers(build)); let image = tmpdir(build).join(format!("{}-image", name)); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 7a2d56fc5d3..b2412fbb3c8 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -27,8 +27,9 @@ use step; /// Deserialized version of all flags for this compile. pub struct Flags { - pub verbose: bool, + pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose pub stage: Option<u32>, + pub keep_stage: Option<u32>, pub build: String, pub host: Vec<String>, pub target: Vec<String>, @@ -36,6 +37,17 @@ pub struct Flags { pub src: Option<PathBuf>, pub jobs: Option<u32>, pub cmd: Subcommand, + pub incremental: bool, +} + +impl Flags { + pub fn verbose(&self) -> bool { + self.verbose > 0 + } + + pub fn very_verbose(&self) -> bool { + self.verbose > 1 + } } pub enum Subcommand { @@ -62,12 +74,14 @@ pub enum Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { let mut opts = Options::new(); - opts.optflag("v", "verbose", "use verbose output"); + opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); + opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optopt("", "stage", "stage to build", "N"); + opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); @@ -108,7 +122,6 @@ Arguments: tests that should be compiled and run. For example: ./x.py test src/test/run-pass - ./x.py test src/test/run-pass/assert-* ./x.py test src/libstd --test-args hash_map ./x.py test src/libstd --stage 0 @@ -255,9 +268,20 @@ To learn more about a subcommand, run `./x.py <command> -h` } }); + let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap()); + + let incremental = m.opt_present("i"); + + if incremental { + if stage.is_none() { + stage = Some(1); + } + } + Flags { - verbose: m.opt_present("v"), - stage: m.opt_str("stage").map(|j| j.parse().unwrap()), + verbose: m.opt_count("v"), + stage: stage, + keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), build: m.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() }), @@ -267,6 +291,7 @@ To learn more about a subcommand, run `./x.py <command> -h` src: m.opt_str("src").map(PathBuf::from), jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, + incremental: incremental, } } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index cd80c4298dc..665e0c67b7f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -64,6 +64,8 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. +#![deny(warnings)] + extern crate build_helper; extern crate cmake; extern crate filetime; @@ -74,6 +76,7 @@ extern crate rustc_serialize; extern crate toml; use std::collections::HashMap; +use std::cmp; use std::env; use std::ffi::OsString; use std::fs::{self, File}; @@ -497,6 +500,17 @@ impl Build { cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); + // Ignore incremental modes except for stage0, since we're + // not guaranteeing correctness acros builds if the compiler + // is changing under your feet.` + if self.flags.incremental && compiler.stage == 0 { + let incr_dir = self.incremental_dir(compiler); + cargo.env("RUSTC_INCREMENTAL", incr_dir); + } + + let verbose = cmp::max(self.config.verbose, self.flags.verbose); + cargo.env("RUSTC_VERBOSE", format!("{}", verbose)); + // Specify some various options for build scripts used throughout // the build. // @@ -516,7 +530,7 @@ impl Build { // FIXME: should update code to not require this env var cargo.env("CFG_COMPILER_HOST_TRIPLE", target); - if self.config.verbose || self.flags.verbose { + if self.config.verbose() || self.flags.verbose() { cargo.arg("-v"); } // FIXME: cargo bench does not accept `--release` @@ -630,6 +644,12 @@ impl Build { } } + /// Get the directory for incremental by-products when using the + /// given compiler. + fn incremental_dir(&self, compiler: &Compiler) -> PathBuf { + self.out.join(compiler.host).join(format!("stage{}-incremental", compiler.stage)) + } + /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. fn sysroot_libdir(&self, compiler: &Compiler, target: &str) -> PathBuf { @@ -703,7 +723,8 @@ impl Build { fn llvm_filecheck(&self, target: &str) -> PathBuf { let target_config = self.config.target_config.get(target); if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - s.parent().unwrap().join(exe("FileCheck", target)) + let llvm_bindir = output(Command::new(s).arg("--bindir")); + Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)) } else { let base = self.llvm_out(&self.config.build).join("build"); let exe = exe("FileCheck", target); @@ -768,7 +789,7 @@ impl Build { /// Prints a message if this build is configured in verbose mode. fn verbose(&self, msg: &str) { - if self.flags.verbose || self.config.verbose { + if self.flags.verbose() || self.config.verbose() { println!("{}", msg); } } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 1fa70081938..0d83a79cf32 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -56,7 +56,8 @@ check-cargotest: dist: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) distcheck: - $(Q)$(BOOTSTRAP) test distcheck + $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) + $(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS) install: $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) tidy: @@ -65,7 +66,7 @@ tidy: check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu: $(Q)$(BOOTSTRAP) test --target arm-linux-androideabi check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu: - $(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-gnu + $(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-musl .PHONY: dist diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index ffa3fe1cbf2..09dbd9f8220 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -81,7 +81,7 @@ pub fn llvm(build: &Build, target: &str) { .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) .define("LLVM_TARGETS_TO_BUILD", - "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430") + "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc") .define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") @@ -109,10 +109,10 @@ pub fn llvm(build: &Build, target: &str) { // MSVC handles compiler business itself if !target.contains("msvc") { - if build.config.ccache { - cfg.define("CMAKE_C_COMPILER", "ccache") + if let Some(ref ccache) = build.config.ccache { + cfg.define("CMAKE_C_COMPILER", ccache) .define("CMAKE_C_COMPILER_ARG1", build.cc(target)) - .define("CMAKE_CXX_COMPILER", "ccache") + .define("CMAKE_CXX_COMPILER", ccache) .define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target)); } else { cfg.define("CMAKE_C_COMPILER", build.cc(target)) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index f3fe22698bb..5d543419fc9 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -143,7 +143,7 @@ pub fn check(build: &mut Build) { // Externally configured LLVM requires FileCheck to exist let filecheck = build.llvm_filecheck(&build.config.build); if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { - panic!("filecheck executable {:?} does not exist", filecheck); + panic!("FileCheck executable {:?} does not exist", filecheck); } for target in build.config.target.iter() { @@ -223,4 +223,8 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake if build.lldb_version.is_some() { build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok(); } + + if let Some(ref s) = build.config.ccache { + need_cmd(s.as_ref()); + } } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 884cc7da8ea..c5898c1119a 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -86,7 +86,7 @@ pub fn build_rules(build: &Build) -> Rules { // // To handle this we do a bit of dynamic dispatch to see what the dependency // is. If we're building a LLVM for the build triple, then we don't actually - // have any dependencies! To do that we return a dependency on the "dummy" + // have any dependencies! To do that we return a dependency on the `Step::noop()` // target which does nothing. // // If we're build a cross-compiled LLVM, however, we need to assemble the @@ -104,7 +104,7 @@ pub fn build_rules(build: &Build) -> Rules { .host(true) .dep(move |s| { if s.target == build.config.build { - dummy(s, build) + Step::noop() } else { s.target(&build.config.build) } @@ -115,14 +115,11 @@ pub fn build_rules(build: &Build) -> Rules { // going on here. You can check out the API docs below and also see a bunch // more examples of rules directly below as well. - // dummy rule to do nothing, useful when a dep maps to no deps - rules.build("dummy", "path/to/nowhere"); - // the compiler with no target libraries ready to go rules.build("rustc", "src/rustc") .dep(move |s| { if s.stage == 0 { - dummy(s, build) + Step::noop() } else { s.name("librustc") .host(&build.config.build) @@ -165,7 +162,7 @@ pub fn build_rules(build: &Build) -> Rules { .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host)) .dep(move |s| { if s.host == build.config.build { - dummy(s, build) + Step::noop() } else { s.host(&build.config.build) } @@ -183,7 +180,7 @@ pub fn build_rules(build: &Build) -> Rules { .dep(|s| s.name("libstd")) .dep(move |s| { if s.host == build.config.build { - dummy(s, build) + Step::noop() } else { s.host(&build.config.build) } @@ -203,7 +200,7 @@ pub fn build_rules(build: &Build) -> Rules { .dep(move |s| s.name("llvm").host(&build.config.build).stage(0)) .dep(move |s| { if s.host == build.config.build { - dummy(s, build) + Step::noop() } else { s.host(&build.config.build) } @@ -233,7 +230,7 @@ pub fn build_rules(build: &Build) -> Rules { if s.target.contains("android") { s.name("android-copy-libs") } else { - dummy(s, build) + Step::noop() } }) .default(true) @@ -270,16 +267,18 @@ pub fn build_rules(build: &Build) -> Rules { // nothing to do for debuginfo tests } else if build.config.build.contains("apple") { rules.test("check-debuginfo", "src/test/debuginfo") + .default(true) .dep(|s| s.name("libtest")) - .dep(|s| s.name("tool-compiletest").host(s.host)) + .dep(|s| s.name("tool-compiletest").target(s.host)) .dep(|s| s.name("test-helpers")) .dep(|s| s.name("debugger-scripts")) .run(move |s| check::compiletest(build, &s.compiler(), s.target, "debuginfo-lldb", "debuginfo")); } else { rules.test("check-debuginfo", "src/test/debuginfo") + .default(true) .dep(|s| s.name("libtest")) - .dep(|s| s.name("tool-compiletest").host(s.host)) + .dep(|s| s.name("tool-compiletest").target(s.host)) .dep(|s| s.name("test-helpers")) .dep(|s| s.name("debugger-scripts")) .run(move |s| check::compiletest(build, &s.compiler(), s.target, @@ -458,7 +457,7 @@ pub fn build_rules(build: &Build) -> Rules { for (krate, path, default) in krates("test_shim") { rules.doc(&krate.doc_step, path) .dep(|s| s.name("libtest")) - .default(default && build.config.docs) + .default(default && build.config.compiler_docs) .run(move |s| doc::test(build, s.stage, s.target)); } for (krate, path, default) in krates("rustc-main") { @@ -490,16 +489,21 @@ pub fn build_rules(build: &Build) -> Rules { .default(true) .run(move |s| dist::std(build, &s.compiler(), s.target)); rules.dist("dist-mingw", "path/to/nowhere") - .run(move |s| dist::mingw(build, s.target)); + .default(true) + .run(move |s| { + if s.target.contains("pc-windows-gnu") { + dist::mingw(build, s.target) + } + }); rules.dist("dist-src", "src") .default(true) .host(true) - .run(move |_| dist::rust_src(build)); + .run(move |s| dist::rust_src(build, s.target)); rules.dist("dist-docs", "src/doc") .default(true) .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); - rules.dist("dist-analysis", "src/libstd") + rules.dist("dist-analysis", "analysis") .dep(|s| s.name("dist-std")) .default(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); @@ -509,12 +513,6 @@ pub fn build_rules(build: &Build) -> Rules { rules.verify(); return rules; - - fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> { - s.name("dummy").stage(0) - .target(&build.config.build) - .host(&build.config.build) - } } #[derive(PartialEq, Eq, Hash, Clone, Debug)] @@ -538,6 +536,10 @@ struct Step<'a> { } impl<'a> Step<'a> { + fn noop() -> Step<'a> { + Step { name: "", stage: 0, host: "", target: "" } + } + /// Creates a new step which is the same as this, except has a new name. fn name(&self, name: &'a str) -> Step<'a> { Step { name: name, ..*self } @@ -733,6 +735,9 @@ impl<'a> Rules<'a> { if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") { continue } + if dep == Step::noop() { + continue + } panic!("\ invalid rule dependency graph detected, was a rule added and maybe typo'd? @@ -817,7 +822,16 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? let hosts = if self.build.flags.host.len() > 0 { &self.build.flags.host } else { - &self.build.config.host + if kind == Kind::Dist { + // For 'dist' steps we only distribute artifacts built from + // the build platform, so only consider that in the hosts + // array. + // NOTE: This relies on the fact that the build triple is + // always placed first, as done in `config.rs`. + &self.build.config.host[..1] + } else { + &self.build.config.host + } }; let targets = if self.build.flags.target.len() > 0 { &self.build.flags.target @@ -859,6 +873,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? // of what we need to do. let mut order = Vec::new(); let mut added = HashSet::new(); + added.insert(Step::noop()); for step in steps.iter().cloned() { self.fill(step, &mut order, &mut added); } @@ -871,6 +886,10 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? // And finally, iterate over everything and execute it. for step in order.iter() { + if self.build.flags.keep_stage.map_or(false, |s| step.stage <= s) { + self.build.verbose(&format!("keeping step {:?}", step)); + continue; + } self.build.verbose(&format!("executing step {:?}", step)); (self.rules[step.name].run)(step); } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index cb5b456a0f2..c9e756b6f99 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -41,6 +41,12 @@ pub fn mtime(path: &Path) -> FileTime { /// Copies a file from `src` to `dst`, attempting to use hard links and then /// falling back to an actually filesystem copy if necessary. pub fn copy(src: &Path, dst: &Path) { + // A call to `hard_link` will fail if `dst` exists, so remove it if it + // already exists so we can try to help `hard_link` succeed. + let _ = fs::remove_file(&dst); + + // Attempt to "easy copy" by creating a hard link (symlinks don't work on + // windows), but if that fails just fall back to a slow `copy` operation. let res = fs::hard_link(src, dst); let res = res.or_else(|_| fs::copy(src, dst).map(|_| ())); if let Err(e) = res { |
