diff --git a/config.toml.example b/config.toml.example index 19678dc779375..962be2e608501 100644 --- a/config.toml.example +++ b/config.toml.example @@ -258,6 +258,9 @@ # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true +# Flag indicating whether git info will be retrieved from .git automatically. +#ignore-git = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index 5ef18b89841f0..d02bc7972ae9a 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -21,11 +21,10 @@ extern crate bootstrap; use std::env; -use bootstrap::{Flags, Config, Build}; +use bootstrap::{Config, Build}; fn main() { let args = env::args().skip(1).collect::>(); - let flags = Flags::parse(&args); - let config = Config::parse(&flags.build, flags.config.clone()); - Build::new(flags, config).build(); + let config = Config::parse(&args); + Build::new(config).build(); } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d7f795e405534..db2c6dfeb9f74 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -120,28 +120,19 @@ impl StepDescription { fn maybe_run(&self, builder: &Builder, path: Option<&Path>) { let build = builder.build; let hosts = if self.only_build_targets || self.only_build { - &build.config.host[..1] + build.build_triple() } else { &build.hosts }; - // Determine the actual targets participating in this rule. - // NOTE: We should keep the full projection from build triple to - // the hosts for the dist steps, now that the hosts array above is - // truncated to avoid duplication of work in that case. Therefore - // the original non-shadowed hosts array is used below. + // Determine the targets participating in this rule. let targets = if self.only_hosts { - // If --target was specified but --host wasn't specified, - // don't run any host-only tests. Also, respect any `--host` - // overrides as done for `hosts`. - if build.flags.host.len() > 0 { - &build.flags.host[..] - } else if build.flags.target.len() > 0 { + if build.config.run_host_only { &[] } else if self.only_build { - &build.config.host[..1] + build.build_triple() } else { - &build.config.host[..] + &build.hosts } } else { &build.targets @@ -288,7 +279,7 @@ impl<'a> Builder<'a> { let builder = Builder { build: build, - top_stage: build.flags.stage.unwrap_or(2), + top_stage: build.config.stage.unwrap_or(2), kind: kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -307,7 +298,7 @@ impl<'a> Builder<'a> { } pub fn run(build: &Build) { - let (kind, paths) = match build.flags.cmd { + let (kind, paths) = match build.config.cmd { Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), @@ -319,7 +310,7 @@ impl<'a> Builder<'a> { let builder = Builder { build: build, - top_stage: build.flags.stage.unwrap_or(2), + top_stage: build.config.stage.unwrap_or(2), kind: kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -414,22 +405,19 @@ impl<'a> Builder<'a> { } } - pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { - self.ensure(tool::Rustdoc { target_compiler: compiler }) + pub fn rustdoc(&self, host: Interned) -> PathBuf { + self.ensure(tool::Rustdoc { host }) } - pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command { + pub fn rustdoc_cmd(&self, host: Interned) -> Command { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); + let compiler = self.compiler(self.top_stage, host); cmd .env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", if compiler.is_snapshot(&self.build) { - INTERNER.intern_path(self.build.rustc_snapshot_libdir()) - } else { - self.sysroot(compiler) - }) - .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(compiler)); + .env("RUSTDOC_REAL", self.rustdoc(host)); cmd } @@ -483,7 +471,7 @@ impl<'a> Builder<'a> { .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" { - self.rustdoc(compiler) + self.rustdoc(compiler.host) } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }) @@ -543,12 +531,12 @@ impl<'a> Builder<'a> { // Ignore incremental modes except for stage0, since we're // not guaranteeing correctness across builds if the compiler // is changing under your feet.` - if self.flags.incremental && compiler.stage == 0 { + if self.config.incremental && compiler.stage == 0 { let incr_dir = self.incremental_dir(compiler); cargo.env("RUSTC_INCREMENTAL", incr_dir); } - if let Some(ref on_fail) = self.flags.on_fail { + if let Some(ref on_fail) = self.config.on_fail { cargo.env("RUSTC_ON_FAIL", on_fail); } diff --git a/src/bootstrap/cc.rs b/src/bootstrap/cc.rs index 739904e4f7c58..0f25da8a238d0 100644 --- a/src/bootstrap/cc.rs +++ b/src/bootstrap/cc.rs @@ -32,6 +32,7 @@ //! everything. use std::process::Command; +use std::iter; use build_helper::{cc2ar, output}; use gcc; @@ -43,47 +44,41 @@ use cache::Interned; pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - // - // This includes targets that aren't necessarily passed on the commandline - // (FIXME: Perhaps it shouldn't?) - for target in &build.config.target { + for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) { let mut cfg = gcc::Config::new(); cfg.cargo_metadata(false).opt_level(0).debug(false) - .target(target).host(&build.build); + .target(&target).host(&build.build); let config = build.config.target_config.get(&target); if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { cfg.compiler(cc); } else { - set_compiler(&mut cfg, "gcc", *target, config, build); + set_compiler(&mut cfg, "gcc", target, config, build); } let compiler = cfg.get_compiler(); - let ar = cc2ar(compiler.path(), target); - build.verbose(&format!("CC_{} = {:?}", target, compiler.path())); + let ar = cc2ar(compiler.path(), &target); + build.verbose(&format!("CC_{} = {:?}", &target, compiler.path())); if let Some(ref ar) = ar { - build.verbose(&format!("AR_{} = {:?}", target, ar)); + build.verbose(&format!("AR_{} = {:?}", &target, ar)); } - build.cc.insert(*target, (compiler, ar)); + build.cc.insert(target, (compiler, ar)); } // For all host triples we need to find a C++ compiler as well - // - // This includes hosts that aren't necessarily passed on the commandline - // (FIXME: Perhaps it shouldn't?) - for host in &build.config.host { + for host in build.hosts.iter().cloned().chain(iter::once(build.build)) { let mut cfg = gcc::Config::new(); cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true) - .target(host).host(&build.build); - let config = build.config.target_config.get(host); + .target(&host).host(&build.build); + let config = build.config.target_config.get(&host); if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); } else { - set_compiler(&mut cfg, "g++", *host, config, build); + set_compiler(&mut cfg, "g++", host, config, build); } let compiler = cfg.get_compiler(); build.verbose(&format!("CXX_{} = {:?}", host, compiler.path())); - build.cxx.insert(*host, compiler); + build.cxx.insert(host, compiler); } } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index beefaeab90b15..9c1ae83d38281 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -21,6 +21,7 @@ use std::process::Command; use build_helper::output; use Build; +use config::Config; // The version number pub const CFG_RELEASE_NUM: &str = "1.21.0"; @@ -41,9 +42,9 @@ struct Info { } impl GitInfo { - pub fn new(dir: &Path) -> GitInfo { + pub fn new(config: &Config, dir: &Path) -> GitInfo { // See if this even begins to look like a git dir - if !dir.join(".git").exists() { + if config.ignore_git || !dir.join(".git").exists() { return GitInfo { inner: None } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index c65f5a9fb48bf..d4d6fdc5c1b7d 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -164,7 +164,7 @@ impl Step for Cargotest { try_run(build, cmd.arg(&build.initial_cargo) .arg(&out_dir) .env("RUSTC", builder.rustc(compiler)) - .env("RUSTDOC", builder.rustdoc(compiler))); + .env("RUSTDOC", builder.rustdoc(compiler.host))); } } @@ -565,7 +565,7 @@ impl Step for Compiletest { // Avoid depending on rustdoc when we don't need it. if mode == "rustdoc" || mode == "run-make" { - cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler)); + cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); } cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); @@ -625,7 +625,7 @@ impl Step for Compiletest { cmd.arg("--system-llvm"); } - cmd.args(&build.flags.cmd.test_args()); + cmd.args(&build.config.cmd.test_args()); if build.is_verbose() { cmd.arg("--verbose"); @@ -814,13 +814,13 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) { } println!("doc tests for: {}", markdown.display()); - let mut cmd = builder.rustdoc_cmd(compiler); + let mut cmd = builder.rustdoc_cmd(compiler.host); build.add_rust_test_threads(&mut cmd); cmd.arg("--test"); cmd.arg(markdown); cmd.env("RUSTC_BOOTSTRAP", "1"); - let test_args = build.flags.cmd.test_args().join(" "); + let test_args = build.config.cmd.test_args().join(" "); cmd.arg("--test-args").arg(test_args); if build.config.quiet_tests { @@ -1051,7 +1051,7 @@ impl Step for Crate { cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cargo.arg("--"); - cargo.args(&build.flags.cmd.test_args()); + cargo.args(&build.config.cmd.test_args()); if build.config.quiet_tests { cargo.arg("--quiet"); @@ -1147,6 +1147,7 @@ pub struct Distcheck; impl Step for Distcheck { type Output = (); + const ONLY_BUILD: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { run.path("distcheck") @@ -1160,16 +1161,6 @@ impl Step for Distcheck { fn run(self, builder: &Builder) { let build = builder.build; - if *build.build != *"x86_64-unknown-linux-gnu" { - return - } - if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") { - return - } - if !build.config.target.iter().any(|s| s == "x86_64-unknown-linux-gnu") { - return - } - println!("Distcheck"); let dir = build.out.join("tmp").join("distcheck"); let _ = fs::remove_dir_all(&dir); @@ -1236,7 +1227,7 @@ impl Step for Bootstrap { if !build.fail_fast { cmd.arg("--no-fail-fast"); } - cmd.arg("--").args(&build.flags.cmd.test_args()); + cmd.arg("--").args(&build.config.cmd.test_args()); try_run(build, &mut cmd); } diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 308a0ab3076dd..119340a0190c4 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -26,7 +26,7 @@ pub fn clean(build: &Build) { rm_rf(&build.out.join("tmp")); rm_rf(&build.out.join("dist")); - for host in build.config.host.iter() { + for host in &build.hosts { let entries = match build.out.join(host).read_dir() { Ok(iter) => iter, Err(_) => continue, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 92a42b59212b4..33c3638a89473 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -32,6 +32,7 @@ use serde_json; use util::{exe, libdir, is_dylib, copy}; use {Build, Compiler, Mode}; use native; +use tool; use cache::{INTERNER, Interned}; use builder::{Step, RunConfig, ShouldRun, Builder}; @@ -198,6 +199,12 @@ impl Step for StdLink { // for reason why the sanitizers are not built in stage0. copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir); } + + builder.ensure(tool::CleanTools { + compiler: target_compiler, + target: target, + mode: Mode::Libstd, + }); } } @@ -389,6 +396,11 @@ impl Step for TestLink { target); add_to_sysroot(&builder.sysroot_libdir(target_compiler, target), &libtest_stamp(build, compiler, target)); + builder.ensure(tool::CleanTools { + compiler: target_compiler, + target: target, + mode: Mode::Libtest, + }); } } @@ -567,6 +579,11 @@ impl Step for RustcLink { target); add_to_sysroot(&builder.sysroot_libdir(target_compiler, target), &librustc_stamp(build, compiler, target)); + builder.ensure(tool::CleanTools { + compiler: target_compiler, + target: target, + mode: Mode::Librustc, + }); } } @@ -679,10 +696,10 @@ impl Step for Assemble { // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - if builder.build.flags.keep_stage.map_or(false, |s| target_compiler.stage <= s) { + if builder.build.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) { builder.verbose("skipping compilation of compiler due to --keep-stage"); let compiler = build_compiler; - for stage in 0..min(target_compiler.stage, builder.flags.keep_stage.unwrap()) { + for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) { let target_compiler = builder.compiler(stage, target_compiler.host); let target = target_compiler.host; builder.ensure(StdLink { compiler, target_compiler, target }); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c4d5d43152118..aa688fc66e267 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -19,11 +19,14 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::path::PathBuf; use std::process; +use std::cmp; use num_cpus; use toml; use util::{exe, push_exe_path}; use cache::{INTERNER, Interned}; +use flags::Flags; +pub use flags::Subcommand; /// Global configuration for the entire build and/or bootstrap. /// @@ -51,6 +54,17 @@ pub struct Config { pub extended: bool, pub sanitizers: bool, pub profiler: bool, + pub ignore_git: bool, + + pub run_host_only: bool, + + pub on_fail: Option, + pub stage: Option, + pub keep_stage: Option, + pub src: PathBuf, + pub jobs: Option, + pub cmd: Subcommand, + pub incremental: bool, // llvm codegen options pub llvm_enabled: bool, @@ -79,8 +93,8 @@ pub struct Config { pub rust_dist_src: bool, pub build: Interned, - pub host: Vec>, - pub target: Vec>, + pub hosts: Vec>, + pub targets: Vec>, pub local_rebuild: bool, // dist misc @@ -249,6 +263,7 @@ struct Rust { optimize_tests: Option, debuginfo_tests: Option, codegen_tests: Option, + ignore_git: Option, } /// TOML representation of how each build target is configured. @@ -265,7 +280,9 @@ struct TomlTarget { } impl Config { - pub fn parse(build: &str, file: Option) -> Config { + pub fn parse(args: &[String]) -> Config { + let flags = Flags::parse(&args); + let file = flags.config.clone(); let mut config = Config::default(); config.llvm_enabled = true; config.llvm_optimize = true; @@ -277,11 +294,22 @@ impl Config { config.docs = true; config.rust_rpath = true; config.rust_codegen_units = 1; - config.build = INTERNER.intern_str(build); config.channel = "dev".to_string(); config.codegen_tests = true; + config.ignore_git = false; config.rust_dist_src = true; + config.on_fail = flags.on_fail; + config.stage = flags.stage; + config.src = flags.src; + config.jobs = flags.jobs; + config.cmd = flags.cmd; + config.incremental = flags.incremental; + config.keep_stage = flags.keep_stage; + + // If --target was specified but --host wasn't specified, don't run any host-only tests. + config.run_host_only = flags.host.is_empty() && !flags.target.is_empty(); + let toml = file.map(|file| { let mut f = t!(File::open(&file)); let mut contents = String::new(); @@ -298,20 +326,37 @@ impl Config { let build = toml.build.clone().unwrap_or(Build::default()); set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x))); - config.host.push(config.build.clone()); + set(&mut config.build, flags.build); + if config.build.is_empty() { + // set by bootstrap.py + config.build = INTERNER.intern_str(&env::var("BUILD").unwrap()); + } + config.hosts.push(config.build.clone()); for host in build.host.iter() { let host = INTERNER.intern_str(host); - if !config.host.contains(&host) { - config.host.push(host); + if !config.hosts.contains(&host) { + config.hosts.push(host); } } - for target in config.host.iter().cloned() + for target in config.hosts.iter().cloned() .chain(build.target.iter().map(|s| INTERNER.intern_str(s))) { - if !config.target.contains(&target) { - config.target.push(target); + if !config.targets.contains(&target) { + config.targets.push(target); } } + config.hosts = if !flags.host.is_empty() { + flags.host + } else { + config.hosts + }; + config.targets = if !flags.target.is_empty() { + flags.target + } else { + config.targets + }; + + config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); config.python = build.python.map(PathBuf::from); @@ -327,6 +372,7 @@ impl Config { set(&mut config.sanitizers, build.sanitizers); set(&mut config.profiler, build.profiler); set(&mut config.openssl_static, build.openssl_static); + config.verbose = cmp::max(config.verbose, flags.verbose); if let Some(ref install) = toml.install { config.prefix = install.prefix.clone().map(PathBuf::from); @@ -373,6 +419,7 @@ impl Config { set(&mut config.use_jemalloc, rust.use_jemalloc); set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); + set(&mut config.ignore_git, rust.ignore_git); config.rustc_default_linker = rust.default_linker.clone(); config.rustc_default_ar = rust.default_ar.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); @@ -505,11 +552,11 @@ impl Config { match key { "CFG_BUILD" if value.len() > 0 => self.build = INTERNER.intern_str(value), "CFG_HOST" if value.len() > 0 => { - self.host.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); + self.hosts.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); } "CFG_TARGET" if value.len() > 0 => { - self.target.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); + self.targets.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); } "CFG_EXPERIMENTAL_TARGETS" if value.len() > 0 => { self.llvm_experimental_targets = Some(value.to_string()); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c322d75dd5b45..bfcfb5f9a37f8 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -413,8 +413,7 @@ impl Step for Rustc { t!(fs::create_dir_all(image.join("bin"))); cp_r(&src.join("bin"), &image.join("bin")); - install(&builder.ensure(tool::Rustdoc { target_compiler: compiler }), - &image.join("bin"), 0o755); + install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755); // Copy runtime DLLs needed by the compiler if libdir != "bin" { @@ -546,7 +545,7 @@ impl Step for Std { // We want to package up as many target libraries as possible // for the `rust-std` package, so if this is a host target we // depend on librustc and otherwise we just depend on libtest. - if build.config.host.iter().any(|t| t == target) { + if build.hosts.iter().any(|t| t == target) { builder.ensure(compile::Rustc { compiler, target }); } else { builder.ensure(compile::Test { compiler, target }); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 1ee578bb62b19..f0e0874abed60 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -260,7 +260,7 @@ fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned, pub stage: Option, pub keep_stage: Option, - pub build: Interned, + pub build: Option>, + pub host: Vec>, pub target: Vec>, pub config: Option, @@ -68,6 +69,14 @@ pub enum Subcommand { }, } +impl Default for Subcommand { + fn default() -> Subcommand { + Subcommand::Build { + paths: vec![PathBuf::from("nowhere")], + } + } +} + impl Flags { pub fn parse(args: &[String]) -> Flags { let mut extra_help = String::new(); @@ -243,10 +252,8 @@ Arguments: // All subcommands can have an optional "Available paths" section if matches.opt_present("verbose") { - let flags = Flags::parse(&["build".to_string()]); - let mut config = Config::parse(&flags.build, cfg_file.clone()); - config.build = flags.build.clone(); - let mut build = Build::new(flags, config); + let config = Config::parse(&["build".to_string()]); + let mut build = Build::new(config); metadata::build(&mut build); let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); @@ -320,9 +327,7 @@ Arguments: stage: stage, on_fail: matches.opt_str("on-fail"), keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: INTERNER.intern_string(matches.opt_str("build").unwrap_or_else(|| { - env::var("BUILD").unwrap() - })), + build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)), host: split(matches.opt_strs("host")) .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), target: split(matches.opt_strs("target")) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index ebfda1e619bd8..89690e444d1f6 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -28,7 +28,7 @@ pub fn install_docs(builder: &Builder, stage: u32, host: Interned) { } pub fn install_std(builder: &Builder, stage: u32) { - for target in builder.build.config.target.iter() { + for target in &builder.build.targets { install_sh(builder, "std", "rust-std", stage, Some(*target)); } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a8485d1d152d1..1452a38f6ed28 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -136,13 +136,13 @@ extern crate toml; extern crate libc; use std::cell::Cell; -use std::cmp; use std::collections::{HashSet, HashMap}; use std::env; use std::fs::{self, File}; use std::io::Read; use std::path::{PathBuf, Path}; use std::process::Command; +use std::slice; use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; @@ -187,7 +187,7 @@ mod job { } pub use config::Config; -pub use flags::{Flags, Subcommand}; +use flags::Subcommand; use cache::{Interned, INTERNER}; /// A structure representing a Rust compiler. @@ -215,9 +215,6 @@ pub struct Build { // User-specified configuration via config.toml config: Config, - // User-specified configuration via CLI flags - flags: Flags, - // Derived properties from the above two configurations src: PathBuf, out: PathBuf, @@ -288,9 +285,9 @@ impl Build { /// line and the filesystem `config`. /// /// By default all build output will be placed in the current directory. - pub fn new(flags: Flags, config: Config) -> Build { + pub fn new(config: Config) -> Build { let cwd = t!(env::current_dir()); - let src = flags.src.clone(); + let src = config.src.clone(); let out = cwd.join("build"); let is_sudo = match env::var_os("SUDO_USER") { @@ -302,43 +299,21 @@ impl Build { } None => false, }; - let rust_info = channel::GitInfo::new(&src); - let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo")); - let rls_info = channel::GitInfo::new(&src.join("src/tools/rls")); - - let hosts = if !flags.host.is_empty() { - for host in flags.host.iter() { - if !config.host.contains(host) { - panic!("specified host `{}` is not in configuration", host); - } - } - flags.host.clone() - } else { - config.host.clone() - }; - let targets = if !flags.target.is_empty() { - for target in flags.target.iter() { - if !config.target.contains(target) { - panic!("specified target `{}` is not in configuration", target); - } - } - flags.target.clone() - } else { - config.target.clone() - }; + let rust_info = channel::GitInfo::new(&config, &src); + let cargo_info = channel::GitInfo::new(&config, &src.join("src/tools/cargo")); + let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls")); Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), local_rebuild: config.local_rebuild, - fail_fast: flags.cmd.fail_fast(), - verbosity: cmp::max(flags.verbose, config.verbose), + fail_fast: config.cmd.fail_fast(), + verbosity: config.verbose, - build: config.host[0].clone(), - hosts: hosts, - targets: targets, + build: config.build, + hosts: config.hosts.clone(), + targets: config.targets.clone(), - flags: flags, config: config, src: src, out: out, @@ -357,13 +332,19 @@ impl Build { } } + pub fn build_triple(&self) -> &[Interned] { + unsafe { + slice::from_raw_parts(&self.build, 1) + } + } + /// Executes the entire build, as configured by the flags and configuration. pub fn build(&mut self) { unsafe { job::setup(self); } - if let Subcommand::Clean = self.flags.cmd { + if let Subcommand::Clean = self.config.cmd { return clean::clean(self); } @@ -608,7 +589,7 @@ impl Build { /// Returns the number of parallel jobs that have been configured for this /// build. fn jobs(&self) -> u32 { - self.flags.jobs.unwrap_or_else(|| num_cpus::get() as u32) + self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32) } /// Returns the path to the C compiler for the target specified. @@ -727,7 +708,7 @@ impl Build { fn force_use_stage1(&self, compiler: Compiler, target: Interned) -> bool { !self.config.full_bootstrap && compiler.stage >= 2 && - self.config.host.iter().any(|h| *h == target) + self.hosts.iter().any(|h| *h == target) } /// Returns the directory that OpenSSL artifacts are compiled into if diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 7063b28f19d01..436a13500f254 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -85,7 +85,7 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = build.config.host.iter() + let building_llvm = build.hosts.iter() .filter_map(|host| build.config.target_config.get(host)) .any(|config| config.llvm_config.is_none()); if building_llvm || build.config.sanitizers { @@ -114,7 +114,7 @@ pub fn check(build: &mut Build) { // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. - for target in &build.config.target { + for target in &build.targets { // On emscripten we don't actually need the C compiler to just // build the target artifacts, only for testing. For the sake // of easier bot configuration, just skip detection. @@ -128,7 +128,7 @@ pub fn check(build: &mut Build) { } } - for host in build.config.host.iter() { + for host in &build.hosts { cmd_finder.must_have(build.cxx(*host).unwrap()); // The msvc hosts don't use jemalloc, turn it off globally to @@ -144,7 +144,7 @@ pub fn check(build: &mut Build) { panic!("FileCheck executable {:?} does not exist", filecheck); } - for target in &build.config.target { + for target in &build.targets { // Can't compile for iOS unless we're on macOS if target.contains("apple-ios") && !build.build.contains("apple-darwin") { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 862b3e2b1edb0..d798e8de3dffa 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -23,10 +23,10 @@ use channel::GitInfo; use cache::Interned; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -struct CleanTools { - compiler: Compiler, - target: Interned, - mode: Mode, +pub struct CleanTools { + pub compiler: Compiler, + pub target: Interned, + pub mode: Mode, } impl Step for CleanTools { @@ -82,7 +82,6 @@ impl Step for ToolBuild { let target = self.target; let tool = self.tool; - builder.ensure(CleanTools { compiler, target, mode: self.mode }); match self.mode { Mode::Libstd => builder.ensure(compile::Std { compiler, target }), Mode::Libtest => builder.ensure(compile::Test { compiler, target }), @@ -93,36 +92,46 @@ impl Step for ToolBuild { let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); println!("Building stage{} tool {} ({})", compiler.stage, tool, target); - let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build"); - let dir = build.src.join("src/tools").join(tool); - cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); - - // We don't want to build tools dynamically as they'll be running across - // stages and such and it's just easier if they're not dynamically linked. - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - - if let Some(dir) = build.openssl_install_dir(target) { - cargo.env("OPENSSL_STATIC", "1"); - cargo.env("OPENSSL_DIR", dir); - cargo.env("LIBZ_SYS_STATIC", "1"); - } + let mut cargo = prepare_tool_cargo(builder, compiler, target, tool); + build.run(&mut cargo); + build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host)) + } +} - cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel); +fn prepare_tool_cargo( + builder: &Builder, + compiler: Compiler, + target: Interned, + tool: &'static str, +) -> Command { + let build = builder.build; + let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build"); + let dir = build.src.join("src/tools").join(tool); + cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); + + // We don't want to build tools dynamically as they'll be running across + // stages and such and it's just easier if they're not dynamically linked. + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + if let Some(dir) = build.openssl_install_dir(target) { + cargo.env("OPENSSL_STATIC", "1"); + cargo.env("OPENSSL_DIR", dir); + cargo.env("LIBZ_SYS_STATIC", "1"); + } - let info = GitInfo::new(&dir); - if let Some(sha) = info.sha() { - cargo.env("CFG_COMMIT_HASH", sha); - } - if let Some(sha_short) = info.sha_short() { - cargo.env("CFG_SHORT_COMMIT_HASH", sha_short); - } - if let Some(date) = info.commit_date() { - cargo.env("CFG_COMMIT_DATE", date); - } + cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel); - build.run(&mut cargo); - build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host)) + let info = GitInfo::new(&build.config, &dir); + if let Some(sha) = info.sha() { + cargo.env("CFG_COMMIT_HASH", sha); + } + if let Some(sha_short) = info.sha_short() { + cargo.env("CFG_SHORT_COMMIT_HASH", sha_short); } + if let Some(date) = info.commit_date() { + cargo.env("CFG_COMMIT_DATE", date); + } + cargo } macro_rules! tool { @@ -226,7 +235,7 @@ impl Step for RemoteTestServer { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { - pub target_compiler: Compiler, + pub host: Interned, } impl Step for Rustdoc { @@ -240,14 +249,20 @@ impl Step for Rustdoc { fn make_run(run: RunConfig) { run.builder.ensure(Rustdoc { - target_compiler: run.builder.compiler(run.builder.top_stage, run.host), + host: run.host, }); } fn run(self, builder: &Builder) -> PathBuf { - let target_compiler = self.target_compiler; + let build = builder.build; + let target_compiler = builder.compiler(builder.top_stage, self.host); + let target = target_compiler.host; let build_compiler = if target_compiler.stage == 0 { builder.compiler(0, builder.build.build) + } else if target_compiler.stage >= 2 { + // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of + // building rustdoc itself. + builder.compiler(target_compiler.stage, builder.build.build) } else { // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage @@ -255,12 +270,18 @@ impl Step for Rustdoc { builder.compiler(target_compiler.stage - 1, builder.build.build) }; - let tool_rustdoc = builder.ensure(ToolBuild { - compiler: build_compiler, - target: target_compiler.host, - tool: "rustdoc", - mode: Mode::Librustc, - }); + builder.ensure(compile::Rustc { compiler: build_compiler, target }); + + let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); + println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host); + + let mut cargo = prepare_tool_cargo(builder, build_compiler, target, "rustdoc"); + build.run(&mut cargo); + // Cargo adds a number of paths to the dylib search path on windows, which results in + // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" + // rustdoc a different name. + let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target) + .join(exe("rustdoc-tool-binary", &target_compiler.host)); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { diff --git a/src/tools/rustdoc/Cargo.toml b/src/tools/rustdoc/Cargo.toml index b6edb76d7f98f..344f617ef95bc 100644 --- a/src/tools/rustdoc/Cargo.toml +++ b/src/tools/rustdoc/Cargo.toml @@ -3,8 +3,11 @@ name = "rustdoc-tool" version = "0.0.0" authors = ["The Rust Project Developers"] +# Cargo adds a number of paths to the dylib search path on windows, which results in +# the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" +# rustdoc a different name. [[bin]] -name = "rustdoc" +name = "rustdoc-tool-binary" path = "main.rs" [dependencies]