diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index f4a86e263967d..8c7675285dcfc 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -57,7 +57,7 @@ impl Step for Std { builder.require_submodule("library/stdarch", None); let target = self.target; - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, false); let mut cargo = builder::Cargo::new( builder, @@ -192,7 +192,7 @@ impl Step for Rustc { /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, false); let target = self.target; if compiler.stage != 0 { @@ -274,7 +274,7 @@ impl Step for CodegenBackend { return; } - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, false); let target = self.target; let backend = self.backend; @@ -329,7 +329,7 @@ impl Step for RustAnalyzer { } fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, true); let target = self.target; builder.ensure(Rustc::new(target, builder)); @@ -411,7 +411,7 @@ fn run_tool_check_step( path: &str, ) { let display_name = path.rsplit('/').next().unwrap(); - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, true); builder.ensure(Rustc::new(target, builder)); diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 21e9fea936387..492cbc17e3f51 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -60,7 +60,7 @@ macro_rules! clean_crate_tree { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.target); + let compiler = builder.compiler(builder.top_stage, run.target, false); builder.ensure(Self { crates: run.cargo_crates_in_set(), compiler }); } diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index fe8c89f7a5394..e963320858952 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -144,7 +144,7 @@ impl Step for Std { builder.require_submodule("library/stdarch", None); let target = self.target; - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, false); let mut cargo = builder::Cargo::new( builder, @@ -204,7 +204,7 @@ impl Step for Rustc { /// This will lint the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, false); let target = self.target; if compiler.stage != 0 { @@ -254,7 +254,7 @@ impl Step for Rustc { macro_rules! lint_any { ($( - $name:ident, $path:expr, $readable_name:expr + $name:ident, $path:expr, $readable_name:expr, $mode:expr $(,lint_by_default = $lint_by_default:expr)* ; )+) => { @@ -283,7 +283,7 @@ macro_rules! lint_any { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, builder.top_stage > 0 && $mode == Mode::ToolRustc); let target = self.target; builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check))); @@ -291,7 +291,7 @@ macro_rules! lint_any { let cargo = prepare_tool_cargo( builder, compiler, - Mode::ToolRustc, + $mode, target, Kind::Clippy, $path, @@ -301,7 +301,7 @@ macro_rules! lint_any { let _guard = builder.msg_tool( Kind::Clippy, - Mode::ToolRustc, + $mode, $readable_name, compiler.stage, &compiler.host, @@ -309,7 +309,7 @@ macro_rules! lint_any { ); let stringified_name = stringify!($name).to_lowercase(); - let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) + let stamp = BuildStamp::new(&builder.cargo_out(compiler, $mode, target)) .with_prefix(&format!("{}-check", stringified_name)); run_cargo( @@ -328,31 +328,31 @@ macro_rules! lint_any { } lint_any!( - Bootstrap, "src/bootstrap", "bootstrap"; - BuildHelper, "src/build_helper", "build_helper"; - BuildManifest, "src/tools/build-manifest", "build-manifest"; - CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri"; - Clippy, "src/tools/clippy", "clippy"; - CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; - CodegenGcc, "compiler/rustc_codegen_gcc", "rustc-codegen-gcc"; - Compiletest, "src/tools/compiletest", "compiletest"; - CoverageDump, "src/tools/coverage-dump", "coverage-dump"; - Jsondocck, "src/tools/jsondocck", "jsondocck"; - Jsondoclint, "src/tools/jsondoclint", "jsondoclint"; - LintDocs, "src/tools/lint-docs", "lint-docs"; - LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker"; - Miri, "src/tools/miri", "miri"; - MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools"; - OptDist, "src/tools/opt-dist", "opt-dist"; - RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; - RemoteTestServer, "src/tools/remote-test-server", "remote-test-server"; - Rls, "src/tools/rls", "rls"; - RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer"; - Rustdoc, "src/librustdoc", "clippy"; - Rustfmt, "src/tools/rustfmt", "rustfmt"; - RustInstaller, "src/tools/rust-installer", "rust-installer"; - Tidy, "src/tools/tidy", "tidy"; - TestFloatParse, "src/etc/test-float-parse", "test-float-parse"; + Bootstrap, "src/bootstrap", "bootstrap", Mode::ToolBootstrap; + BuildHelper, "src/build_helper", "build_helper", Mode::ToolBootstrap; + BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolBootstrap; + CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustc; + Clippy, "src/tools/clippy", "clippy", Mode::ToolRustc; + CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata", Mode::ToolBootstrap; + CodegenGcc, "compiler/rustc_codegen_gcc", "rustc-codegen-gcc", Mode::ToolRustc; + Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolBootstrap; + CoverageDump, "src/tools/coverage-dump", "coverage-dump", Mode::ToolBootstrap; + Jsondocck, "src/tools/jsondocck", "jsondocck", Mode::ToolBootstrap; + Jsondoclint, "src/tools/jsondoclint", "jsondoclint", Mode::ToolBootstrap; + LintDocs, "src/tools/lint-docs", "lint-docs", Mode::ToolBootstrap; + LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker", Mode::ToolRustc; + Miri, "src/tools/miri", "miri", Mode::ToolRustc; + MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools", Mode::ToolRustc; + OptDist, "src/tools/opt-dist", "opt-dist", Mode::ToolBootstrap; + RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolBootstrap; + RemoteTestServer, "src/tools/remote-test-server", "remote-test-server", Mode::ToolBootstrap; + Rls, "src/tools/rls", "rls", Mode::ToolBootstrap; + RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustc; + Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustc; + Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustc; + RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::ToolBootstrap; + Tidy, "src/tools/tidy", "tidy", Mode::ToolBootstrap; + TestFloatParse, "src/etc/test-float-parse", "test-float-parse", Mode::ToolStd; ); #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index f447d186a5242..8a3c199e515b3 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -110,7 +110,7 @@ impl Step for Std { && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none(); run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple(), false), target: run.target, crates, force_recompile, @@ -162,7 +162,7 @@ impl Step for Std { let mut target_deps = builder.ensure(StartupObjects { compiler, target }); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target, false); if compiler_to_use != compiler { builder.ensure(Std::new(compiler_to_use, target)); let msg = if compiler_to_use.host == target { @@ -264,7 +264,7 @@ impl Step for Std { builder.ensure(StdLink::from_std( self, - builder.compiler(compiler.stage, builder.config.build), + builder.compiler(compiler.stage, builder.config.build, false), )); } } @@ -770,7 +770,7 @@ impl Step for StartupObjects { fn make_run(run: RunConfig<'_>) { run.builder.ensure(StartupObjects { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple(), false), target: run.target, }); } @@ -837,11 +837,18 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte } } +/// Low-level implementation of the compiler's compilation process. +/// +/// DO NOT `pub` the fields of this type and AVOID using it anywhere +/// unless it's in the `Assemble` step. +/// +/// If you want to build a compiler for a specific stage and target, use +/// `Builder::compiler` instead. #[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] pub struct Rustc { - pub target: TargetSelection, + target: TargetSelection, /// The **previous** compiler used to compile this compiler. - pub compiler: Compiler, + compiler: Compiler, /// Whether to build a subset of crates, rather than the whole compiler. /// /// This should only be requested by the user, not used within bootstrap itself. @@ -851,6 +858,9 @@ pub struct Rustc { } impl Rustc { + /// Serves as a helpful util for unit tests and should NEVER exist + /// for non-test environment. + #[cfg(test)] pub fn new(compiler: Compiler, target: TargetSelection) -> Self { Self { target, compiler, crates: Default::default() } } @@ -884,7 +894,7 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { let crates = run.cargo_crates_in_set(); run.builder.ensure(Rustc { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple(), false), target: run.target, crates, }); @@ -921,9 +931,10 @@ impl Step for Rustc { return compiler.stage; } - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target, false); if compiler_to_use != compiler { - builder.ensure(Rustc::new(compiler_to_use, target)); + let _ = builder.compiler(compiler_to_use.stage, target, false); + let msg = if compiler_to_use.host == target { format!( "Uplifting rustc (stage{} -> stage{})", @@ -946,7 +957,7 @@ impl Step for Rustc { // Ensure that build scripts and proc macros have a std / libproc_macro to link against. builder.ensure(Std::new( - builder.compiler(self.compiler.stage, builder.config.build), + builder.compiler(self.compiler.stage, builder.config.build, false), builder.config.build, )); @@ -1012,7 +1023,7 @@ impl Step for Rustc { builder.ensure(RustcLink::from_rustc( self, - builder.compiler(compiler.stage, builder.config.build), + builder.compiler(compiler.stage, builder.config.build, false), )); compiler.stage @@ -1413,7 +1424,7 @@ impl Step for CodegenBackend { run.builder.ensure(CodegenBackend { target: run.target, - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple(), false), backend: backend.clone(), }); } @@ -1424,7 +1435,7 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - builder.ensure(Rustc::new(compiler, target)); + let _ = builder.compiler(compiler.stage, target, false); if builder.config.keep_stage.contains(&compiler.stage) { builder.info( @@ -1436,7 +1447,7 @@ impl Step for CodegenBackend { return; } - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target, false); if compiler_to_use != compiler { builder.ensure(CodegenBackend { compiler: compiler_to_use, target, backend }); return; @@ -1734,7 +1745,7 @@ impl Step for Assemble { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Assemble { - target_compiler: run.builder.compiler(run.builder.top_stage + 1, run.target), + target_compiler: run.builder.compiler(run.builder.top_stage + 1, run.target, false), }); } @@ -1792,7 +1803,7 @@ impl Step for Assemble { } } - let maybe_install_llvm_bitcode_linker = |compiler| { + let maybe_install_llvm_bitcode_linker = |compiler: Compiler| { if builder.config.llvm_bitcode_linker_enabled { let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { compiler, @@ -1835,7 +1846,8 @@ impl Step for Assemble { // // FIXME: It may be faster if we build just a stage 1 compiler and then // use that to bootstrap this compiler forward. - let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + let mut build_compiler = + builder.compiler(target_compiler.stage - 1, builder.config.build, false); // Build enzyme let enzyme_install = if builder.config.llvm_enzyme { @@ -1861,7 +1873,11 @@ 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). - let actual_stage = builder.ensure(Rustc::new(build_compiler, target_compiler.host)); + let actual_stage = builder.ensure(Rustc { + compiler: build_compiler, + target: target_compiler.host, + crates: vec![], + }); // Current build_compiler.stage might be uplifted instead of being built; so update it // to not fail while linking the artifacts. build_compiler.stage = actual_stage; @@ -1974,7 +1990,11 @@ impl Step for Assemble { ); } - maybe_install_llvm_bitcode_linker(build_compiler); + { + let mut compiler_for_rustc_tool = build_compiler; + compiler_for_rustc_tool.downgraded_from = Some(target_compiler.stage); + maybe_install_llvm_bitcode_linker(compiler_for_rustc_tool); + } // Ensure that `libLLVM.so` ends up in the newly build compiler directory, // so that it can be found when the newly built `rustc` is run. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 18f920b85eee0..7cb9c752e7822 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -367,8 +367,9 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustc { compiler: run.builder.compiler(run.builder.top_stage, run.target) }); + run.builder.ensure(Rustc { + compiler: run.builder.compiler(run.builder.top_stage, run.target, false), + }); } /// Creates the `rustc` installer component. @@ -423,6 +424,7 @@ impl Step for Rustc { compiler.stage, builder.config.build, compiler.host, + false, ), target: compiler.host, }, @@ -663,6 +665,7 @@ impl Step for Std { run.builder.top_stage, run.builder.config.build, run.target, + false, ), target: run.target, }); @@ -681,7 +684,7 @@ impl Step for Std { let mut tarball = Tarball::new(builder, "rust-std", &target.triple); tarball.include_target_in_component_name(true); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target, false); let stamp = build_stamp::libstd_stamp(builder, compiler_to_use, target); verify_uefi_rlib_format(builder, target, &stamp); copy_target_libs(builder, target, tarball.image_dir(), &stamp); @@ -715,6 +718,7 @@ impl Step for RustcDev { run.builder.top_stage, run.builder.config.build, run.target, + false, ), target: run.target, }); @@ -727,11 +731,11 @@ impl Step for RustcDev { return None; } - builder.ensure(compile::Rustc::new(compiler, target)); + let _ = builder.compiler(compiler.stage, target, false); let tarball = Tarball::new(builder, "rustc-dev", &target.triple); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target, false); let stamp = build_stamp::librustc_stamp(builder, compiler_to_use, target); copy_target_libs(builder, target, tarball.image_dir(), &stamp); @@ -777,6 +781,7 @@ impl Step for Analysis { run.builder.top_stage, run.builder.config.build, run.target, + false, ), target: run.target, }); @@ -1125,6 +1130,7 @@ impl Step for Cargo { run.builder.top_stage, run.builder.config.build, run.target, + true, ), target: run.target, }); @@ -1174,6 +1180,7 @@ impl Step for Rls { run.builder.top_stage, run.builder.config.build, run.target, + false, ), target: run.target, }); @@ -1216,6 +1223,7 @@ impl Step for RustAnalyzer { run.builder.top_stage, run.builder.config.build, run.target, + true, ), target: run.target, }); @@ -1258,6 +1266,7 @@ impl Step for Clippy { run.builder.top_stage, run.builder.config.build, run.target, + true, ), target: run.target, }); @@ -1305,6 +1314,7 @@ impl Step for Miri { run.builder.top_stage, run.builder.config.build, run.target, + true, ), target: run.target, }); @@ -1355,7 +1365,7 @@ impl Step for CodegenBackend { } run.builder.ensure(CodegenBackend { - compiler: run.builder.compiler(run.builder.top_stage, run.target), + compiler: run.builder.compiler(run.builder.top_stage, run.target, false), backend: backend.clone(), }); } @@ -1443,6 +1453,7 @@ impl Step for Rustfmt { run.builder.top_stage, run.builder.config.build, run.target, + true, ), target: run.target, }); @@ -1493,7 +1504,7 @@ impl Step for Extended { fn run(self, builder: &Builder<'_>) { let target = self.target; let stage = self.stage; - let compiler = builder.compiler_for(self.stage, self.host, self.target); + let compiler = builder.compiler_for(self.stage, self.host, self.target, false); builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target)); @@ -1512,7 +1523,7 @@ impl Step for Extended { // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) })); + tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target, false) })); tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std")); if target.is_windows_gnu() { @@ -1530,7 +1541,7 @@ impl Step for Extended { add_component!("miri" => Miri { compiler, target }); add_component!("analysis" => Analysis { compiler, target }); add_component!("rustc-codegen-cranelift" => CodegenBackend { - compiler: builder.compiler(stage, target), + compiler: builder.compiler(stage, target, false), backend: "cranelift".to_string(), }); add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target}); @@ -2104,8 +2115,7 @@ pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself. pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) { - let dst_libdir = - sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target })); + let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler::new(1, target))); // We do not need to copy LLVM files into the sysroot if it is not // dynamically linked; it is already included into librustc_llvm // statically. @@ -2224,6 +2234,7 @@ impl Step for LlvmBitcodeLinker { run.builder.top_stage, run.builder.config.build, run.target, + true, ), target: run.target, }); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0eb4080c053a7..e65f53e0ba127 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -209,7 +209,7 @@ impl Step for TheBook { fn make_run(run: RunConfig<'_>) { run.builder.ensure(TheBook { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } @@ -329,7 +329,7 @@ impl Step for Standalone { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Standalone { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } @@ -431,7 +431,7 @@ impl Step for Releases { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Releases { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } @@ -449,7 +449,7 @@ impl Step for Releases { t!(fs::create_dir_all(&out)); builder.ensure(Standalone { - compiler: builder.compiler(builder.top_stage, builder.config.build), + compiler: builder.compiler(builder.top_stage, builder.config.build, false), target, }); @@ -698,7 +698,7 @@ fn doc_std( extra_args: &[&str], requested_crates: &[String], ) { - let compiler = builder.compiler(stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.build, false); let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" }; let target_dir = builder.stage_out(compiler, Mode::Std).join(target).join(target_doc_dir_name); @@ -801,7 +801,7 @@ impl Step for Rustc { // Build the standard library, so that proc-macros can use it. // (Normally, only the metadata would be necessary, but proc-macros are special since they run at compile-time.) - let compiler = builder.compiler(stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.build, false); builder.ensure(compile::Std::new(compiler, builder.config.build)); let _guard = builder.msg_sysroot_tool( @@ -943,7 +943,7 @@ macro_rules! tool_doc { let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.build, false); builder.ensure(compile::Std::new(compiler, target)); if true $(&& $rustc_tool)? { @@ -953,7 +953,7 @@ macro_rules! tool_doc { // Rustdoc needs the rustc sysroot available to build. // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed // with strange errors, but only on a full bors test ... - builder.ensure(compile::Rustc::new(compiler, target)); + let _ = builder.compiler(compiler.stage, target, true); } // Build cargo command. @@ -1173,7 +1173,7 @@ impl Step for RustcBook { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustcBook { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, validate: false, }); @@ -1260,7 +1260,7 @@ impl Step for Reference { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Reference { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 4f96d67a5bd89..b1e53b50de4f0 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -185,7 +185,7 @@ macro_rules! install { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } @@ -267,7 +267,7 @@ install!((self, builder, _config), }; Rustc, path = "compiler/rustc", true, only_hosts: true, { let tarball = builder.ensure(dist::Rustc { - compiler: builder.compiler(builder.top_stage, self.target), + compiler: builder.compiler(builder.top_stage, self.target, false), }); install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball); }; diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 5b83080a3260f..3cab4b7c898b7 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -6,7 +6,7 @@ use crate::core::config::DebuginfoLevel; /// Performs profiling using `rustc-perf` on a built version of the compiler. pub fn perf(builder: &Builder<'_>) { let collector = builder.ensure(RustcPerf { - compiler: builder.compiler(0, builder.config.build), + compiler: builder.compiler(0, builder.config.build, false), target: builder.config.build, }); @@ -15,7 +15,7 @@ pub fn perf(builder: &Builder<'_>) { Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); } - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build, false); builder.ensure(Std::new(compiler, builder.config.build)); let sysroot = builder.ensure(Sysroot::new(compiler)); let rustc = sysroot.join("bin/rustc"); diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 8513c59808c6b..5511cae378284 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -124,12 +124,12 @@ impl Step for Miri { } // This compiler runs on the host, we'll just use it for the target. - let target_compiler = builder.compiler(stage, host); + let target_compiler = builder.compiler(stage, host, false); // 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 // compilers, which isn't what we want. Rustdoc should be linked in the same way as the // rustc compiler it's paired with, so it must be built with the previous stage compiler. - let host_compiler = builder.compiler(stage - 1, host); + let host_compiler = builder.compiler(stage, host, true); // Get a target sysroot for Miri. let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 825e5452f0e6a..a66416555f81d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -68,7 +68,7 @@ impl Step for CrateBootstrap { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; - let compiler = builder.compiler(0, bootstrap_host); + let compiler = builder.compiler(0, bootstrap_host, false); let mut path = self.path.to_str().unwrap(); // Map alias `tidyselftest` back to the actual crate path of tidy. @@ -126,7 +126,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" // Test the linkchecker itself. let bootstrap_host = builder.config.build; - let compiler = builder.compiler(0, bootstrap_host); + let compiler = builder.compiler(0, bootstrap_host, false); let cargo = tool::prepare_tool_cargo( builder, @@ -250,8 +250,7 @@ impl Step for Cargotest { /// This tool in `src/tools` will check out a few Rust projects and run `cargo /// test` to ensure that we don't regress the test suites there. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(self.stage, self.host); - builder.ensure(compile::Rustc::new(compiler, compiler.host)); + let compiler = builder.compiler(self.stage, self.host, false); let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host }); // Note that this is a short, cryptic, and not scoped directory name. This @@ -297,7 +296,7 @@ impl Step for Cargo { /// Runs `cargo test` for `cargo` packaged with Rust. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(self.stage, self.host); + let compiler = builder.compiler(self.stage, self.host, true); builder.ensure(tool::Cargo { compiler, target: self.host }); let cargo = tool::prepare_tool_cargo( @@ -365,11 +364,7 @@ impl Step for RustAnalyzer { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let host = self.host; - let compiler = builder.compiler(stage, host); - - // We don't need to build the whole Rust Analyzer for the proc-macro-srv test suite, - // but we do need the standard library to be present. - builder.ensure(compile::Rustc::new(compiler, host)); + let compiler = builder.compiler(stage, host, true); let workspace_path = "src/tools/rust-analyzer"; // until the whole RA test suite runs on `i686`, we only run @@ -424,7 +419,7 @@ impl Step for Rustfmt { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let host = self.host; - let compiler = builder.compiler(stage, host); + let compiler = builder.compiler(stage, host, true); builder.ensure(tool::Rustfmt { compiler, target: self.host }); @@ -520,17 +515,17 @@ impl Step for Miri { } // This compiler runs on the host, we'll just use it for the target. - let target_compiler = builder.compiler(stage, host); + let target_compiler = builder.compiler(stage, host, false); // 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 // compilers, which isn't what we want. Rustdoc should be linked in the same way as the // rustc compiler it's paired with, so it must be built with the previous stage compiler. - let host_compiler = builder.compiler(stage - 1, host); + let host_compiler = builder.compiler(stage, host, true); // Build our tools. - let miri = builder.ensure(tool::Miri { compiler: host_compiler, target: host }); + let miri = builder.ensure(tool::Miri { compiler: target_compiler, target: host }); // the ui tests also assume cargo-miri has been built - builder.ensure(tool::CargoMiri { compiler: host_compiler, target: host }); + builder.ensure(tool::CargoMiri { compiler: target_compiler, target: host }); // We also need sysroots, for Miri and for the host (the latter for build scripts). // This is for the tests so everything is done with the target compiler. @@ -636,7 +631,7 @@ impl Step for CargoMiri { } // This compiler runs on the host, we'll just use it for the target. - let compiler = builder.compiler(stage, host); + let compiler = builder.compiler(stage, host, false); // Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures @@ -695,7 +690,7 @@ impl Step for CompiletestTest { /// Runs `cargo test` for compiletest. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(builder.top_stage, host); + let compiler = builder.compiler(builder.top_stage, host, false); // We need `ToolStd` for the locally-built sysroot because // compiletest uses unstable features of the `test` crate. @@ -740,7 +735,7 @@ impl Step for Clippy { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let host = self.host; - let compiler = builder.compiler(stage, host); + let compiler = builder.compiler(stage, host, true); builder.ensure(tool::Clippy { compiler, target: self.host }); let mut cargo = tool::prepare_tool_cargo( @@ -800,7 +795,7 @@ impl Step for RustdocTheme { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.target); + let compiler = run.builder.compiler(run.builder.top_stage, run.target, false); run.builder.ensure(RustdocTheme { compiler }); } @@ -898,7 +893,7 @@ impl Step for RustdocJSNotStd { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); run.builder.ensure(RustdocJSNotStd { target: run.target, compiler }); } @@ -963,7 +958,7 @@ impl Step for RustdocGUI { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); run.builder.ensure(RustdocGUI { target: run.target, compiler }); } @@ -1175,7 +1170,7 @@ macro_rules! test { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); run.builder.ensure($name { compiler, target: run.target }); } @@ -1214,7 +1209,7 @@ impl Step for RunMakeSupport { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() }); } @@ -1266,7 +1261,7 @@ impl Step for CrateRunMakeSupport { /// Runs `cargo test` for run-make-support. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(0, host); + let compiler = builder.compiler(0, host, false); let mut cargo = tool::prepare_tool_cargo( builder, @@ -1311,7 +1306,7 @@ impl Step for CrateBuildHelper { /// Runs `cargo test` for build_helper. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(0, host); + let compiler = builder.compiler(0, host, false); let mut cargo = tool::prepare_tool_cargo( builder, @@ -1413,7 +1408,7 @@ impl Step for RunMake { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() }); run.builder.ensure(RunMake { compiler, target: run.target }); } @@ -1467,7 +1462,7 @@ impl Step for Coverage { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); let target = run.target; // List of (coverage) test modes that the coverage test suite will be @@ -1550,7 +1545,7 @@ impl Step for MirOpt { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple(), false); run.builder.ensure(MirOpt { compiler, target: run.target }); } @@ -1654,14 +1649,14 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // to `build.build` in the configuration. let build = builder.build.build; - compiler = builder.compiler(compiler.stage - 1, build); + compiler = builder.compiler(compiler.stage - 1, build, false); format!("stage{}-{}", compiler.stage + 1, build) } else { format!("stage{}-{}", compiler.stage, target) }; if suite.ends_with("fulldeps") { - builder.ensure(compile::Rustc::new(compiler, target)); + let _ = builder.compiler(compiler.stage + 1, target, false); } if suite == "debuginfo" { @@ -1715,17 +1710,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // If we're using `--stage 0`, we should provide the bootstrap cargo. builder.initial_cargo.clone() } else { - // We need to properly build cargo using the suitable stage compiler. - - let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(|| - // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if - // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built - // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off - // the compiler stage by 1 to align with expected `./x test run-make --stage N` - // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri - // which does a similar hack. - builder.compiler(builder.top_stage - 1, compiler.host)); - builder.ensure(tool::Cargo { compiler, target: compiler.host }) }; @@ -2215,7 +2199,7 @@ impl BookTest { /// This runs the equivalent of `mdbook test` (via the rustbook wrapper) /// which in turn runs `rustdoc --test` on each file in the book. fn run_ext_doc(self, builder: &Builder<'_>) { - let compiler = self.compiler; + let mut compiler = self.compiler; builder.ensure(compile::Std::new(compiler, compiler.host)); @@ -2233,6 +2217,11 @@ impl BookTest { rustbook_cmd.env("RUSTC_BOOTSTRAP", "1"); rustbook_cmd.env("PATH", new_path).arg("test").arg(path); + // FIXME: remove stage check + if compiler.stage > 0 { + compiler.downgrade(); + } + // Books may also need to build dependencies. For example, `TheBook` has // code samples which use the `trpl` crate. For the `rustdoc` invocation // to find them them successfully, they need to be built first and their @@ -2359,7 +2348,7 @@ macro_rules! test_book { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.target), + compiler: run.builder.compiler(run.builder.top_stage, run.target, false), }); } @@ -2423,7 +2412,7 @@ impl Step for ErrorIndex { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest // tests in tests/rustdoc) so that it shares the same artifacts. - let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build); + let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build, false); run.builder.ensure(ErrorIndex { compiler }); } @@ -2506,7 +2495,7 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = builder.compiler_for(builder.top_stage, host, host); + let compiler = builder.compiler_for(builder.top_stage, host, host, false); let crates = run.make_run_crates(Alias::Compiler); builder.ensure(CrateLibrustc { compiler, target: run.target, crates }); @@ -2665,7 +2654,7 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = builder.compiler_for(builder.top_stage, host, host); + let compiler = builder.compiler_for(builder.top_stage, host, host, false); let crates = run .paths .iter() @@ -2696,7 +2685,12 @@ impl Step for Crate { // version of libstd, then what we're actually testing is the libstd // produced in stage1. Reflect that here by updating the compiler that // we're working with automatically. - let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler = builder.compiler_for( + compiler.stage, + compiler.host, + target, + self.mode == Mode::ToolRustc, + ); let mut cargo = if builder.kind == Kind::Miri { if builder.top_stage == 0 { @@ -2810,20 +2804,20 @@ impl Step for CrateRustdoc { let target = self.host; let compiler = if builder.download_rustc() { - builder.compiler(builder.top_stage, target) + builder.compiler(builder.top_stage, target, false) } else { // Use the previous stage compiler to reuse the artifacts that are // created when running compiletest for tests/rustdoc. If this used // `compiler`, then it would cause rustdoc to be built *again*, which // isn't really necessary. - builder.compiler_for(builder.top_stage, target, target) + builder.compiler_for(builder.top_stage, target, target, false) }; // NOTE: normally `ensure(Rustc)` automatically runs `ensure(Std)` for us. However, when // using `download-rustc`, the rustc_private artifacts may be in a *different sysroot* from // the target rustdoc (`ci-rustc-sysroot` vs `stage2`). In that case, we need to ensure this // explicitly to make sure it ends up in the stage2 sysroot. builder.ensure(compile::Std::new(compiler, target)); - builder.ensure(compile::Rustc::new(compiler, target)); + let _ = builder.compiler(compiler.stage, target, false); let mut cargo = tool::prepare_tool_cargo( builder, @@ -2913,8 +2907,8 @@ impl Step for CrateRustdocJsonTypes { // created when running compiletest for tests/rustdoc. If this used // `compiler`, then it would cause rustdoc to be built *again*, which // isn't really necessary. - let compiler = builder.compiler_for(builder.top_stage, target, target); - builder.ensure(compile::Rustc::new(compiler, target)); + let compiler = builder.compiler_for(builder.top_stage, target, target, false); + let _ = builder.compiler(compiler.stage, target, false); let cargo = tool::prepare_tool_cargo( builder, @@ -3078,7 +3072,7 @@ impl Step for Bootstrap { /// Tests the build system itself. fn run(self, builder: &Builder<'_>) { let host = builder.config.build; - let compiler = builder.compiler(0, host); + let compiler = builder.compiler(0, host, false); let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host); // Some tests require cargo submodule to be present. @@ -3143,8 +3137,12 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = - run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target); + let compiler = run.builder.compiler_for( + run.builder.top_stage, + run.builder.build.build, + run.target, + false, + ); run.builder.ensure(TierCheck { compiler }); } @@ -3195,7 +3193,7 @@ impl Step for LintDocs { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LintDocs { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } @@ -3222,7 +3220,7 @@ impl Step for RustInstaller { /// Ensure the version placeholder replacement tool builds fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; - let compiler = builder.compiler(0, bootstrap_host); + let compiler = builder.compiler(0, bootstrap_host, false); let cargo = tool::prepare_tool_cargo( builder, compiler, @@ -3350,7 +3348,7 @@ impl Step for CodegenCranelift { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + let compiler = run.builder.compiler_for(run.builder.top_stage, host, host, false); if builder.doc_tests == DocTests::Only { return; @@ -3389,7 +3387,7 @@ impl Step for CodegenCranelift { // version of libstd, then what we're actually testing is the libstd // produced in stage1. Reflect that here by updating the compiler that // we're working with automatically. - let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler = builder.compiler_for(compiler.stage, compiler.host, target, false); let build_cargo = || { let mut cargo = builder::Cargo::new( @@ -3474,7 +3472,7 @@ impl Step for CodegenGCC { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let host = run.build_triple(); - let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + let compiler = run.builder.compiler_for(run.builder.top_stage, host, host, false); if builder.doc_tests == DocTests::Only { return; @@ -3519,7 +3517,7 @@ impl Step for CodegenGCC { // version of libstd, then what we're actually testing is the libstd // produced in stage1. Reflect that here by updating the compiler that // we're working with automatically. - let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler = builder.compiler_for(compiler.stage, compiler.host, target, false); let build_cargo = || { let mut cargo = builder::Cargo::new( @@ -3610,7 +3608,7 @@ impl Step for TestFloatParse { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; - let compiler = builder.compiler(builder.top_stage, bootstrap_host); + let compiler = builder.compiler(builder.top_stage, bootstrap_host, false); let path = self.path.to_str().unwrap(); let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index a0abd439de020..00e1b34729b96 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,12 +1,22 @@ +//! This module handles building and managing various tools in bootstrap +//! build system. +//! +//! **What It Does** +//! - Defines how tools are built, configured and installed. +//! - Manages tool dependencies and build steps. +//! - Copies built tool binaries to the correct locations. +//! +//! Each tool **MUST** utilize `ToolBuild` inside their `Step` logic and +//! they should never prepare `cargo` invocations manually. + use std::path::PathBuf; use std::{env, fs}; +use self::builder::cargo_profile_var; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, llvm}; use crate::core::builder; -use crate::core::builder::{ - Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step, cargo_profile_var, -}; +use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection}; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, command}; @@ -55,7 +65,7 @@ impl Builder<'_> { *target, ), // doesn't depend on compiler, same as host compiler - _ => self.msg(Kind::Build, build_stage, format_args!("tool {tool}"), *host, *target), + _ => self.msg(kind, build_stage, format_args!("tool {tool}"), *host, *target), } } } @@ -71,36 +81,57 @@ impl Step for ToolBuild { /// /// This will build the specified tool with the specified `host` compiler in /// `stage` into the normal cargo output directory. - fn run(self, builder: &Builder<'_>) -> PathBuf { - let compiler = self.compiler; - let target = self.target; - let mut tool = self.tool; - let path = self.path; - + fn run(mut self, builder: &Builder<'_>) -> PathBuf { match self.mode { Mode::ToolRustc => { - builder.ensure(compile::Std::new(compiler, compiler.host)); - builder.ensure(compile::Rustc::new(compiler, target)); + // FIXME: remove stage check + if self.compiler.stage > 0 && !self.compiler.is_downgraded_already() { + builder.ensure(compile::Std::new(self.compiler, self.target)); + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/$tool_name be effectively different stage + // compilers, which isn't what we want. + // + // Compiler tools should be linked in the same way as the compiler it's paired with, + // so it must be built with the previous stage compiler. + self.compiler.downgrade(); + }; } - Mode::ToolStd => builder.ensure(compile::Std::new(compiler, target)), - Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs + Mode::ToolStd => builder.ensure(compile::Std::new(self.compiler, self.target)), + Mode::ToolBootstrap => {} _ => panic!("unexpected Mode for tool build"), } let mut cargo = prepare_tool_cargo( builder, - compiler, + self.compiler, self.mode, - target, + self.target, Kind::Build, - path, + self.path, self.source_type, &self.extra_features, ); + if !self.allow_features.is_empty() { cargo.allow_features(self.allow_features); } + + if self.path.ends_with("/rustdoc") { + // rustdoc is performance sensitive, so apply LTO to it. + let lto = match builder.config.rust_lto { + RustcLto::Off => Some("off"), + RustcLto::Thin => Some("thin"), + RustcLto::Fat => Some("fat"), + RustcLto::ThinLocal => None, + }; + + if let Some(lto) = lto { + cargo.env(cargo_profile_var("LTO", &builder.config), lto); + } + } + cargo.args(self.cargo_args); + let _guard = builder.msg_tool( Kind::Build, self.mode, @@ -114,7 +145,7 @@ impl Step for ToolBuild { let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {}); builder.save_toolstate( - tool, + self.tool, if build_success { ToolState::TestFail } else { ToolState::BuildFail }, ); @@ -124,10 +155,10 @@ impl Step for ToolBuild { // HACK(#82501): on Windows, the tools directory gets added to PATH when running tests, and // compiletest confuses HTML tidy with the in-tree tidy. Name the in-tree tidy something // different so the problem doesn't come up. - if tool == "tidy" { - tool = "rust-tidy"; + if self.tool == "tidy" { + self.tool = "rust-tidy"; } - copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) + copy_link_tool_bin(builder, self.compiler, self.target, self.mode, self.tool) } } } @@ -135,7 +166,7 @@ impl Step for ToolBuild { #[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this. pub fn prepare_tool_cargo( builder: &Builder<'_>, - compiler: Compiler, + mut compiler: Compiler, mode: Mode, target: TargetSelection, cmd_kind: Kind, @@ -143,6 +174,17 @@ pub fn prepare_tool_cargo( source_type: SourceType, extra_features: &[String], ) -> CargoCommand { + // FIXME: remove stage check + if builder.top_stage > 0 && mode == Mode::ToolRustc && !compiler.is_downgraded_already() { + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/$tool_name be effectively different stage + // compilers, which isn't what we want. + // + // Compiler tools should be linked in the same way as the compiler it's paired with, + // so it must be built with the previous stage compiler. + compiler.downgrade(); + } + let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, cmd_kind); let dir = builder.src.join(path); @@ -273,7 +315,7 @@ macro_rules! bootstrap_tool { match tool { $(Tool::$name => self.ensure($name { - compiler: self.compiler(0, self.config.build), + compiler: self.compiler(0, self.config.build, false), target: self.config.build, }), )+ @@ -298,7 +340,7 @@ macro_rules! bootstrap_tool { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { // snapshot compiler - compiler: run.builder.compiler(0, run.builder.config.build), + compiler: run.builder.compiler(0, run.builder.config.build, false), target: run.target, }); } @@ -386,7 +428,7 @@ impl Step for OptimizedDist { fn make_run(run: RunConfig<'_>) { run.builder.ensure(OptimizedDist { - compiler: run.builder.compiler(0, run.builder.config.build), + compiler: run.builder.compiler(0, run.builder.config.build, false), target: run.target, }); } @@ -428,7 +470,7 @@ impl Step for RustcPerf { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustcPerf { - compiler: run.builder.compiler(0, run.builder.config.build), + compiler: run.builder.compiler(0, run.builder.config.build, false), target: run.target, }); } @@ -469,7 +511,7 @@ impl ErrorIndex { // Error-index-generator links with the rustdoc library, so we need to add `rustc_lib_paths` // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc. let host = builder.config.build; - let compiler = builder.compiler_for(builder.top_stage, host, host); + let compiler = builder.compiler_for(builder.top_stage, host, host, true); let mut cmd = command(builder.ensure(ErrorIndex { compiler })); let mut dylib_paths = builder.rustc_lib_paths(compiler); dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, compiler.host))); @@ -486,16 +528,12 @@ impl Step for ErrorIndex { } fn make_run(run: RunConfig<'_>) { - // Compile the error-index in the same stage as rustdoc to avoid - // recompiling rustdoc twice if we can. - // // NOTE: This `make_run` isn't used in normal situations, only if you // manually build the tool with `x.py build // src/tools/error-index-generator` which almost nobody does. // Normally, `x.py test` or `x.py doc` will use the // `ErrorIndex::command` function instead. - let compiler = - run.builder.compiler(run.builder.top_stage.saturating_sub(1), run.builder.config.build); + let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build, true); run.builder.ensure(ErrorIndex { compiler }); } @@ -529,7 +567,7 @@ impl Step for RemoteTestServer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RemoteTestServer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, false), target: run.target, }); } @@ -571,25 +609,26 @@ impl Step for Rustdoc { // compiler here, because rustdoc *is* a compiler. We won't be using // this as the compiler to build with, but rather this is "what // compiler are we producing"? - compiler: run.builder.compiler(run.builder.top_stage, run.target), + compiler: run.builder.compiler(run.builder.top_stage, run.target, true), }); } fn run(self, builder: &Builder<'_>) -> PathBuf { - let target_compiler = self.compiler; - if target_compiler.stage == 0 { - if !target_compiler.is_snapshot(builder) { + let compiler = self.compiler; + let target = compiler.host; + + if compiler.stage == 0 && !compiler.is_downgraded_already() { + if !compiler.is_snapshot(builder) { panic!("rustdoc in stage 0 must be snapshot rustdoc"); } - return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host)); + return builder.initial_rustc.with_file_name(exe("rustdoc", compiler.host)); } - let target = target_compiler.host; let bin_rustdoc = || { - let sysroot = builder.sysroot(target_compiler); + let sysroot = builder.sysroot(compiler); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); - let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host)); + let bin_rustdoc = bindir.join(exe("rustdoc", target)); let _ = fs::remove_file(&bin_rustdoc); bin_rustdoc }; @@ -597,7 +636,7 @@ impl Step for Rustdoc { // If CI rustc is enabled and we haven't modified the rustdoc sources, // use the precompiled rustdoc from CI rustc's sysroot to speed up bootstrapping. if builder.download_rustc() - && target_compiler.stage > 0 + && compiler.stage > 0 && builder.rust_info().is_managed_git_subrepository() { let files_to_track = &["src/librustdoc", "src/tools/rustdoc"]; @@ -605,11 +644,8 @@ impl Step for Rustdoc { // Check if unchanged if builder.config.last_modified_commit(files_to_track, "download-rustc", true).is_some() { - let precompiled_rustdoc = builder - .config - .ci_rustc_dir() - .join("bin") - .join(exe("rustdoc", target_compiler.host)); + let precompiled_rustdoc = + builder.config.ci_rustc_dir().join("bin").join(exe("rustdoc", target)); let bin_rustdoc = bin_rustdoc(); builder.copy_link(&precompiled_rustdoc, &bin_rustdoc); @@ -617,23 +653,6 @@ impl Step for Rustdoc { } } - let build_compiler = if builder.download_rustc() && target_compiler.stage == 1 { - // We already have the stage 1 compiler, we don't need to cut the stage. - builder.compiler(target_compiler.stage, builder.config.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 - // compilers, which isn't what we want. Rustdoc should be linked in the same way as the - // rustc compiler it's paired with, so it must be built with the previous stage compiler. - builder.compiler(target_compiler.stage - 1, builder.config.build) - }; - - // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually - // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build - // it. - builder.ensure(compile::Std::new(build_compiler, target_compiler.host)); - builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host)); - // The presence of `target_compiler` ensures that the necessary libraries (codegen backends, // compiler libraries, ...) are built. Rustdoc does not require the presence of any // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since @@ -641,53 +660,28 @@ impl Step for Rustdoc { // libraries here. The intuition here is that If we've built a compiler, we should be able // to build rustdoc. // - let mut features = Vec::new(); + let mut extra_features = Vec::new(); if builder.config.jemalloc { - features.push("jemalloc".to_string()); + extra_features.push("jemalloc".to_string()); } - // NOTE: Never modify the rustflags here, it breaks the build cache for other tools! - let mut cargo = prepare_tool_cargo( - builder, - build_compiler, - Mode::ToolRustc, + let tool_rustdoc = builder.ensure(ToolBuild { + compiler, target, - Kind::Build, - "src/tools/rustdoc", - SourceType::InTree, - features.as_slice(), - ); - - // rustdoc is performance sensitive, so apply LTO to it. - let lto = match builder.config.rust_lto { - RustcLto::Off => Some("off"), - RustcLto::Thin => Some("thin"), - RustcLto::Fat => Some("fat"), - RustcLto::ThinLocal => None, - }; - if let Some(lto) = lto { - cargo.env(cargo_profile_var("LTO", &builder.config), lto); - } - - let _guard = builder.msg_tool( - Kind::Build, - Mode::ToolRustc, - "rustdoc", - build_compiler.stage, - &self.compiler.host, - &target, - ); - cargo.into_cmd().run(builder); - - // 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 = builder - .cargo_out(build_compiler, Mode::ToolRustc, target) - .join(exe("rustdoc_tool_binary", target_compiler.host)); + // 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. + tool: "rustdoc_tool_binary", + mode: Mode::ToolRustc, + path: "src/tools/rustdoc", + source_type: SourceType::InTree, + extra_features, + allow_features: "", + cargo_args: Vec::new(), + }); // don't create a stage0-sysroot/bin directory. - if target_compiler.stage > 0 { + if compiler.stage > 0 { if builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None { // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into // our final binaries @@ -720,7 +714,7 @@ impl Step for Cargo { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Cargo { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, true), target: run.target, }); } @@ -813,7 +807,7 @@ impl Step for RustAnalyzer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustAnalyzer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, true), target: run.target, }); } @@ -857,7 +851,7 @@ impl Step for RustAnalyzerProcMacroSrv { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustAnalyzerProcMacroSrv { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, true), target: run.target, }); } @@ -905,57 +899,36 @@ impl Step for LlvmBitcodeLinker { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmBitcodeLinker { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, true), extra_features: Vec::new(), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> PathBuf { - let bin_name = "llvm-bitcode-linker"; - - // If enabled, use ci-rustc and skip building the in-tree compiler. - if !builder.download_rustc() { - builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); - builder.ensure(compile::Rustc::new(self.compiler, self.target)); - } - - let cargo = prepare_tool_cargo( - builder, - self.compiler, - Mode::ToolRustc, - self.target, - Kind::Build, - "src/tools/llvm-bitcode-linker", - SourceType::InTree, - &self.extra_features, - ); - - let _guard = builder.msg_tool( - Kind::Build, - Mode::ToolRustc, - bin_name, - self.compiler.stage, - &self.compiler.host, - &self.target, - ); - - cargo.into_cmd().run(builder); - - let tool_out = builder - .cargo_out(self.compiler, Mode::ToolRustc, self.target) - .join(exe(bin_name, self.compiler.host)); + let bin_source = builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "llvm-bitcode-linker", + mode: Mode::ToolRustc, + path: "src/tools/llvm-bitcode-linker", + source_type: SourceType::InTree, + extra_features: self.extra_features, + allow_features: "", + cargo_args: Vec::new(), + }); if self.compiler.stage > 0 { let bindir_self_contained = builder .sysroot(self.compiler) .join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple)); t!(fs::create_dir_all(&bindir_self_contained)); - let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host)); - builder.copy_link(&tool_out, &bin_destination); + let bin_destination = + bindir_self_contained.join(exe("llvm-bitcode-linker", self.compiler.host)); + builder.copy_link(&bin_source, &bin_destination); bin_destination } else { - tool_out + bin_source } } } @@ -1055,7 +1028,7 @@ macro_rules! tool_extended { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build, true), target: run.target, }); } @@ -1107,7 +1080,7 @@ fn run_tool_build_step( path: &'static str, add_bins_to_sysroot: Option<&[&str]>, ) -> PathBuf { - let tool = builder.ensure(ToolBuild { + let bin_source = builder.ensure(ToolBuild { compiler, target, tool: tool_name, @@ -1126,10 +1099,7 @@ fn run_tool_build_step( let bindir = builder.sysroot(compiler).join("bin"); t!(fs::create_dir_all(&bindir)); - let tools_out = builder.cargo_out(compiler, Mode::ToolRustc, target); - for add_bin in add_bins_to_sysroot { - let bin_source = tools_out.join(exe(add_bin, target)); let bin_destination = bindir.join(exe(add_bin, compiler.host)); builder.copy_link(&bin_source, &bin_destination); } @@ -1137,7 +1107,7 @@ fn run_tool_build_step( // Return a path into the bin dir. bindir.join(exe(tool_name, compiler.host)) } else { - tool + bin_source } } @@ -1185,7 +1155,7 @@ impl Step for TestFloatParse { fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; - let compiler = builder.compiler(builder.top_stage, bootstrap_host); + let compiler = builder.compiler(builder.top_stage, bootstrap_host, false); builder.ensure(ToolBuild { compiler, @@ -1206,7 +1176,7 @@ impl Builder<'_> { /// `host`. pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand { let mut cmd = command(self.tool_exe(tool)); - let compiler = self.compiler(0, self.config.build); + let compiler = self.compiler(0, self.config.build, false); let host = &compiler.host; // Prepares the `cmd` provided to be able to run the `compiler` provided. // diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 04a00fde3ab45..30ae65d106b31 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1209,8 +1209,28 @@ impl<'a> Builder<'a> { /// compiler will run on, *not* the target it will build code for). Explicitly does not take /// `Compiler` since all `Compiler` instances are meant to be obtained through this function, /// since it ensures that they are valid (i.e., built and assembled). - pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler { - self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } }) + pub fn compiler( + &self, + stage: u32, + host: TargetSelection, + downgrade_for_rustc_tool: bool, + ) -> Compiler { + let mut compiler = + self.ensure(compile::Assemble { target_compiler: Compiler::new(stage, host) }); + + // FIXME: remove stage check + if stage > 0 && downgrade_for_rustc_tool { + self.ensure(compile::Std::new(compiler, host)); + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/$tool_name be effectively different stage + // compilers, which isn't what we want. + // + // Compiler tools should be linked in the same way as the compiler it's paired with, + // so it must be built with the previous stage compiler. + compiler.downgrade(); + }; + + compiler } /// Similar to `compiler`, except handles the full-bootstrap option to @@ -1229,13 +1249,14 @@ impl<'a> Builder<'a> { stage: u32, host: TargetSelection, target: TargetSelection, + for_rustc_tool: bool, ) -> Compiler { if self.build.force_use_stage2(stage) { - self.compiler(2, self.config.build) + self.compiler(2, self.config.build, for_rustc_tool) } else if self.build.force_use_stage1(stage, target) { - self.compiler(1, self.config.build) + self.compiler(1, self.config.build, for_rustc_tool) } else { - self.compiler(stage, host) + self.compiler(stage, host, for_rustc_tool) } } @@ -1347,12 +1368,21 @@ impl<'a> Builder<'a> { .map(|entry| entry.path()) } - pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { + pub fn rustdoc(&self, mut compiler: Compiler) -> PathBuf { + if compiler.is_snapshot(self) && !compiler.is_downgraded_already() { + return self.initial_rustc.with_file_name(exe("rustdoc", compiler.host)); + } + + if !compiler.is_downgraded_already() { + assert!(compiler.stage > 0, "Can't use stage0 compiler for rustdoc"); + compiler.downgrade(); + } + self.ensure(tool::Rustdoc { compiler }) } - pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { - if run_compiler.stage == 0 { + pub fn cargo_clippy_cmd(&self, compiler: Compiler) -> BootstrapCommand { + if compiler.stage == 0 { let cargo_clippy = self .config .initial_cargo_clippy @@ -1364,12 +1394,10 @@ impl<'a> Builder<'a> { return cmd; } - let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build); - self.ensure(tool::Clippy { compiler: build_compiler, target: self.build.build }); - let cargo_clippy = - self.ensure(tool::CargoClippy { compiler: build_compiler, target: self.build.build }); + self.ensure(tool::Clippy { compiler, target: self.build.build }); + let cargo_clippy = self.ensure(tool::CargoClippy { compiler, target: self.build.build }); let mut dylib_path = helpers::dylib_path(); - dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); + dylib_path.insert(0, self.sysroot(compiler).join("lib")); let mut cmd = command(cargo_clippy); cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); @@ -1377,14 +1405,12 @@ impl<'a> Builder<'a> { cmd } - pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { - assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); - let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build); + pub fn cargo_miri_cmd(&self, compiler: Compiler) -> BootstrapCommand { + assert!(compiler.stage > 0, "miri can not be invoked at stage 0"); // Prepare the tools - let miri = self.ensure(tool::Miri { compiler: build_compiler, target: self.build.build }); - let cargo_miri = - self.ensure(tool::CargoMiri { compiler: build_compiler, target: self.build.build }); + let miri = self.ensure(tool::Miri { compiler, target: self.build.build }); + let cargo_miri = self.ensure(tool::CargoMiri { compiler, target: self.build.build }); // Invoke cargo-miri, make sure it can find miri and cargo. let mut cmd = command(cargo_miri); cmd.env("MIRI", &miri); @@ -1397,7 +1423,7 @@ impl<'a> Builder<'a> { // `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries added to // the PATH due to the stage mismatch. // Also see https://github.com/rust-lang/rust/pull/123192#issuecomment-2028901503. - add_dylib_path(self.rustc_lib_paths(run_compiler), &mut cmd); + add_dylib_path(self.rustc_lib_paths(compiler), &mut cmd); cmd } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 0c27597083def..79214c7cb0c96 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -69,7 +69,7 @@ fn check_cli(paths: [&str; N]) { macro_rules! std { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Std::new( - Compiler { host: TargetSelection::from_user($host), stage: $stage }, + Compiler::new($stage, TargetSelection::from_user($host)), TargetSelection::from_user($target), ) }; @@ -82,7 +82,7 @@ macro_rules! doc_std { macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( - Compiler { host: TargetSelection::from_user($host), stage: $stage }, + Compiler::new($stage, TargetSelection::from_user($host)), TargetSelection::from_user($target), ) }; @@ -281,7 +281,7 @@ mod defaults { first(cache.all::()), // Recall that rustdoc stages are off-by-one // - this is the compiler it's _linked_ to, not built with. - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }], + &[tool::Rustdoc { compiler: Compiler::new(0, a).downgraded_from(1) }], ); assert_eq!(first(cache.all::()), &[ rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0) @@ -302,7 +302,7 @@ mod defaults { first(cache.all::()), // This is the beta rustdoc. // Add an assert here to make sure this is the only rustdoc built. - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }], + &[tool::Rustdoc { compiler: Compiler::new(0, a) }], ); assert!(cache.all::().is_empty()); } @@ -328,15 +328,16 @@ mod defaults { std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), + std!(TEST_TRIPLE_2 => TEST_TRIPLE_2, stage = 1), ]); assert_eq!(first(cache.all::()), &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + compile::Assemble { target_compiler: Compiler::new(0, a) }, + compile::Assemble { target_compiler: Compiler::new(1, a) }, + compile::Assemble { target_compiler: Compiler::new(1, b) }, ]); assert_eq!(first(cache.all::()), &[ - tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, - tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + tool::Rustdoc { compiler: Compiler::new(0, a).downgraded_from(1) }, + tool::Rustdoc { compiler: Compiler::new(0, b).downgraded_from(1) }, ],); assert_eq!(first(cache.all::()), &[ rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), @@ -356,13 +357,25 @@ mod defaults { // rustdoc tool. assert_eq!(first(cache.all::()), &[doc::ErrorIndex { target: a },]); assert_eq!(first(cache.all::()), &[tool::ErrorIndex { - compiler: Compiler { host: a, stage: 0 } + compiler: Compiler::new(0, a) }]); + assert!(first(cache.all::()).is_empty()); + } + + #[test] + fn doc_stage_1() { + let mut config = configure("doc", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); + config.compiler_docs = true; + config.stage = 1; + config.cmd = Subcommand::Doc { open: false, json: false }; + let mut cache = run_build(&[], config); + let a = TargetSelection::from_user(TEST_TRIPLE_1); + // docs should be built with the beta compiler, not with the stage0 artifacts. // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to, // not the one it was built by. assert_eq!(first(cache.all::()), &[tool::Rustdoc { - compiler: Compiler { host: a, stage: 0 } + compiler: Compiler::new(0, a).downgraded_from(1) },]); } } @@ -386,16 +399,16 @@ mod dist { assert_eq!(first(cache.all::()), &[dist::Docs { host: a },]); assert_eq!(first(cache.all::()), &[dist::Mingw { host: a },]); assert_eq!(first(cache.all::()), &[dist::Rustc { - compiler: Compiler { host: a, stage: 2 } + compiler: Compiler::new(2, a) },]); assert_eq!(first(cache.all::()), &[dist::Std { - compiler: Compiler { host: a, stage: 1 }, + compiler: Compiler::new(1, a), target: a },]); assert_eq!(first(cache.all::()), &[dist::Src]); // Make sure rustdoc is only built once. assert_eq!(first(cache.all::()), &[tool::Rustdoc { - compiler: Compiler { host: a, stage: 2 } + compiler: Compiler::new(1, a).downgraded_from(2) },]); } @@ -414,11 +427,11 @@ mod dist { host: b },]); assert_eq!(first(cache.all::()), &[dist::Rustc { - compiler: Compiler { host: a, stage: 2 } + compiler: Compiler::new(2, a) },]); assert_eq!(first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(2, a), target: b }, ]); assert_eq!(first(cache.all::()), &[dist::Src]); } @@ -440,17 +453,18 @@ mod dist { host: b },]); assert_eq!(first(cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + dist::Rustc { compiler: Compiler::new(2, a) }, + dist::Rustc { compiler: Compiler::new(2, b) }, ]); assert_eq!(first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(1, a), target: b }, ]); assert_eq!(first(cache.all::()), &[ std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 2), + std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 2), ],); @@ -468,10 +482,11 @@ mod dist { let mut cache = run_build(&[], config); assert_eq!(first(cache.all::()), &[dist::Rustc { - compiler: Compiler { host: b, stage: 2 } + compiler: Compiler::new(2, b) },]); assert_eq!(first(cache.all::()), &[ rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0), rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), ]); } @@ -502,13 +517,13 @@ mod dist { dist::Mingw { host: c }, ]); assert_eq!(first(cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + dist::Rustc { compiler: Compiler::new(2, a) }, + dist::Rustc { compiler: Compiler::new(2, b) }, ]); assert_eq!(first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(1, a), target: b }, + dist::Std { compiler: Compiler::new(2, a), target: c }, ]); assert_eq!(first(cache.all::()), &[dist::Src]); } @@ -524,7 +539,7 @@ mod dist { assert_eq!(first(cache.all::()), &[dist::Docs { host: c },]); assert_eq!(first(cache.all::()), &[dist::Mingw { host: c },]); assert_eq!(first(cache.all::()), &[dist::Std { - compiler: Compiler { host: a, stage: 2 }, + compiler: Compiler::new(2, a), target: c },]); } @@ -546,26 +561,28 @@ mod dist { host: b },]); assert_eq!(first(cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + dist::Rustc { compiler: Compiler::new(2, a) }, + dist::Rustc { compiler: Compiler::new(2, b) }, ]); assert_eq!(first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(1, a), target: b }, ]); assert_eq!(first(cache.all::()), &[dist::Src]); assert_eq!(first(cache.all::()), &[ std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 2), + std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 2), ]); assert_eq!(first(cache.all::()), &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, + compile::Assemble { target_compiler: Compiler::new(0, a) }, + compile::Assemble { target_compiler: Compiler::new(1, a) }, + compile::Assemble { target_compiler: Compiler::new(1, b) }, + compile::Assemble { target_compiler: Compiler::new(2, a) }, + compile::Assemble { target_compiler: Compiler::new(2, b) }, ]); } @@ -586,16 +603,17 @@ mod dist { std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 2), + std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), std!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 2), std!(TEST_TRIPLE_1 => TEST_TRIPLE_3, stage = 2), ]); - assert_eq!(builder.cache.all::().len(), 5); + assert_eq!(builder.cache.all::().len(), 6); assert_eq!(first(builder.cache.all::()), &[ rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 2), - rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0), rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 2), ]); } @@ -632,9 +650,9 @@ mod dist { std!(TEST_TRIPLE_1 => TEST_TRIPLE_3, stage = 2), ]); assert_eq!(first(builder.cache.all::()), &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, + compile::Assemble { target_compiler: Compiler::new(0, a) }, + compile::Assemble { target_compiler: Compiler::new(1, a) }, + compile::Assemble { target_compiler: Compiler::new(2, a) }, ]); assert_eq!(first(builder.cache.all::()), &[ rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), @@ -676,7 +694,7 @@ mod dist { // Ensure we don't build any compiler artifacts. assert!(!builder.cache.contains::()); assert_eq!(first(builder.cache.all::()), &[test::Crate { - compiler: Compiler { host, stage: 0 }, + compiler: Compiler::new(0, host), target: host, mode: crate::Mode::Std, crates: vec!["std".to_owned()], @@ -700,12 +718,12 @@ mod dist { &[doc::ErrorIndex { target: a },] ); assert_eq!(first(builder.cache.all::()), &[tool::ErrorIndex { - compiler: Compiler { host: a, stage: 1 } + compiler: Compiler::new(0, a).downgraded_from(1) }]); // This is actually stage 1, but Rustdoc::run swaps out the compiler with // stage minus 1 if --stage is not 0. Very confusing! assert_eq!(first(builder.cache.all::()), &[tool::Rustdoc { - compiler: Compiler { host: a, stage: 2 } + compiler: Compiler::new(1, a).downgraded_from(2) },]); } @@ -744,7 +762,7 @@ mod dist { &[doc::ErrorIndex { target: a },] ); assert_eq!(first(builder.cache.all::()), &[tool::ErrorIndex { - compiler: Compiler { host: a, stage: 1 } + compiler: Compiler::new(0, a).downgraded_from(1) }]); // Unfortunately rustdoc is built twice. Once from stage1 for compiletest // (and other things), and once from stage0 for std crates. Ideally it @@ -758,9 +776,8 @@ mod dist { // (currently) needed to run "cargo test" on the linkchecker, and // should be relatively "free". assert_eq!(first(builder.cache.all::()), &[ - tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }, - tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, - tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } }, + tool::Rustdoc { compiler: Compiler::new(0, a).downgraded_from(1) }, + tool::Rustdoc { compiler: Compiler::new(1, a).downgraded_from(2) }, ]); } } @@ -775,7 +792,7 @@ mod sysroot_target_dirs { let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); let builder = Builder::new(&build); let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); - let compiler = Compiler { stage: 1, host: target_triple_1 }; + let compiler = Compiler::new(1, target_triple_1); let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); let actual = builder.sysroot_target_libdir(compiler, target_triple_2); @@ -795,7 +812,7 @@ mod sysroot_target_dirs { let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); let builder = Builder::new(&build); let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); - let compiler = Compiler { stage: 1, host: target_triple_1 }; + let compiler = Compiler::new(1, target_triple_1); let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); let actual = builder.sysroot_target_bindir(compiler, target_triple_2); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d56f35f866cb8..fc566faae16d8 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -90,12 +90,30 @@ const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ /// Each compiler has a `stage` that it is associated with and a `host` that /// corresponds to the platform the compiler runs on. This structure is used as /// a parameter to many methods below. -#[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)] +#[derive(PartialOrd, Ord, Clone, Copy, Debug)] pub struct Compiler { stage: u32, host: TargetSelection, + downgraded_from: Option, } +impl std::hash::Hash for Compiler { + fn hash(&self, state: &mut H) { + self.stage.hash(state); + self.host.hash(state); + } +} + +impl PartialEq for Compiler { + fn eq(&self, other: &Self) -> bool { + self.stage == other.stage && self.host == other.host + // We have coverage for `downgraded_from` in our unit tests + && (!cfg!(test) || self.downgraded_from == other.downgraded_from) + } +} + +impl Eq for Compiler {} + #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum DocTests { /// Run normal tests and doc tests (default). @@ -1925,6 +1943,16 @@ fn chmod(path: &Path, perms: u32) { fn chmod(_path: &Path, _perms: u32) {} impl Compiler { + pub fn new(stage: u32, host: TargetSelection) -> Compiler { + Compiler { stage, host, downgraded_from: None } + } + + #[cfg(test)] + pub fn downgraded_from(mut self, stage: u32) -> Compiler { + self.downgraded_from = Some(stage); + self + } + pub fn with_stage(mut self, stage: u32) -> Compiler { self.stage = stage; self @@ -1934,6 +1962,18 @@ impl Compiler { pub fn is_snapshot(&self, build: &Build) -> bool { self.stage == 0 && self.host == build.build } + + /// Check whether or not if compiler was already downgraded before. + pub fn is_downgraded_already(&self) -> bool { + self.downgraded_from.is_some() + } + + /// Downgrade stage of the compiler used for rustc tools. + pub fn downgrade(&mut self) { + assert!(self.stage > 0, "Can't downgrade stage 0 compiler"); + self.downgraded_from = Some(self.stage); + self.stage -= 1; + } } fn envify(s: &str) -> String {