From 89370e0240adf25216427e787787780bcb90156e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 17:16:14 +0200 Subject: [PATCH] Make `WasmComponentLd` a `ToolTarget` tool --- src/bootstrap/src/core/build_steps/check.rs | 5 +- src/bootstrap/src/core/build_steps/compile.rs | 14 +-- src/bootstrap/src/core/build_steps/tool.rs | 107 +++++++++++++++++- src/bootstrap/src/core/builder/mod.rs | 1 + 4 files changed, 111 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 2ba4c37d9a71..d4d3b7a7babe 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -5,7 +5,8 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ - COMPILETEST_ALLOW_FEATURES, SourceType, get_compiler_for_target, prepare_tool_cargo, + COMPILETEST_ALLOW_FEATURES, SourceType, ToolTargetBuildMode, get_tool_target_compiler, + prepare_tool_cargo, }; use crate::core::builder::{ self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, @@ -252,7 +253,7 @@ fn prepare_compiler_for_check( match mode { Mode::ToolBootstrap => builder.compiler(0, host), - Mode::ToolTarget => get_compiler_for_target(builder, target), + Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)), Mode::ToolStd => { // These tools require the local standard library to be checked let build_compiler = builder.compiler(builder.top_stage, host); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 0587d21ecc28..60618942c820 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2286,15 +2286,13 @@ impl Step for Assemble { } // In addition to `rust-lld` also install `wasm-component-ld` when - // LLD is enabled. This is a relatively small binary that primarily - // delegates to the `rust-lld` binary for linking and then runs - // logic to create the final binary. This is used by the - // `wasm32-wasip2` target of Rust. + // is enabled. 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 = + builder.ensure(crate::core::build_steps::tool::WasmComponentLd::for_compiler( + builder, + target_compiler, + )); builder.copy_link( &wasm_component.tool_path, &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 631d04385274..2d3187274f2a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -365,12 +365,36 @@ pub(crate) fn get_tool_rustc_compiler( builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target) } -/// Returns the smallest stage compiler that is able to compile code for the given `target`. -pub(crate) fn get_compiler_for_target(builder: &Builder<'_>, target: TargetSelection) -> Compiler { +/// Determines how to build a `ToolTarget`, i.e. which compiler should be used to compile it. +/// The compiler stage is automatically auto-bumped if we need to cross-compile a stage 1 tool. +pub enum ToolTargetBuildMode { + /// Build the tool using rustc that corresponds to the selected CLI stage. + Build(TargetSelection), + /// Build the tool so that it can be attached to the sysroot of the passed compiler. + /// Since we always dist stage 2+, the compiler that builds the tool in this case has to be + /// stage 1+. + Dist(Compiler), +} + +/// Returns compiler that is able to compile a `ToolTarget` tool with the given `mode`. +pub(crate) fn get_tool_target_compiler( + builder: &Builder<'_>, + mode: ToolTargetBuildMode, +) -> Compiler { + let (target, min_build_compiler_stage) = match mode { + ToolTargetBuildMode::Build(target) => { + assert!(builder.top_stage > 0); + (target, builder.top_stage - 1) + } + ToolTargetBuildMode::Dist(target_compiler) => { + assert!(target_compiler.stage > 0); + (target_compiler.host, target_compiler.stage - 1) + } + }; let compiler = if builder.host_target == target { - builder.compiler(0, builder.host_target) + builder.compiler(min_build_compiler_stage, builder.host_target) } else { - builder.compiler(1, builder.host_target) + builder.compiler(min_build_compiler_stage.max(1), builder.host_target) }; builder.std(compiler, target); compiler @@ -533,7 +557,6 @@ bootstrap_tool!( // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; - WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump"; OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"]; @@ -661,7 +684,10 @@ impl Step for RemoteTestServer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RemoteTestServer { - build_compiler: get_compiler_for_target(run.builder, run.target), + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), + ), target: run.target, }); } @@ -935,6 +961,75 @@ impl Step for LldWrapper { } } +/// Builds the `wasm-component-ld` linker wrapper, which is shipped with rustc to be executed on the +/// host platform where rustc runs. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct WasmComponentLd { + build_compiler: Compiler, + target: TargetSelection, +} + +impl WasmComponentLd { + /// Returns `WasmComponentLd` that should be **used** by the passed compiler. + pub fn for_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self { + Self { + build_compiler: get_tool_target_compiler( + builder, + ToolTargetBuildMode::Dist(target_compiler), + ), + target: target_compiler.host, + } + } +} + +impl Step for WasmComponentLd { + type Output = ToolBuildResult; + + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/wasm-component-ld") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(WasmComponentLd { + build_compiler: get_tool_target_compiler( + run.builder, + ToolTargetBuildMode::Build(run.target), + ), + target: run.target, + }); + } + + #[cfg_attr( + feature = "tracing", + instrument( + level = "debug", + name = "WasmComponentLd::run", + skip_all, + fields(build_compiler = ?self.build_compiler), + ), + )] + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + builder.ensure(ToolBuild { + build_compiler: self.build_compiler, + target: self.target, + tool: "wasm-component-ld", + mode: Mode::ToolTarget, + path: "src/tools/wasm-component-ld", + source_type: SourceType::InTree, + extra_features: vec![], + allow_features: "min-specialization", + cargo_args: vec![], + artifact_kind: ToolArtifactKind::Binary, + }) + } + + fn metadata(&self) -> Option { + Some(StepMetadata::build("WasmComponentLd", self.target).built_by(self.build_compiler)) + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index e538c12df6d9..65e9c3850e79 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -981,6 +981,7 @@ impl<'a> Builder<'a> { tool::CoverageDump, tool::LlvmBitcodeLinker, tool::RustcPerf, + tool::WasmComponentLd ), Kind::Clippy => describe!( clippy::Std,