diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 5ecce31fe1562..6a8700ee1f2a8 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2024,19 +2024,25 @@ 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, - extra_features: vec![], + target: compiler.host, }); - let tool_exe = exe("llvm-bitcode-linker", 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", 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/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 7aa9e6cc2b53e..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,24 +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, extra_features: vec![] }); + 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 717accb399adc..8e4a82077dd0c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -983,11 +983,12 @@ impl Step for RustAnalyzerProcMacroSrv { } } -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +/// 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, PartialOrd, Ord)] pub struct LlvmBitcodeLinker { - pub compiler: Compiler, pub target: TargetSelection, - pub extra_features: Vec, } impl Step for LlvmBitcodeLinker { @@ -1002,11 +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), - extra_features: Vec::new(), - target: run.target, - }); + run.builder.ensure(LlvmBitcodeLinker { target: run.target }); } #[cfg_attr( @@ -1014,35 +1011,20 @@ impl Step for LlvmBitcodeLinker { instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all) )] fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - let tool_result = builder.ensure(ToolBuild { - compiler: self.compiler, + let compiler = builder.compiler_for_target(self.target); + + builder.ensure(ToolBuild { + 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, + extra_features: vec![], 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 - } + }) } } 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)) } 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) }] + ); +}