From 9ed5fbaf2296f5be8a47a9f6549b83c72c3442ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 10 Jun 2025 20:15:36 +0200 Subject: [PATCH 1/4] Remove `extra_features` from `LlvmBitcodeLinker` It wasn't used anywhere. --- src/bootstrap/src/core/build_steps/compile.rs | 1 - src/bootstrap/src/core/build_steps/dist.rs | 3 +-- src/bootstrap/src/core/build_steps/tool.rs | 4 +--- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 5ecce31fe1562..1e7063da5ecb0 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2031,7 +2031,6 @@ impl Step for Assemble { 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( diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 7aa9e6cc2b53e..96e7d08990d08 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2354,8 +2354,7 @@ impl Step for LlvmBitcodeLinker { builder.ensure(compile::Rustc::new(compiler, target)); - let llbc_linker = - builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] }); + let llbc_linker = builder.ensure(tool::LlvmBitcodeLinker { compiler, target }); let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 717accb399adc..05b5a7d5fe9c5 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -987,7 +987,6 @@ impl Step for RustAnalyzerProcMacroSrv { pub struct LlvmBitcodeLinker { pub compiler: Compiler, pub target: TargetSelection, - pub extra_features: Vec, } impl Step for LlvmBitcodeLinker { @@ -1004,7 +1003,6 @@ 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), - extra_features: Vec::new(), target: run.target, }); } @@ -1021,7 +1019,7 @@ impl Step for LlvmBitcodeLinker { mode: Mode::ToolRustc, path: "src/tools/llvm-bitcode-linker", source_type: SourceType::InTree, - extra_features: self.extra_features, + extra_features: vec![], allow_features: "", cargo_args: Vec::new(), artifact_kind: ToolArtifactKind::Binary, From 6178c6da312fac0ed3d7589d76fd5943a4b7b87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 11 Jun 2025 08:50:09 +0200 Subject: [PATCH 2/4] Remove sysroot copy from `LlvmBitcodeLinker` step That step should be responsible for building the tool, not performing side-effects. Also, only copy the tool to the `self-contained` directory, not to the `rustlib//bin` directory. --- src/bootstrap/src/core/build_steps/compile.rs | 9 +++++++- src/bootstrap/src/core/build_steps/tool.rs | 21 ++----------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 1e7063da5ecb0..bca02b04ef7cf 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2032,10 +2032,17 @@ impl Step for Assemble { compiler, target: target_compiler.host, }); + + // Copy the llvm-bitcode-linker to the self-contained binary directory + let bindir_self_contained = builder + .sysroot(compiler) + .join(format!("lib/rustlib/{}/bin/self-contained", compiler.host)); let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); + + t!(fs::create_dir_all(&bindir_self_contained)); builder.copy_link( &llvm_bitcode_linker.tool_path, - &libdir_bin.join(tool_exe), + &bindir_self_contained.join(tool_exe), FileType::Executable, ); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 05b5a7d5fe9c5..6dcd4dc91e597 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1012,7 +1012,7 @@ impl Step for LlvmBitcodeLinker { instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all) )] fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - let tool_result = builder.ensure(ToolBuild { + builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, tool: "llvm-bitcode-linker", @@ -1023,24 +1023,7 @@ impl Step for LlvmBitcodeLinker { allow_features: "", cargo_args: Vec::new(), artifact_kind: ToolArtifactKind::Binary, - }); - - if tool_result.target_compiler.stage > 0 { - let bindir_self_contained = builder - .sysroot(tool_result.target_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, FileType::Executable); - ToolBuildResult { - tool_path: bin_destination, - build_compiler: tool_result.build_compiler, - target_compiler: tool_result.target_compiler, - } - } else { - tool_result - } + }) } } From 6d949a7dea6abcb26ccf8b1e2a86caddbdfe4c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 11 Jun 2025 08:59:55 +0200 Subject: [PATCH 3/4] Build `llvm-bitcode-linker` as a HostRustc tool This tool can be built with any compiler that can produce code for the host target of the compiler for which the linker should be installed. This change saves one rebuild of the tool in stage 2 build. --- src/bootstrap/src/core/build_steps/compile.rs | 8 ++++---- src/bootstrap/src/core/build_steps/dist.rs | 18 +++--------------- src/bootstrap/src/core/build_steps/install.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 13 +++++++------ src/bootstrap/src/core/builder/mod.rs | 15 +++++++++++++++ 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index bca02b04ef7cf..6a8700ee1f2a8 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2024,20 +2024,20 @@ impl Step for Assemble { } } - let maybe_install_llvm_bitcode_linker = |compiler| { + // Build llvm-bitcode-linker if it is enabled and install it into the sysroot of `compiler` + let maybe_install_llvm_bitcode_linker = |compiler: 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, + target: compiler.host, }); // Copy the llvm-bitcode-linker to the self-contained binary directory let bindir_self_contained = builder .sysroot(compiler) .join(format!("lib/rustlib/{}/bin/self-contained", compiler.host)); - let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); + let tool_exe = exe("llvm-bitcode-linker", compiler.host); t!(fs::create_dir_all(&bindir_self_contained)); builder.copy_link( diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 96e7d08990d08..d32ac537ef842 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1555,7 +1555,7 @@ impl Step for Extended { compiler: builder.compiler(stage, target), backend: "cranelift".to_string(), }); - add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target}); + add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {target}); let etc = builder.src.join("src/etc/installer"); @@ -2323,7 +2323,6 @@ impl Step for LlvmTools { #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct LlvmBitcodeLinker { - pub compiler: Compiler, pub target: TargetSelection, } @@ -2338,23 +2337,12 @@ impl Step for LlvmBitcodeLinker { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(LlvmBitcodeLinker { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.build, - run.target, - ), - target: run.target, - }); + run.builder.ensure(LlvmBitcodeLinker { target: run.target }); } fn run(self, builder: &Builder<'_>) -> Option { - let compiler = self.compiler; let target = self.target; - - builder.ensure(compile::Rustc::new(compiler, target)); - - let llbc_linker = builder.ensure(tool::LlvmBitcodeLinker { compiler, target }); + let llbc_linker = builder.ensure(tool::LlvmBitcodeLinker { target }); let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 5419540aa2e08..15ad0e57ad5c5 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -287,7 +287,7 @@ install!((self, builder, _config), } }; LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, { - if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) { + if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { target: self.target }) { install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); } else { builder.info( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 6dcd4dc91e597..f702ce8157986 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -983,9 +983,11 @@ impl Step for RustAnalyzerProcMacroSrv { } } +/// Compile the `llvm-bitcode-linker` tool for `target`. +/// It is a compiler host tool used to link specific targets using LLVM. +/// It is used by `rustc` at runtime. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct LlvmBitcodeLinker { - pub compiler: Compiler, pub target: TargetSelection, } @@ -1001,10 +1003,7 @@ 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), - target: run.target, - }); + run.builder.ensure(LlvmBitcodeLinker { target: run.target }); } #[cfg_attr( @@ -1012,8 +1011,10 @@ impl Step for LlvmBitcodeLinker { instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all) )] fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + let compiler = builder.compiler_for_target(self.target); + builder.ensure(ToolBuild { - compiler: self.compiler, + compiler, target: self.target, tool: "llvm-bitcode-linker", mode: Mode::ToolRustc, diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8b1520de3a854..c66d5d1d1b78e 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -15,6 +15,7 @@ use tracing::instrument; pub use self::cargo::{Cargo, cargo_profile_var}; pub use crate::Compiler; +use crate::core::build_steps::compile::Std; use crate::core::build_steps::{ check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, tool, vendor, }; @@ -1314,6 +1315,20 @@ impl<'a> Builder<'a> { resolved_compiler } + /// Return the lowest stage compiler that can compile code for the given `target`. + pub fn compiler_for_target(&self, target: TargetSelection) -> Compiler { + // If we're not cross-compiling, we can always use the stage0 compiler + if self.config.build == target { + self.compiler(0, target) + } else { + // Otherwise, we have to build a stage 1 compiler that can compile code for `target`. + let compiler = self.compiler(1, self.config.build); + // FIXME(kobzol): get rid of this nonsense and create something like `RustcWithStdForTarget` + self.ensure(Std::new(compiler, target)); + compiler + } + } + pub fn sysroot(&self, compiler: Compiler) -> PathBuf { self.ensure(compile::Sysroot::new(compiler)) } From 769f9847c6dfe723845ca39cbeecf57a2b00c90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 11 Jun 2025 12:28:51 +0200 Subject: [PATCH 4/4] Add test --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/bootstrap/src/core/builder/tests.rs | 27 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index f702ce8157986..8e4a82077dd0c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -986,7 +986,7 @@ impl Step for RustAnalyzerProcMacroSrv { /// Compile the `llvm-bitcode-linker` tool for `target`. /// It is a compiler host tool used to link specific targets using LLVM. /// It is used by `rustc` at runtime. -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct LlvmBitcodeLinker { pub target: TargetSelection, } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a264d772c5629..1c26b4787e6c1 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -7,6 +7,7 @@ use llvm::prebuilt_llvm_config; use super::*; use crate::Flags; use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::build_steps::tool::LlvmBitcodeLinker; use crate::core::config::Config; use crate::utils::tests::git::{GitCtx, git_test}; @@ -1233,3 +1234,29 @@ fn any_debug() { // Downcasting to the underlying type should succeed. assert_eq!(x.downcast_ref::(), Some(&MyStruct { x: 7 })); } + +/// Check that during a non-cross-compiling stage 2 build, we only compile rustc host tools +/// (such as llvm-bitcode-linker) only once. +#[test] +fn llvm_bitcode_linker_compile_once() { + let mut cache = run_build( + &[], + configure_with_args( + &[ + "build".to_string(), + "--stage".to_string(), + "2".to_string(), + "--set".to_string(), + "rust.llvm-bitcode-linker=true".to_string(), + ], + &[TEST_TRIPLE_1], + &[TEST_TRIPLE_2], + ), + ); + + // Check that llvm-bitcode-linker was built only once, and for host, not target + assert_eq!( + first(cache.all::()), + &[LlvmBitcodeLinker { target: TargetSelection::from_user(TEST_TRIPLE_1) }] + ); +}