diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 916c8e5d187c2a2b4c64748e8ba36ddc37a78e4a..eee90ed2c1c1134bddf09c9154102e8f78b40eb0 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -446,7 +446,7 @@ class RustBuild(object): self.nix_deps_dir = None self.rustc_commit = None - def download_toolchain(self, stage0=True, rustc_channel=None): + def download_toolchain(self, rustc_channel=None): """Fetch the build system for Rust, written in Rust This method will build a cache directory, then it will fetch the @@ -458,35 +458,26 @@ class RustBuild(object): """ if rustc_channel is None: rustc_channel = self.stage0_compiler.version - bin_root = self.bin_root(stage0) + bin_root = self.bin_root() key = self.stage0_compiler.date - if not stage0: - key += str(self.rustc_commit) - if self.rustc(stage0).startswith(bin_root) and \ - (not os.path.exists(self.rustc(stage0)) or - self.program_out_of_date(self.rustc_stamp(stage0), key)): + if self.rustc().startswith(bin_root) and \ + (not os.path.exists(self.rustc()) or + self.program_out_of_date(self.rustc_stamp(), key)): if os.path.exists(bin_root): shutil.rmtree(bin_root) tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz' filename = "rust-std-{}-{}{}".format( rustc_channel, self.build, tarball_suffix) pattern = "rust-std-{}".format(self.build) - self._download_component_helper(filename, pattern, tarball_suffix, stage0) + self._download_component_helper(filename, pattern, tarball_suffix) filename = "rustc-{}-{}{}".format(rustc_channel, self.build, tarball_suffix) - self._download_component_helper(filename, "rustc", tarball_suffix, stage0) - # download-rustc doesn't need its own cargo, it can just use beta's. - if stage0: - filename = "cargo-{}-{}{}".format(rustc_channel, self.build, - tarball_suffix) - self._download_component_helper(filename, "cargo", tarball_suffix) - self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root)) - else: - filename = "rustc-dev-{}-{}{}".format(rustc_channel, self.build, tarball_suffix) - self._download_component_helper( - filename, "rustc-dev", tarball_suffix, stage0 - ) + self._download_component_helper(filename, "rustc", tarball_suffix) + filename = "cargo-{}-{}{}".format(rustc_channel, self.build, + tarball_suffix) + self._download_component_helper(filename, "cargo", tarball_suffix) + self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root)) self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root)) self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root)) @@ -494,7 +485,7 @@ class RustBuild(object): for lib in os.listdir(lib_dir): if lib.endswith(".so"): self.fix_bin_or_dylib(os.path.join(lib_dir, lib)) - with output(self.rustc_stamp(stage0)) as rust_stamp: + with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(key) if self.rustfmt() and self.rustfmt().startswith(bin_root) and ( @@ -518,24 +509,17 @@ class RustBuild(object): rustfmt_stamp.write(self.stage0_rustfmt.channel()) def _download_component_helper( - self, filename, pattern, tarball_suffix, stage0=True, key=None + self, filename, pattern, tarball_suffix, key=None ): if key is None: - if stage0: - key = self.stage0_compiler.date - else: - key = self.rustc_commit + key = self.stage0_compiler.date cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, key) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - if stage0: - base = self._download_url - url = "dist/{}".format(key) - else: - base = "https://ci-artifacts.rust-lang.org" - url = "rustc-builds/{}".format(self.rustc_commit) + base = self._download_url + url = "dist/{}".format(key) tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get( @@ -544,9 +528,9 @@ class RustBuild(object): tarball, self.checksums_sha256, verbose=self.verbose, - do_verify=stage0, + do_verify=True, ) - unpack(tarball, tarball_suffix, self.bin_root(stage0), match=pattern, verbose=self.verbose) + unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose) def fix_bin_or_dylib(self, fname): """Modifies the interpreter section of 'fname' to fix the dynamic linker, @@ -689,17 +673,15 @@ class RustBuild(object): # FIXME: support downloading artifacts from the beta channel self.download_toolchain(False, "nightly") - def rustc_stamp(self, stage0): + def rustc_stamp(self): """Return the path for .rustc-stamp at the given stage >>> rb = RustBuild() >>> rb.build_dir = "build" - >>> rb.rustc_stamp(True) == os.path.join("build", "stage0", ".rustc-stamp") - True - >>> rb.rustc_stamp(False) == os.path.join("build", "ci-rustc", ".rustc-stamp") + >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp") True """ - return os.path.join(self.bin_root(stage0), '.rustc-stamp') + return os.path.join(self.bin_root(), '.rustc-stamp') def rustfmt_stamp(self): """Return the path for .rustfmt-stamp @@ -709,7 +691,7 @@ class RustBuild(object): >>> rb.rustfmt_stamp() == os.path.join("build", "stage0", ".rustfmt-stamp") True """ - return os.path.join(self.bin_root(True), '.rustfmt-stamp') + return os.path.join(self.bin_root(), '.rustfmt-stamp') def program_out_of_date(self, stamp_path, key): """Check if the given program stamp is out of date""" @@ -718,26 +700,21 @@ class RustBuild(object): with open(stamp_path, 'r') as stamp: return key != stamp.read() - def bin_root(self, stage0): + def bin_root(self): """Return the binary root directory for the given stage >>> rb = RustBuild() >>> rb.build_dir = "build" - >>> rb.bin_root(True) == os.path.join("build", "stage0") - True - >>> rb.bin_root(False) == os.path.join("build", "ci-rustc") + >>> rb.bin_root() == os.path.join("build", "stage0") True When the 'build' property is given should be a nested directory: >>> rb.build = "devel" - >>> rb.bin_root(True) == os.path.join("build", "devel", "stage0") + >>> rb.bin_root() == os.path.join("build", "devel", "stage0") True """ - if stage0: - subdir = "stage0" - else: - subdir = "ci-rustc" + subdir = "stage0" return os.path.join(self.build_dir, self.build, subdir) def get_toml(self, key, section=None): @@ -785,9 +762,9 @@ class RustBuild(object): """Return config path for cargo""" return self.program_config('cargo') - def rustc(self, stage0): + def rustc(self): """Return config path for rustc""" - return self.program_config('rustc', stage0) + return self.program_config('rustc') def rustfmt(self): """Return config path for rustfmt""" @@ -795,7 +772,7 @@ class RustBuild(object): return None return self.program_config('rustfmt') - def program_config(self, program, stage0=True): + def program_config(self, program): """Return config path for the given program at the given stage >>> rb = RustBuild() @@ -803,19 +780,15 @@ class RustBuild(object): >>> rb.program_config('rustc') 'rustc' >>> rb.config_toml = '' - >>> cargo_path = rb.program_config('cargo', True) - >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(True), - ... "bin", "cargo") - True - >>> cargo_path = rb.program_config('cargo', False) - >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(False), + >>> cargo_path = rb.program_config('cargo') + >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(), ... "bin", "cargo") True """ config = self.get_toml(program) if config: return os.path.expanduser(config) - return os.path.join(self.bin_root(stage0), "bin", "{}{}".format( + return os.path.join(self.bin_root(), "bin", "{}{}".format( program, self.exe_suffix())) @staticmethod @@ -871,14 +844,14 @@ class RustBuild(object): if "CARGO_BUILD_TARGET" in env: del env["CARGO_BUILD_TARGET"] env["CARGO_TARGET_DIR"] = build_dir - env["RUSTC"] = self.rustc(True) - env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \ + env["RUSTC"] = self.rustc() + env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["LD_LIBRARY_PATH"]) \ if "LD_LIBRARY_PATH" in env else "" - env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \ + env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ if "DYLD_LIBRARY_PATH" in env else "" - env["LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \ + env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" @@ -900,7 +873,7 @@ class RustBuild(object): if self.get_toml("deny-warnings", "rust") != "false": env["RUSTFLAGS"] += " -Dwarnings" - env["PATH"] = os.path.join(self.bin_root(True), "bin") + \ + 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 `{}`".format( @@ -1172,7 +1145,7 @@ def bootstrap(help_triggered): # Fetch/build the bootstrap build.download_toolchain() # Download the master compiler if `download-rustc` is set - build.maybe_download_ci_toolchain() + # build.maybe_download_ci_toolchain() sys.stdout.flush() build.ensure_vendored() build.build_bootstrap() diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index a0ce200883d3c570a39c8b41cd8a45739a94132f..94918cb318f9b71080f9ee182c7cca0573127823 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -915,15 +915,12 @@ fn download_with_retries(&self, tempfile: &str, url: &str) { } } - pub(crate) fn unpack(&self, tarball: &Path, dst: &Path) { + pub(crate) fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) { println!("extracting {} to {}", tarball.display(), dst.display()); if !dst.exists() { t!(fs::create_dir_all(dst)); } - // FIXME: will need to be a parameter once `download-rustc` is moved to rustbuild - const MATCH: &str = "rust-dev"; - // `tarball` ends with `.tar.xz`; strip that suffix // example: `rust-dev-nightly-x86_64-unknown-linux-gnu` let uncompressed_filename = @@ -943,10 +940,10 @@ pub(crate) fn unpack(&self, tarball: &Path, dst: &Path) { continue; } let mut short_path = t!(original_path.strip_prefix(directory_prefix)); - if !short_path.starts_with(MATCH) { + if !short_path.starts_with(pattern) { continue; } - short_path = t!(short_path.strip_prefix(MATCH)); + short_path = t!(short_path.strip_prefix(pattern)); let dst_path = dst.join(short_path); self.verbose(&format!("extracting {} to {}", original_path.display(), dst.display())); if !t!(member.unpack_in(dst)) { @@ -1022,7 +1019,7 @@ fn run(self, builder: &Builder<'_>) -> Interned { .join("lib"); // Avoid deleting the rustlib/ directory we just copied // (in `impl Step for Sysroot`). - if !builder.config.download_rustc { + if !builder.download_rustc() { let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); } @@ -1179,6 +1176,10 @@ pub(crate) fn llvm_link_shared(&self) -> bool { Config::llvm_link_shared(self) } + pub(crate) fn download_rustc(&self) -> bool { + Config::download_rustc(self) + } + /// Prepares an invocation of `cargo` to be run. /// /// This will create a `Command` that represents a pending execution of diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0b430f64e1edc94ee2622f7b4a9b5b750ff76bff..f1960e39a41c7296b370ee78e5693f107adc25c2 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -42,8 +42,10 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { // When downloading stage1, the standard library has already been copied to the sysroot, so // there's no need to rebuild it. - let download_rustc = run.builder.config.download_rustc; - run.all_krates("test").path("library").default_condition(!download_rustc) + let builder = run.builder; + run.all_krates("test") + .path("library") + .lazy_default_condition(Box::new(|| !builder.download_rustc())) } fn make_run(run: RunConfig<'_>) { @@ -66,7 +68,7 @@ fn run(self, builder: &Builder<'_>) { // Don't recompile them. // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. - if builder.config.download_rustc && compiler.stage != 0 { + if builder.download_rustc() && compiler.stage != 0 { return; } @@ -551,7 +553,7 @@ fn run(self, builder: &Builder<'_>) { // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. - if builder.config.download_rustc && compiler.stage != 0 { + if builder.download_rustc() && compiler.stage != 0 { // Copy the existing artifacts instead of rebuilding them. // NOTE: this path is only taken for tools linking to rustc-dev. builder.ensure(Sysroot { compiler }); @@ -995,7 +997,7 @@ fn run(self, builder: &Builder<'_>) -> Interned { t!(fs::create_dir_all(&sysroot)); // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. - if builder.config.download_rustc && compiler.stage != 0 { + if builder.download_rustc() && compiler.stage != 0 { assert_eq!( builder.config.build, compiler.host, "Cross-compiling is not yet supported with `download-rustc`", @@ -1090,7 +1092,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler { let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. - if builder.config.download_rustc { + if builder.download_rustc() { builder.ensure(Sysroot { compiler: target_compiler }); return target_compiler; } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 843d276cd7a88d201beaa91bfcc11755914ce5b3..f51a6481e43fc36f4eaf331043ad7c9b6e340296 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -7,9 +7,11 @@ use std::cmp; use std::collections::{HashMap, HashSet}; use std::env; +use std::ffi::OsStr; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; +use std::process::{exit, Command}; use std::str::FromStr; use crate::builder::{Builder, TaskPath}; @@ -17,7 +19,8 @@ use crate::channel::GitInfo; pub use crate::flags::Subcommand; use crate::flags::{Color, Flags}; -use crate::util::{exe, t}; +use crate::util::{exe, output, program_out_of_date, t}; +use once_cell::sync::OnceCell; use serde::{Deserialize, Deserializer}; macro_rules! check_ci_llvm { @@ -81,7 +84,11 @@ pub struct Config { pub cmd: Subcommand, pub incremental: bool, pub dry_run: bool, - pub download_rustc: bool, + /// `None` if we shouldn't download CI compiler artifacts, or the commit to download if we should. + #[cfg(not(test))] + download_rustc_commit: Option, + #[cfg(test)] + pub download_rustc_commit: Option, pub deny_warnings: bool, pub backtrace_on_ice: bool, @@ -1080,7 +1087,8 @@ pub fn parse(args: &[String]) -> Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); - config.download_rustc = env::var("BOOTSTRAP_DOWNLOAD_RUSTC").as_deref() == Ok("1"); + config.download_rustc_commit = + download_ci_rustc_commit(rust.download_rustc, config.verbose > 0); } else { config.rust_profile_use = flags.rust_profile_use; config.rust_profile_generate = flags.rust_profile_generate; @@ -1192,7 +1200,7 @@ pub fn parse(args: &[String]) -> Config { let default = config.channel == "dev"; config.ignore_git = ignore_git.unwrap_or(default); - let download_rustc = config.download_rustc; + let download_rustc = config.download_rustc_commit.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { Subcommand::Check { .. } => flags.stage.or(build.check_stage).unwrap_or(0), @@ -1309,6 +1317,23 @@ pub(crate) fn llvm_link_shared(builder: &Builder<'_>) -> bool { llvm_link_shared } + /// Return whether we will use a downloaded, pre-compiled version of rustc, or just build from source. + pub(crate) fn download_rustc(builder: &Builder<'_>) -> bool { + static DOWNLOAD_RUSTC: OnceCell = OnceCell::new(); + if builder.config.dry_run && DOWNLOAD_RUSTC.get().is_none() { + // avoid trying to actually download the commit + return false; + } + + *DOWNLOAD_RUSTC.get_or_init(|| match &builder.config.download_rustc_commit { + None => false, + Some(commit) => { + download_ci_rustc(builder, commit); + true + } + }) + } + pub fn verbose(&self) -> bool { self.verbose > 0 } @@ -1358,3 +1383,116 @@ fn threads_from_config(v: u32) -> u32 { n => n, } } + +/// Returns the commit to download, or `None` if we shouldn't download CI artifacts. +fn download_ci_rustc_commit(download_rustc: Option, verbose: bool) -> Option { + // If `download-rustc` is not set, default to rebuilding. + let if_unchanged = match download_rustc { + None | Some(StringOrBool::Bool(false)) => return None, + Some(StringOrBool::Bool(true)) => false, + Some(StringOrBool::String(s)) if s == "if-unchanged" => true, + Some(StringOrBool::String(other)) => { + panic!("unrecognized option for download-rustc: {}", other) + } + }; + + // Handle running from a directory other than the top level + let top_level = output(Command::new("git").args(&["rev-parse", "--show-toplevel"])); + let top_level = top_level.trim_end(); + let compiler = format!("{top_level}/compiler/"); + let library = format!("{top_level}/library/"); + + // Look for a version to compare to based on the current commit. + // Only commits merged by bors will have CI artifacts. + let merge_base = output(Command::new("git").args(&[ + "rev-list", + "--author=bors@rust-lang.org", + "-n1", + "--first-parent", + "HEAD", + ])); + let commit = merge_base.trim_end(); + if commit.is_empty() { + println!("error: could not find commit hash for downloading rustc"); + println!("help: maybe your repository history is too shallow?"); + println!("help: consider disabling `download-rustc`"); + println!("help: or fetch enough history to include one upstream commit"); + exit(1); + } + + // Warn if there were changes to the compiler or standard library since the ancestor commit. + let has_changes = !t!(Command::new("git") + .args(&["diff-index", "--quiet", &commit, "--", &compiler, &library]) + .status()) + .success(); + if has_changes { + if if_unchanged { + if verbose { + println!( + "warning: saw changes to compiler/ or library/ since {commit}; \ + ignoring `download-rustc`" + ); + } + return None; + } + println!( + "warning: `download-rustc` is enabled, but there are changes to \ + compiler/ or library/" + ); + } + + Some(commit.to_string()) +} + +fn download_ci_rustc(builder: &Builder<'_>, commit: &str) { + builder.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})")); + // FIXME: support downloading artifacts from the beta channel + const CHANNEL: &str = "nightly"; + let host = builder.config.build.triple; + let bin_root = builder.out.join(host).join("ci-rustc"); + let rustc_stamp = bin_root.join(".rustc-stamp"); + + if !bin_root.join("bin").join("rustc").exists() || program_out_of_date(&rustc_stamp, commit) { + if bin_root.exists() { + t!(fs::remove_dir_all(&bin_root)); + } + let filename = format!("rust-std-{CHANNEL}-{host}.tar.xz"); + let pattern = format!("rust-std-{host}"); + download_component(builder, filename, &pattern, commit); + let filename = format!("rustc-{CHANNEL}-{host}.tar.xz"); + download_component(builder, filename, "rustc", commit); + // download-rustc doesn't need its own cargo, it can just use beta's. + let filename = format!("rustc-dev-{CHANNEL}-{host}.tar.xz"); + download_component(builder, filename, "rustc-dev", commit); + + builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc")); + builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc")); + let lib_dir = bin_root.join("lib"); + for lib in t!(fs::read_dir(lib_dir)) { + let lib = t!(lib); + if lib.path().extension() == Some(OsStr::new("so")) { + builder.fix_bin_or_dylib(&lib.path()); + } + } + t!(fs::write(rustc_stamp, commit)); + } +} + +/// Download a single component of a CI-built toolchain (not necessarily a published nightly). +// NOTE: intentionally takes an owned string to avoid downloading multiple times by accident +fn download_component(builder: &Builder<'_>, filename: String, prefix: &str, commit: &str) { + let cache_dst = builder.out.join("cache"); + let rustc_cache = cache_dst.join(commit); + if !rustc_cache.exists() { + t!(fs::create_dir_all(&rustc_cache)); + } + + let base = "https://ci-artifacts.rust-lang.org"; + let url = format!("rustc-builds/{commit}"); + let tarball = rustc_cache.join(&filename); + if !tarball.exists() { + builder.download_component(base, &format!("{url}/{filename}"), &tarball); + } + let bin_root = builder.out.join(builder.config.build.triple).join("ci-rustc"); + builder.unpack(&tarball, &bin_root, prefix) +} diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5bb94f297c81410f2bc4e5200611ac7dca2cbe74..d7211b2c2af2f9ba46f2651dfaaf6491ae32fa5e 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -182,7 +182,7 @@ fn download_ci_llvm(builder: &Builder<'_>, llvm_sha: &str) { builder.download_component(base, &format!("{}/{}", url, filename), &tarball); } let llvm_root = builder.config.ci_llvm_root(); - builder.unpack(&tarball, &llvm_root); + builder.unpack(&tarball, &llvm_root, "rust-dev"); } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index bc851568f896b95076ef5926dc01af6f66d380ae..99e9e8794e30bc0e74d6c65b09aaf4b631e984a1 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2058,7 +2058,7 @@ fn run(self, builder: &Builder<'_>) { let test_kind = self.test_kind; let target = self.host; - let compiler = if builder.config.download_rustc { + let compiler = if builder.download_rustc() { builder.compiler(builder.top_stage, target) } else { // Use the previous stage compiler to reuse the artifacts that are @@ -2127,7 +2127,7 @@ fn run(self, builder: &Builder<'_>) { // with. // // Note that this set the host libdir for `download_rustc`, which uses a normal rust distribution. - let libdir = if builder.config.download_rustc { + let libdir = if builder.download_rustc() { builder.rustc_libdir(compiler) } else { builder.sysroot_libdir(compiler, target).to_path_buf() diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 3b30e6de12a63abed65ed9388ea05a4e339e63ee..e1b78904646490899e03e43526c24406fb8a6cac 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -516,7 +516,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf { builder.ensure(compile::Rustc { compiler: build_compiler, target: target_compiler.host }); // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0 // compiler, since you do just as much work. - if !builder.config.dry_run && builder.config.download_rustc && build_compiler.stage == 0 { + if !builder.config.dry_run && builder.download_rustc() && build_compiler.stage == 0 { println!( "warning: `download-rustc` does nothing when building stage1 tools; consider using `--stage 2` instead" );