diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 57c2706f60a56..64097320caba7 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -8,8 +8,6 @@ incremental = true download-rustc = "if-unchanged" [build] -# cargo and clippy tests don't pass on stage 1 -test-stage = 2 # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile. doc-stage = 2 # Contributors working on tools will probably expect compiler docs to be generated, so they can figure out how to use the API. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 9d3d07c83d25a..8e9b5856096ae 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1983,14 +1983,13 @@ impl Step for Assemble { let maybe_install_llvm_bitcode_linker = |compiler| { if builder.config.llvm_bitcode_linker_enabled { trace!("llvm-bitcode-linker enabled, installing"); - let llvm_bitcode_linker = - builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { - compiler, - target: target_compiler.host, - extra_features: vec![], - }); + let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { + compiler, + target: target_compiler.host, + extra_features: vec![], + }); let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); - builder.copy_link(&llvm_bitcode_linker.tool_path, &libdir_bin.join(tool_exe)); + builder.copy_link(&src_path, &libdir_bin.join(tool_exe)); } }; @@ -2182,13 +2181,14 @@ impl Step for Assemble { // logic to create the final binary. This is used by the // `wasm32-wasip2` target of Rust. if builder.tool_enabled("wasm-component-ld") { - let wasm_component = builder.ensure(crate::core::build_steps::tool::WasmComponentLd { - compiler: build_compiler, - target: target_compiler.host, - }); + let wasm_component_ld_exe = + builder.ensure(crate::core::build_steps::tool::WasmComponentLd { + compiler: build_compiler, + target: target_compiler.host, + }); builder.copy_link( - &wasm_component.tool_path, - &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), + &wasm_component_ld_exe, + &libdir_bin.join(wasm_component_ld_exe.file_name().unwrap()), ); } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index dc96b7d0e0d98..795f9506a259b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -430,7 +430,7 @@ impl Step for Rustc { }, builder.kind, ) { - builder.install(&ra_proc_macro_srv.tool_path, &image.join("libexec"), 0o755); + builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755); } let libdir_relative = builder.libdir_relative(compiler); @@ -1145,7 +1145,7 @@ impl Step for Cargo { let mut tarball = Tarball::new(builder, "cargo", &target.triple); tarball.set_overlay(OverlayKind::Cargo); - tarball.add_file(cargo.tool_path, "bin", 0o755); + tarball.add_file(cargo, "bin", 0o755); tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); tarball.add_dir(etc.join("man"), "share/man/man1"); @@ -1191,7 +1191,7 @@ impl Step for Rls { let mut tarball = Tarball::new(builder, "rls", &target.triple); tarball.set_overlay(OverlayKind::Rls); tarball.is_preview(true); - tarball.add_file(rls.tool_path, "bin", 0o755); + tarball.add_file(rls, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/rls"); Some(tarball.generate()) } @@ -1233,7 +1233,7 @@ impl Step for RustAnalyzer { let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); tarball.set_overlay(OverlayKind::RustAnalyzer); tarball.is_preview(true); - tarball.add_file(rust_analyzer.tool_path, "bin", 0o755); + tarball.add_file(rust_analyzer, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/rust-analyzer"); Some(tarball.generate()) } @@ -1279,8 +1279,8 @@ impl Step for Clippy { let mut tarball = Tarball::new(builder, "clippy", &target.triple); tarball.set_overlay(OverlayKind::Clippy); tarball.is_preview(true); - tarball.add_file(clippy.tool_path, "bin", 0o755); - tarball.add_file(cargoclippy.tool_path, "bin", 0o755); + tarball.add_file(clippy, "bin", 0o755); + tarball.add_file(cargoclippy, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/clippy"); Some(tarball.generate()) } @@ -1329,8 +1329,8 @@ impl Step for Miri { let mut tarball = Tarball::new(builder, "miri", &target.triple); tarball.set_overlay(OverlayKind::Miri); tarball.is_preview(true); - tarball.add_file(miri.tool_path, "bin", 0o755); - tarball.add_file(cargomiri.tool_path, "bin", 0o755); + tarball.add_file(miri, "bin", 0o755); + tarball.add_file(cargomiri, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/miri"); Some(tarball.generate()) } @@ -1460,8 +1460,8 @@ impl Step for Rustfmt { let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); tarball.set_overlay(OverlayKind::Rustfmt); tarball.is_preview(true); - tarball.add_file(rustfmt.tool_path, "bin", 0o755); - tarball.add_file(cargofmt.tool_path, "bin", 0o755); + tarball.add_file(rustfmt, "bin", 0o755); + tarball.add_file(cargofmt, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/rustfmt"); Some(tarball.generate()) } @@ -2283,7 +2283,7 @@ impl Step for LlvmBitcodeLinker { tarball.set_overlay(OverlayKind::LlvmBitcodeLinker); tarball.is_preview(true); - tarball.add_file(llbc_linker.tool_path, self_contained_bin_dir, 0o755); + tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755); Some(tarball.generate()) } diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 6962001fdc240..98c63a41e768b 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -166,7 +166,7 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); let results_dir = rustc_perf_dir.join("results"); builder.create_dir(&results_dir); - let mut cmd = command(collector.tool_path); + let mut cmd = command(collector); // We need to set the working directory to `src/tools/rustc-perf`, so that it can find the directory // with compile-time benchmarks. diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index fea8232296eca..2b17e02cae5a4 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -126,7 +126,11 @@ 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 host_compiler = tool::get_tool_rustc_compiler(builder, target_compiler); + // 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); // 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 604f9e73b4581..299decd0883ff 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -263,7 +263,7 @@ impl Step for Cargotest { let _time = helpers::timeit(builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); - cmd.arg(&cargo.tool_path) + cmd.arg(&cargo) .arg(&out_dir) .args(builder.config.test_args()) .env("RUSTC", builder.rustc(compiler)) @@ -298,16 +298,9 @@ impl Step for Cargo { /// Runs `cargo test` for `cargo` packaged with Rust. fn run(self, builder: &Builder<'_>) { - if self.stage < 2 { - eprintln!("WARNING: cargo tests on stage {} may not behave well.", self.stage); - eprintln!("HELP: consider using stage 2"); - } - let compiler = builder.compiler(self.stage, self.host); - let cargo = builder.ensure(tool::Cargo { compiler, target: self.host }); - let compiler = cargo.build_compiler; - + builder.ensure(tool::Cargo { compiler, target: self.host }); let cargo = tool::prepare_tool_cargo( builder, compiler, @@ -374,7 +367,6 @@ impl Step for RustAnalyzer { let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); - let compiler = tool::get_tool_rustc_compiler(builder, compiler); // 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. @@ -435,8 +427,7 @@ impl Step for Rustfmt { let host = self.host; let compiler = builder.compiler(stage, host); - let tool_result = builder.ensure(tool::Rustfmt { compiler, target: self.host }); - let compiler = tool_result.build_compiler; + builder.ensure(tool::Rustfmt { compiler, target: self.host }); let mut cargo = tool::prepare_tool_cargo( builder, @@ -531,11 +522,16 @@ 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); + // 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); // Build our tools. - let miri = builder.ensure(tool::Miri { compiler: target_compiler, target: host }); + let miri = builder.ensure(tool::Miri { compiler: host_compiler, target: host }); // the ui tests also assume cargo-miri has been built - builder.ensure(tool::CargoMiri { compiler: target_compiler, target: host }); + builder.ensure(tool::CargoMiri { compiler: host_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. @@ -546,8 +542,7 @@ impl Step for Miri { // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors. if !builder.config.dry_run() { - let ui_test_dep_dir = - builder.stage_out(miri.build_compiler, Mode::ToolStd).join("miri_ui"); + let ui_test_dep_dir = builder.stage_out(host_compiler, Mode::ToolStd).join("miri_ui"); // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see // ). // We can hence use that directly as a signal to clear the ui test dir. @@ -558,7 +553,7 @@ impl Step for Miri { // This is with the Miri crate, so it uses the host compiler. let mut cargo = tool::prepare_tool_cargo( builder, - miri.build_compiler, + host_compiler, Mode::ToolRustc, host, Kind::Test, @@ -576,7 +571,7 @@ impl Step for Miri { // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); cargo.env("MIRI_HOST_SYSROOT", &host_sysroot); - cargo.env("MIRI", &miri.tool_path); + cargo.env("MIRI", &miri); // Set the target. cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg()); @@ -748,13 +743,7 @@ impl Step for Clippy { let host = self.host; let compiler = builder.compiler(stage, host); - if stage < 2 { - eprintln!("WARNING: clippy tests on stage {stage} may not behave well."); - eprintln!("HELP: consider using stage 2"); - } - - let tool_result = builder.ensure(tool::Clippy { compiler, target: self.host }); - let compiler = tool_result.build_compiler; + builder.ensure(tool::Clippy { compiler, target: self.host }); let mut cargo = tool::prepare_tool_cargo( builder, compiler, @@ -1739,7 +1728,18 @@ 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 { - builder.ensure(tool::Cargo { compiler, target: compiler.host }).tool_path + // 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 }) }; cmd.arg("--cargo-path").arg(cargo_path); @@ -1760,10 +1760,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // Use the beta compiler for jsondocck let json_compiler = compiler.with_stage(0); cmd.arg("--jsondocck-path") - .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path); - cmd.arg("--jsondoclint-path").arg( - builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path, - ); + .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target })); + cmd.arg("--jsondoclint-path") + .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target })); } if matches!(mode, "coverage-map" | "coverage-run") { @@ -3000,15 +2999,12 @@ impl Step for RemoteCopyLibs { builder.info(&format!("REMOTE copy libs to emulator ({target})")); - let remote_test_server = builder.ensure(tool::RemoteTestServer { compiler, target }); + let server = builder.ensure(tool::RemoteTestServer { compiler, target }); // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); let mut cmd = command(&tool); - cmd.arg("spawn-emulator") - .arg(target.triple) - .arg(&remote_test_server.tool_path) - .arg(builder.tempdir()); + cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir()); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 39acb646dff4d..75bfff340862a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,14 +1,3 @@ -//! 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 Rust tool **MUST** utilize `ToolBuild` inside their `Step` logic, -//! return `ToolBuildResult` and should never prepare `cargo` invocations manually. - use std::path::PathBuf; use std::{env, fs}; @@ -75,21 +64,8 @@ impl Builder<'_> { } } -/// Result of the tool build process. Each `Step` in this module is responsible -/// for using this type as `type Output = ToolBuildResult;` -#[derive(Clone)] -pub struct ToolBuildResult { - /// Executable path of the corresponding tool that was built. - pub tool_path: PathBuf, - /// Compiler used to build the tool. For non-`ToolRustc` tools this is equal to `target_compiler`. - /// For `ToolRustc` this is one stage before of the `target_compiler`. - pub build_compiler: Compiler, - /// Target compiler passed to `Step`. - pub target_compiler: Compiler, -} - impl Step for ToolBuild { - type Output = ToolBuildResult; + type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() @@ -99,31 +75,25 @@ 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(mut self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { + let compiler = self.compiler; let target = self.target; let mut tool = self.tool; let path = self.path; - let target_compiler = self.compiler; - self.compiler = if self.mode == Mode::ToolRustc { - get_tool_rustc_compiler(builder, self.compiler) - } else { - self.compiler - }; - match self.mode { Mode::ToolRustc => { - builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); - builder.ensure(compile::Rustc::new(self.compiler, target)); + builder.ensure(compile::Std::new(compiler, compiler.host)); + builder.ensure(compile::Rustc::new(compiler, target)); } - Mode::ToolStd => builder.ensure(compile::Std::new(self.compiler, target)), + Mode::ToolStd => builder.ensure(compile::Std::new(compiler, target)), Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs _ => panic!("unexpected Mode for tool build"), } let mut cargo = prepare_tool_cargo( builder, - self.compiler, + compiler, self.mode, target, Kind::Build, @@ -131,28 +101,10 @@ impl Step for ToolBuild { self.source_type, &self.extra_features, ); - - if path.ends_with("/rustdoc") && - // rustdoc is performance sensitive, so apply LTO to it. - is_lto_stage(&self.compiler) - { - 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); - } - } - if !self.allow_features.is_empty() { cargo.allow_features(self.allow_features); } - cargo.args(self.cargo_args); - let _guard = builder.msg_tool( Kind::Build, self.mode, @@ -179,10 +131,7 @@ impl Step for ToolBuild { if tool == "tidy" { tool = "rust-tidy"; } - let tool_path = - copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool); - - ToolBuildResult { tool_path, build_compiler: self.compiler, target_compiler } + copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) } } } @@ -291,23 +240,6 @@ pub fn prepare_tool_cargo( cargo } -/// Handle stage-off logic for `ToolRustc` tools when necessary. -pub(crate) fn get_tool_rustc_compiler( - builder: &Builder<'_>, - target_compiler: Compiler, -) -> 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/$rustc_tool be effectively different stage - // compilers, which isn't what we want. Rustc 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. - builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build) - } -} - /// Links a built tool binary with the given `name` from the build directory to the /// tools directory. fn copy_link_tool_bin( @@ -347,7 +279,7 @@ macro_rules! bootstrap_tool { self.ensure($name { compiler: self.compiler(0, self.config.build), target: self.config.build, - }).tool_path, + }), )+ } } @@ -361,7 +293,7 @@ macro_rules! bootstrap_tool { } impl Step for $name { - type Output = ToolBuildResult; + type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path($path) @@ -383,7 +315,7 @@ macro_rules! bootstrap_tool { skip_all, ), )] - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { $( for submodule in $submodules { builder.require_submodule(submodule, None); @@ -458,7 +390,7 @@ pub struct OptimizedDist { } impl Step for OptimizedDist { - type Output = ToolBuildResult; + type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/opt-dist") @@ -471,7 +403,7 @@ impl Step for OptimizedDist { }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { // We need to ensure the rustc-perf submodule is initialized when building opt-dist since // the tool requires it to be in place to run. builder.require_submodule("src/tools/rustc-perf", None); @@ -500,7 +432,7 @@ pub struct RustcPerf { impl Step for RustcPerf { /// Path to the built `collector` binary. - type Output = ToolBuildResult; + type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/rustc-perf") @@ -513,7 +445,7 @@ impl Step for RustcPerf { }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { // We need to ensure the rustc-perf submodule is initialized. builder.require_submodule("src/tools/rustc-perf", None); @@ -530,12 +462,12 @@ impl Step for RustcPerf { // a CLI. cargo_args: vec!["-p".to_string(), "collector".to_string()], }; - let res = builder.ensure(tool.clone()); + let collector_bin = builder.ensure(tool.clone()); // We also need to symlink the `rustc-fake` binary to the corresponding directory, // because `collector` expects it in the same directory. copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake"); - res + collector_bin } } @@ -550,7 +482,7 @@ impl ErrorIndex { // 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 mut cmd = command(builder.ensure(ErrorIndex { compiler }).tool_path); + 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))); add_dylib_path(dylib_paths, &mut cmd); @@ -559,23 +491,27 @@ impl ErrorIndex { } impl Step for ErrorIndex { - type Output = ToolBuildResult; + type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/error_index_generator") } 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, run.builder.config.build); + let compiler = + run.builder.compiler(run.builder.top_stage.saturating_sub(1), run.builder.config.build); run.builder.ensure(ErrorIndex { compiler }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { builder.ensure(ToolBuild { compiler: self.compiler, target: self.compiler.host, @@ -597,7 +533,7 @@ pub struct RemoteTestServer { } impl Step for RemoteTestServer { - type Output = ToolBuildResult; + type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/remote-test-server") @@ -610,7 +546,7 @@ impl Step for RemoteTestServer { }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -633,7 +569,7 @@ pub struct Rustdoc { } impl Step for Rustdoc { - type Output = ToolBuildResult; + type Output = PathBuf; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -642,25 +578,24 @@ impl Step for Rustdoc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.target) }); + run.builder.ensure(Rustdoc { + // NOTE: this is somewhat unique in that we actually want a *target* + // 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), + }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { let target_compiler = self.compiler; - let target = target_compiler.host; - if target_compiler.stage == 0 { if !target_compiler.is_snapshot(builder) { panic!("rustdoc in stage 0 must be snapshot rustdoc"); } - - return ToolBuildResult { - tool_path: builder.initial_rustdoc.clone(), - build_compiler: target_compiler, - target_compiler, - }; + return builder.initial_rustdoc.clone(); } + let target = target_compiler.host; let bin_rustdoc = || { let sysroot = builder.sysroot(target_compiler); @@ -690,15 +625,27 @@ impl Step for Rustdoc { let bin_rustdoc = bin_rustdoc(); builder.copy_link(&precompiled_rustdoc, &bin_rustdoc); - - return ToolBuildResult { - tool_path: bin_rustdoc, - build_compiler: target_compiler, - target_compiler, - }; + return bin_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 @@ -706,39 +653,65 @@ 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 extra_features = Vec::new(); + let mut features = Vec::new(); if builder.config.jemalloc(target) { - extra_features.push("jemalloc".to_string()); + features.push("jemalloc".to_string()); } - let ToolBuildResult { tool_path, build_compiler, target_compiler } = - builder.ensure(ToolBuild { - compiler: target_compiler, - target, - // 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(), - }); + // 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, + target, + Kind::Build, + "src/tools/rustdoc", + SourceType::InTree, + features.as_slice(), + ); + + // rustdoc is performance sensitive, so apply LTO to it. + if is_lto_stage(&build_compiler) { + 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)); // don't create a stage0-sysroot/bin directory. if target_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 - compile::strip_debug(builder, target, &tool_path); + compile::strip_debug(builder, target, &tool_rustdoc); } let bin_rustdoc = bin_rustdoc(); - builder.copy_link(&tool_path, &bin_rustdoc); - ToolBuildResult { tool_path: bin_rustdoc, build_compiler, target_compiler } + builder.copy_link(&tool_rustdoc, &bin_rustdoc); + bin_rustdoc } else { - ToolBuildResult { tool_path, build_compiler, target_compiler } + tool_rustdoc } } } @@ -750,7 +723,7 @@ pub struct Cargo { } impl Step for Cargo { - type Output = ToolBuildResult; + type Output = PathBuf; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -766,7 +739,7 @@ impl Step for Cargo { }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { builder.build.require_submodule("src/tools/cargo", None); builder.ensure(ToolBuild { @@ -790,7 +763,7 @@ pub struct LldWrapper { } impl Step for LldWrapper { - type Output = ToolBuildResult; + type Output = (); fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() @@ -805,19 +778,14 @@ impl Step for LldWrapper { fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler), ), )] - - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) { if builder.config.dry_run() { - return ToolBuildResult { - tool_path: Default::default(), - build_compiler: self.build_compiler, - target_compiler: self.target_compiler, - }; + return; } let target = self.target_compiler.host; - let tool_result = builder.ensure(ToolBuild { + let executable = builder.ensure(ToolBuild { compiler: self.build_compiler, target, tool: "lld-wrapper", @@ -841,11 +809,8 @@ impl Step for LldWrapper { t!(fs::create_dir_all(&self_contained_lld_dir)); for name in crate::LLD_FILE_NAMES { - builder - .copy_link(&tool_result.tool_path, &self_contained_lld_dir.join(exe(name, target))); + builder.copy_link(&executable, &self_contained_lld_dir.join(exe(name, target))); } - - tool_result } } @@ -860,7 +825,7 @@ impl RustAnalyzer { } impl Step for RustAnalyzer { - type Output = ToolBuildResult; + type Output = PathBuf; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -876,7 +841,7 @@ impl Step for RustAnalyzer { }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -898,7 +863,7 @@ pub struct RustAnalyzerProcMacroSrv { } impl Step for RustAnalyzerProcMacroSrv { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -920,8 +885,8 @@ impl Step for RustAnalyzerProcMacroSrv { }); } - fn run(self, builder: &Builder<'_>) -> Option { - let tool_result = builder.ensure(ToolBuild { + fn run(self, builder: &Builder<'_>) -> Option { + let path = builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, tool: "rust-analyzer-proc-macro-srv", @@ -937,10 +902,9 @@ impl Step for RustAnalyzerProcMacroSrv { // so that r-a can use it. let libexec_path = builder.sysroot(self.compiler).join("libexec"); t!(fs::create_dir_all(&libexec_path)); - builder - .copy_link(&tool_result.tool_path, &libexec_path.join("rust-analyzer-proc-macro-srv")); + builder.copy_link(&path, &libexec_path.join("rust-analyzer-proc-macro-srv")); - Some(tool_result) + Some(path) } } @@ -952,7 +916,7 @@ pub struct LlvmBitcodeLinker { } impl Step for LlvmBitcodeLinker { - type Output = ToolBuildResult; + type Output = PathBuf; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -974,34 +938,51 @@ impl Step for LlvmBitcodeLinker { feature = "tracing", instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all) )] - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - let tool_result = 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(), - }); + 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)); + } - if tool_result.target_compiler.stage > 0 { + 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)); + + if self.compiler.stage > 0 { let bindir_self_contained = builder - .sysroot(tool_result.target_compiler) + .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("llvm-bitcode-linker", tool_result.target_compiler.host)); - builder.copy_link(&tool_result.tool_path, &bin_destination); - ToolBuildResult { - tool_path: bin_destination, - build_compiler: tool_result.build_compiler, - target_compiler: tool_result.target_compiler, - } + let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host)); + builder.copy_link(&tool_out, &bin_destination); + bin_destination } else { - tool_result + tool_out } } } @@ -1086,7 +1067,7 @@ macro_rules! tool_extended { } impl Step for $name { - type Output = ToolBuildResult; + type Output = PathBuf; const DEFAULT: bool = true; // Overridden by `should_run_tool_build_step` const ONLY_HOSTS: bool = true; @@ -1106,7 +1087,7 @@ macro_rules! tool_extended { }); } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) -> PathBuf { let Self { compiler, target } = self; run_tool_build_step( builder, @@ -1152,37 +1133,38 @@ fn run_tool_build_step( tool_name: &'static str, path: &'static str, add_bins_to_sysroot: Option<&[&str]>, -) -> ToolBuildResult { - let ToolBuildResult { tool_path, build_compiler, target_compiler } = - builder.ensure(ToolBuild { - compiler, - target, - tool: tool_name, - mode: Mode::ToolRustc, - path, - extra_features: vec![], - source_type: SourceType::InTree, - allow_features: "", - cargo_args: vec![], - }); +) -> PathBuf { + let tool = builder.ensure(ToolBuild { + compiler, + target, + tool: tool_name, + mode: Mode::ToolRustc, + path, + extra_features: vec![], + source_type: SourceType::InTree, + allow_features: "", + cargo_args: vec![], + }); // FIXME: This should just be an if-let-chain, but those are unstable. if let Some(add_bins_to_sysroot) = - add_bins_to_sysroot.filter(|bins| !bins.is_empty() && target_compiler.stage > 0) + add_bins_to_sysroot.filter(|bins| !bins.is_empty() && compiler.stage > 0) { - let bindir = builder.sysroot(target_compiler).join("bin"); + 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_destination = bindir.join(exe(add_bin, target_compiler.host)); - builder.copy_link(&tool_path, &bin_destination); + 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); } // Return a path into the bin dir. - let path = bindir.join(exe(tool_name, target_compiler.host)); - ToolBuildResult { tool_path: path, build_compiler, target_compiler } + bindir.join(exe(tool_name, compiler.host)) } else { - ToolBuildResult { tool_path, build_compiler, target_compiler } + tool } } @@ -1220,7 +1202,7 @@ pub struct TestFloatParse { } impl Step for TestFloatParse { - type Output = ToolBuildResult; + type Output = (); const ONLY_HOSTS: bool = true; const DEFAULT: bool = false; @@ -1228,7 +1210,7 @@ impl Step for TestFloatParse { run.path("src/etc/test-float-parse") } - fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.build; let compiler = builder.compiler(builder.top_stage, bootstrap_host); @@ -1242,7 +1224,7 @@ impl Step for TestFloatParse { extra_features: Vec::new(), allow_features: "", cargo_args: Vec::new(), - }) + }); } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 25fa10e081114..daef8fa3c8a34 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1392,7 +1392,7 @@ impl<'a> Builder<'a> { } pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { - self.ensure(tool::Rustdoc { compiler }).tool_path + self.ensure(tool::Rustdoc { compiler }) } pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { @@ -1408,13 +1408,14 @@ impl<'a> Builder<'a> { return cmd; } - let _ = self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.build }); + 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: run_compiler, target: self.build.build }); + self.ensure(tool::CargoClippy { compiler: build_compiler, target: self.build.build }); let mut dylib_path = helpers::dylib_path(); dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); - let mut cmd = command(cargo_clippy.tool_path); + let mut cmd = command(cargo_clippy); cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cmd.env("CARGO", &self.initial_cargo); cmd @@ -1422,21 +1423,23 @@ impl<'a> Builder<'a> { 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); + // Prepare the tools - let miri = self.ensure(tool::Miri { compiler: run_compiler, target: self.build.build }); + let miri = self.ensure(tool::Miri { compiler: build_compiler, target: self.build.build }); let cargo_miri = - self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.build }); + self.ensure(tool::CargoMiri { compiler: build_compiler, target: self.build.build }); // Invoke cargo-miri, make sure it can find miri and cargo. - let mut cmd = command(cargo_miri.tool_path); - cmd.env("MIRI", &miri.tool_path); + let mut cmd = command(cargo_miri); + cmd.env("MIRI", &miri); cmd.env("CARGO", &self.initial_cargo); - // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler` - // in `tool::ToolBuild` step, so they match the Miri we just built. However this means they - // are actually living one stage up, i.e. we are running `stage0-tools-bin/miri` with the - // libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact - // that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary. - // We can't use `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. + // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`, + // so they match the Miri we just built. However this means they are actually living one + // stage up, i.e. we are running `stage0-tools-bin/miri` with the libraries in `stage1/lib`. + // This is an unfortunate off-by-1 caused (possibly) by the fact that Miri doesn't have an + // "assemble" step like rustc does that would cross the stage boundary. We can't use + // `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); cmd diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b6aa9e7c8446d..445b5dfbeab22 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -525,7 +525,6 @@ mod dist { 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), ] ); @@ -1085,33 +1084,3 @@ fn test_is_builder_target() { assert!(!builder.is_builder_target(target2)); } } - -#[test] -fn test_get_tool_rustc_compiler() { - let mut config = configure("build", &[], &[]); - config.download_rustc_commit = None; - let build = Build::new(config); - let builder = Builder::new(&build); - - let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); - - let compiler = Compiler { stage: 2, host: target_triple_1 }; - let expected = Compiler { stage: 1, host: target_triple_1 }; - let actual = tool::get_tool_rustc_compiler(&builder, compiler); - assert_eq!(expected, actual); - - let compiler = Compiler { stage: 1, host: target_triple_1 }; - let expected = Compiler { stage: 0, host: target_triple_1 }; - let actual = tool::get_tool_rustc_compiler(&builder, compiler); - assert_eq!(expected, actual); - - let mut config = configure("build", &[], &[]); - config.download_rustc_commit = Some("".to_owned()); - let build = Build::new(config); - let builder = Builder::new(&build); - - let compiler = Compiler { stage: 1, host: target_triple_1 }; - let expected = Compiler { stage: 1, host: target_triple_1 }; - let actual = tool::get_tool_rustc_compiler(&builder, compiler); - assert_eq!(expected, actual); -} diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 8dfe0d3a35ef6..f215c3f6d0b39 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -355,9 +355,4 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "It is now possible to configure `jemalloc` for each target", }, - ChangeInfo { - change_id: 137215, - severity: ChangeSeverity::Info, - summary: "Added `build.test-stage = 2` to 'tools' profile defaults", - }, ]; diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 106db508ebbc7..91c4aeacbd749 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -75,7 +75,6 @@ - [Prologue](./building/bootstrapping/intro.md) - [What Bootstrapping does](./building/bootstrapping/what-bootstrapping-does.md) - [How Bootstrap does it](./building/bootstrapping/how-bootstrap-does-it.md) -- [Writing tools in Bootstrap](./building/bootstrapping/writing-tools-in-bootstrap.md) - [Debugging bootstrap](./building/bootstrapping/debugging-bootstrap.md) # High-level Compiler Architecture diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md deleted file mode 100644 index 6046d5b133d7d..0000000000000 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md +++ /dev/null @@ -1,23 +0,0 @@ -# Writing tools in Bootstrap - -There are three types of tools you can write in bootstrap: - -- **`Mode::ToolBootstrap`** - Use this for tools that don’t need anything from the in-tree compiler and can run with the stage0 `rustc`. - The output is placed in the "stage0-bootstrap-tools" directory. This mode is for general-purpose tools built - entirely with the stage0 compiler, including target libraries and only works for stage 0. - -- **`Mode::ToolStd`** - Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory. - This mode is rarely used, mainly for `compiletest` which requires `libtest`. - -- **`Mode::ToolRustc`** - Use this for tools that depend on both the locally built `rustc` and the target `std`. This is more complex than - the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" - directory. When you choose `Mode::ToolRustc`, `ToolBuild` implementation takes care of this automatically. - If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is - returned by the tool's [`Step`]. - -Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it. - -[`Step`]: https://doc.rust-lang.org/nightly/nightly-rustc/bootstrap/core/builder/trait.Step.html