From b768c4f9500100aed7bb7b92f7ad5da59a55cd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 4 Aug 2026 16:06:44 +0200 Subject: [PATCH 01/10] Avoid using `is_system_llvm` in Config parsing At this point in the code, the LLVM config could not have been set by `download-ci-llvm` yet, so we don't have to check it. --- src/bootstrap/src/core/config/config.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 81a425fba1cab..d9ca3632eb8f6 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1076,7 +1076,7 @@ impl Config { llvm_assertions, ); let is_host_system_llvm = - is_system_llvm(&target_config, llvm_from_ci, host_target, host_target); + target_config.get(&host_target).and_then(|c| c.llvm_config.as_ref()).is_some(); if llvm_from_ci { let warn = |option: &str| { @@ -1111,9 +1111,7 @@ impl Config { "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." ); } - } - if llvm_from_ci { let triple = &host_target.triple; let ci_llvm_bin = ci_llvm_root(&dwn_ctx, llvm_from_ci, &out).join("bin"); let build_target = From 3febcb80abceb1cc7e6194811f321aa8ea51dd00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 4 Aug 2026 16:12:13 +0200 Subject: [PATCH 02/10] Rename `LlvmResult` to `LlvmOutput` To make it consistent with `GccOutput` --- src/bootstrap/src/core/build_steps/compile.rs | 4 +-- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 26 +++++++++---------- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 652e797538223..3a47e43feffaa 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1425,7 +1425,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_enzyme { cargo.env("LLVM_ENZYME", "1"); } - let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); + let llvm::LlvmOutput { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); if builder.config.llvm_offload { builder.ensure(llvm::OmpOffload { target }); cargo.env("LLVM_OFFLOAD", "1"); @@ -2122,7 +2122,7 @@ impl CommandLineStep for Assemble { trace!("target_compiler.host" = ?target_compiler.host, "LLVM enabled"); let target = target_compiler.host; - let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); + let llvm::LlvmOutput { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { trace!("LLVM tools enabled"); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 9028a7a340ca7..17cee4ec76054 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2527,7 +2527,7 @@ fn maybe_install_llvm( } } !builder.config.dry_run() - } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { + } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmOutput { host_llvm_config, .. }) = llvm::prebuilt_llvm_config(builder, target, true) { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index d3276cfb5371b..4354077760f67 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -27,7 +27,7 @@ use crate::utils::helpers::{ use crate::{CLang, GitRepo, Kind, exit, trace}; #[derive(Clone)] -pub struct LlvmResult { +pub struct LlvmOutput { /// Path to llvm-config binary. /// NB: This is always the host llvm-config! pub host_llvm_config: PathBuf, @@ -37,13 +37,13 @@ pub struct LlvmResult { pub struct Meta { stamp: BuildStamp, - res: LlvmResult, + res: LlvmOutput, out_dir: PathBuf, root: String, } pub enum LlvmBuildStatus { - AlreadyBuilt(LlvmResult), + AlreadyBuilt(LlvmOutput), ShouldBuild(Meta), } @@ -56,7 +56,7 @@ impl LlvmBuildStatus { } #[cfg(test)] - pub fn llvm_result(&self) -> &LlvmResult { + pub fn llvm_result(&self) -> &LlvmOutput { match self { LlvmBuildStatus::AlreadyBuilt(res) => res, LlvmBuildStatus::ShouldBuild(meta) => &meta.res, @@ -136,7 +136,7 @@ pub fn prebuilt_llvm_config( llvm_cmake_dir.push("lib"); llvm_cmake_dir.push("cmake"); llvm_cmake_dir.push("llvm"); - return LlvmBuildStatus::AlreadyBuilt(LlvmResult { host_llvm_config, llvm_cmake_dir }); + return LlvmBuildStatus::AlreadyBuilt(LlvmOutput { host_llvm_config, llvm_cmake_dir }); } if handle_submodule_when_needed { @@ -161,7 +161,7 @@ pub fn prebuilt_llvm_config( }; let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); - let res = LlvmResult { host_llvm_config: build_llvm_config, llvm_cmake_dir }; + let res = LlvmOutput { host_llvm_config: build_llvm_config, llvm_cmake_dir }; static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -273,7 +273,7 @@ pub struct Llvm { } impl CommandLineStep for Llvm { - type Output = LlvmResult; + type Output = LlvmOutput; const IS_HOST: bool = true; @@ -286,7 +286,7 @@ impl CommandLineStep for Llvm { } /// Compile LLVM for `target`. - fn run(self, builder: &Builder<'_>) -> LlvmResult { + fn run(self, builder: &Builder<'_>) -> LlvmOutput { let target = self.target; let target_native = if self.target.starts_with("riscv") { // RISC-V target triples in Rust is not named the same as C compiler target triples. @@ -509,7 +509,7 @@ impl CommandLineStep for Llvm { // https://llvm.org/docs/HowToCrossCompileLLVM.html if !builder.config.is_host_target(target) { - let LlvmResult { host_llvm_config, .. } = + let LlvmOutput { host_llvm_config, .. } = builder.ensure(Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { let llvm_bindir = command(&host_llvm_config) @@ -992,7 +992,7 @@ impl CommandLineStep for OmpOffload { } let target = self.target; - let LlvmResult { host_llvm_config, llvm_cmake_dir } = + let LlvmOutput { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target: self.target }); // Running cmake twice in the same folder is known to cause issues, like deleting existing @@ -1174,7 +1174,7 @@ impl CommandLineStep for Enzyme { return BuiltEnzyme { enzyme: builder.config.tempdir().join("enzyme-dryrun") }; } - let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); + let LlvmOutput { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); // Enzyme links against LLVM. If we update the LLVM submodule libLLVM might get a new // version number, in which case Enzyme will now fail to find LLVM. By including the LLVM @@ -1305,7 +1305,7 @@ impl CommandLineStep for Lld { } let target = self.target; - let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); + let LlvmOutput { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin` @@ -1435,7 +1435,7 @@ impl CommandLineStep for Sanitizers { return runtimes; } - let LlvmResult { host_llvm_config, .. } = + let LlvmOutput { host_llvm_config, .. } = builder.ensure(Llvm { target: builder.config.host_target }); static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9257a238a3498..2ebca2e77eefc 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2630,7 +2630,7 @@ Please disable assertions with `rust.debug-assertions = false`. let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled(test_compiler.host) { - let llvm::LlvmResult { host_llvm_config, .. } = + let llvm::LlvmOutput { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { let llvm_version = get_llvm_version(builder, &host_llvm_config); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 603ef65854cf6..6321ba3630166 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1551,7 +1551,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler /// *target*. pub fn llvm_config(&self, target: TargetSelection) -> Option { if self.config.llvm_enabled(target) && self.kind != Kind::Check && !self.config.dry_run() { - let llvm::LlvmResult { host_llvm_config, .. } = self.ensure(llvm::Llvm { target }); + let llvm::LlvmOutput { host_llvm_config, .. } = self.ensure(llvm::Llvm { target }); if host_llvm_config.is_file() { return Some(host_llvm_config); } From 5d835ab6a289d63eebc06d8aa08e00f00563abe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 4 Aug 2026 16:27:50 +0200 Subject: [PATCH 03/10] Store LLVM root directory in `LlvmOutput` So that it can be used explicitly in bootstrap, rather than depending on `builder.llvm_out`. --- src/bootstrap/src/core/build_steps/llvm.rs | 56 ++++++++++++---------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 4354077760f67..da857676a58c7 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -26,13 +26,21 @@ use crate::utils::helpers::{ }; use crate::{CLang, GitRepo, Kind, exit, trace}; +/// Result of building or downloading LLVM artifacts. #[derive(Clone)] pub struct LlvmOutput { /// Path to llvm-config binary. /// NB: This is always the host llvm-config! pub host_llvm_config: PathBuf, - /// Path to LLVM cmake directory for the target. - pub llvm_cmake_dir: PathBuf, + /// Directory containing the built LLVM artifacts. + pub llvm_root_dir: PathBuf, +} + +impl LlvmOutput { + /// Path to LLVM cmake directory. + pub fn llvm_cmake_dir(&self) -> PathBuf { + self.llvm_root_dir.join("lib").join("cmake").join("llvm") + } } pub struct Meta { @@ -130,13 +138,10 @@ pub fn prebuilt_llvm_config( { check_llvm_version(builder, s); let host_llvm_config = s.to_path_buf(); - let mut llvm_cmake_dir = host_llvm_config.clone(); - llvm_cmake_dir.pop(); - llvm_cmake_dir.pop(); - llvm_cmake_dir.push("lib"); - llvm_cmake_dir.push("cmake"); - llvm_cmake_dir.push("llvm"); - return LlvmBuildStatus::AlreadyBuilt(LlvmOutput { host_llvm_config, llvm_cmake_dir }); + let mut llvm_root_dir = host_llvm_config.clone(); + llvm_root_dir.pop(); + llvm_root_dir.pop(); + return LlvmBuildStatus::AlreadyBuilt(LlvmOutput { host_llvm_config, llvm_root_dir }); } if handle_submodule_when_needed { @@ -160,8 +165,7 @@ pub fn prebuilt_llvm_config( llvm_config_ret_dir.join(exe("llvm-config", builder.config.host_target)) }; - let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); - let res = LlvmOutput { host_llvm_config: build_llvm_config, llvm_cmake_dir }; + let res = LlvmOutput { host_llvm_config: build_llvm_config, llvm_root_dir: out_dir.clone() }; static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -992,8 +996,7 @@ impl CommandLineStep for OmpOffload { } let target = self.target; - let LlvmOutput { host_llvm_config, llvm_cmake_dir } = - builder.ensure(Llvm { target: self.target }); + let llvm_output = builder.ensure(Llvm { target: self.target }); // Running cmake twice in the same folder is known to cause issues, like deleting existing // binaries. We therefore write our offload artifacts into it's own folder, instead of @@ -1087,12 +1090,12 @@ impl CommandLineStep for OmpOffload { // runtime to simplify our build. So far, these are still under development. cfg.out_dir(&out_dir) .profile(profile) - .env("LLVM_CONFIG_REAL", &host_llvm_config) + .env("LLVM_CONFIG_REAL", &llvm_output.host_llvm_config) .define("LLVM_ENABLE_ASSERTIONS", "ON") .define("LLVM_INCLUDE_TESTS", "OFF") .define("OFFLOAD_INCLUDE_TESTS", "OFF") .define("LLVM_ROOT", builder.llvm_out(target).join("build")) - .define("LLVM_DIR", llvm_cmake_dir.clone()) + .define("LLVM_DIR", llvm_output.llvm_cmake_dir()) .define("LLVM_DEFAULT_TARGET_TRIPLE", omp_target); if let Some(p) = clang_dir.clone() { cfg.define("Clang_DIR", p); @@ -1174,7 +1177,7 @@ impl CommandLineStep for Enzyme { return BuiltEnzyme { enzyme: builder.config.tempdir().join("enzyme-dryrun") }; } - let LlvmOutput { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); + let llvm_output = builder.ensure(Llvm { target }); // Enzyme links against LLVM. If we update the LLVM submodule libLLVM might get a new // version number, in which case Enzyme will now fail to find LLVM. By including the LLVM @@ -1194,7 +1197,8 @@ impl CommandLineStep for Enzyme { let out_dir = builder.enzyme_out(target); let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash); - let llvm_version_major = llvm::get_llvm_version_major(builder, &host_llvm_config); + let llvm_version_major = + llvm::get_llvm_version_major(builder, &llvm_output.host_llvm_config); let lib_ext = std::env::consts::DLL_EXTENSION; let libenzyme = format!("libEnzyme-{llvm_version_major}"); let build_dir = out_dir.join(libdir(target)); @@ -1216,10 +1220,11 @@ impl CommandLineStep for Enzyme { return BuiltEnzyme { enzyme: dylib }; } + let llvm_cmake_dir = llvm_output.llvm_cmake_dir(); if !builder.config.dry_run() && !llvm_cmake_dir.is_dir() { builder.info(&format!( - "WARNING: {} does not exist, Enzyme build will likely fail", - llvm_cmake_dir.display() + "WARNING: {:?} does not exist, Enzyme build will likely fail", + llvm_cmake_dir )); } @@ -1258,7 +1263,7 @@ impl CommandLineStep for Enzyme { cfg.out_dir(&out_dir) .profile(profile) - .env("LLVM_CONFIG_REAL", &host_llvm_config) + .env("LLVM_CONFIG_REAL", &llvm_output.host_llvm_config) .define("LLVM_ENABLE_ASSERTIONS", "ON") .define("ENZYME_EXTERNAL_SHARED_LIB", "ON") .define("ENZYME_BC_LOADER", "OFF") @@ -1305,13 +1310,13 @@ impl CommandLineStep for Lld { } let target = self.target; - let LlvmOutput { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); + let llvm_output = builder.ensure(Llvm { target }); // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin` // subfolder. We check if that's the case, and if LLD's binary already exists there next to // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source. - let ci_llvm_bin = host_llvm_config.parent().unwrap(); + let ci_llvm_bin = llvm_output.host_llvm_config.parent().unwrap(); if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" { let lld_path = ci_llvm_bin.join(exe("lld", target)); if lld_path.exists() { @@ -1387,14 +1392,17 @@ impl CommandLineStep for Lld { cfg.out_dir(&out_dir) .profile(profile) - .define("LLVM_CMAKE_DIR", llvm_cmake_dir) + .define("LLVM_CMAKE_DIR", llvm_output.llvm_cmake_dir()) .define("LLVM_INCLUDE_TESTS", "OFF"); if !builder.config.is_host_target(target) { // Use the host llvm-tblgen binary. cfg.define( "LLVM_TABLEGEN_EXE", - host_llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION), + llvm_output + .host_llvm_config + .with_file_name("llvm-tblgen") + .with_extension(EXE_EXTENSION), ); } From dba5082046432f8c3bba6cb91cfd4cb1c87d4ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 13:35:53 +0200 Subject: [PATCH 04/10] Remove some uses of `llvm_out` To remove dependency on implicit paths. --- src/bootstrap/src/core/build_steps/compile.rs | 10 +++++----- src/bootstrap/src/core/build_steps/dist.rs | 10 +++++----- src/bootstrap/src/core/build_steps/llvm.rs | 16 ++++++++++------ 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3a47e43feffaa..23cdf5ad9bf7e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1425,13 +1425,13 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_enzyme { cargo.env("LLVM_ENZYME", "1"); } - let llvm::LlvmOutput { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); + let llvm_output = builder.ensure(llvm::Llvm { target }); if builder.config.llvm_offload { builder.ensure(llvm::OmpOffload { target }); cargo.env("LLVM_OFFLOAD", "1"); } - cargo.env("LLVM_CONFIG", &host_llvm_config); + cargo.env("LLVM_CONFIG", &llvm_output.host_llvm_config); // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by @@ -2122,11 +2122,11 @@ impl CommandLineStep for Assemble { trace!("target_compiler.host" = ?target_compiler.host, "LLVM enabled"); let target = target_compiler.host; - let llvm::LlvmOutput { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); + let llvm_output = builder.ensure(llvm::Llvm { target }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { trace!("LLVM tools enabled"); - let host_llvm_bin_dir = command(&host_llvm_config) + let host_llvm_bin_dir = command(&llvm_output.host_llvm_config) .arg("--bindir") .cached() .run_capture_stdout(builder) @@ -2153,7 +2153,7 @@ impl CommandLineStep for Assemble { // relative to its output build directory, and then apply it to the target // LLVM output build directory. let host_llvm_out = builder.llvm_out(builder.host_target); - let target_llvm_out = builder.llvm_out(target); + let target_llvm_out = llvm_output.root_dir(); if let Ok(relative_path) = Path::new(&host_llvm_bin_dir).strip_prefix(host_llvm_out) { diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 17cee4ec76054..09edcd2d17daf 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2678,7 +2678,7 @@ impl CommandLineStep for LlvmTools { builder.require_submodule("src/llvm-project", None); } - builder.ensure(crate::core::build_steps::llvm::Llvm { target }); + let llvm_output = builder.ensure(crate::core::build_steps::llvm::Llvm { target }); let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple); tarball.set_overlay(OverlayKind::Llvm); @@ -2686,7 +2686,7 @@ impl CommandLineStep for LlvmTools { if builder.config.llvm_tools_enabled { // Prepare the image directory - let src_bindir = builder.llvm_out(target).join("bin"); + let src_bindir = llvm_output.root_dir().join("bin"); let dst_bindir = format!("lib/rustlib/{}/bin", target.triple); for tool in tools_to_install(&builder.paths) { let exe = src_bindir.join(exe(tool, target)); @@ -2859,9 +2859,9 @@ impl CommandLineStep for RustDev { // LLVM requires a shared object symlink to exist on some platforms. tarball.permit_symlinks(true); - builder.ensure(crate::core::build_steps::llvm::Llvm { target }); + let llvm_output = builder.ensure(crate::core::build_steps::llvm::Llvm { target }); - let src_bindir = builder.llvm_out(target).join("bin"); + let src_bindir = llvm_output.root_dir().join("bin"); // If updating this, you likely want to change // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users // will not pick up the extra file until LLVM gets bumped. @@ -2893,7 +2893,7 @@ impl CommandLineStep for RustDev { // Copy the include directory as well; needed mostly to build // librustc_llvm properly (e.g., llvm-config.h is in here). But also // just broadly useful to be able to link against the bundled LLVM. - tarball.add_dir(builder.llvm_out(target).join("include"), "include"); + tarball.add_dir(llvm_output.root_dir().join("include"), "include"); // Copy libLLVM.so to the target lib dir as well, so the RPATH like // `$ORIGIN/../lib` can find it. It may also be used as a dependency diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index da857676a58c7..2a0095bd0a9c7 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -32,13 +32,17 @@ pub struct LlvmOutput { /// Path to llvm-config binary. /// NB: This is always the host llvm-config! pub host_llvm_config: PathBuf, - /// Directory containing the built LLVM artifacts. - pub llvm_root_dir: PathBuf, + llvm_root_dir: PathBuf, } impl LlvmOutput { + /// Directory containing the built LLVM artifacts. + pub fn root_dir(&self) -> &Path { + &self.llvm_root_dir + } + /// Path to LLVM cmake directory. - pub fn llvm_cmake_dir(&self) -> PathBuf { + pub fn cmake_dir(&self) -> PathBuf { self.llvm_root_dir.join("lib").join("cmake").join("llvm") } } @@ -1095,7 +1099,7 @@ impl CommandLineStep for OmpOffload { .define("LLVM_INCLUDE_TESTS", "OFF") .define("OFFLOAD_INCLUDE_TESTS", "OFF") .define("LLVM_ROOT", builder.llvm_out(target).join("build")) - .define("LLVM_DIR", llvm_output.llvm_cmake_dir()) + .define("LLVM_DIR", llvm_output.cmake_dir()) .define("LLVM_DEFAULT_TARGET_TRIPLE", omp_target); if let Some(p) = clang_dir.clone() { cfg.define("Clang_DIR", p); @@ -1220,7 +1224,7 @@ impl CommandLineStep for Enzyme { return BuiltEnzyme { enzyme: dylib }; } - let llvm_cmake_dir = llvm_output.llvm_cmake_dir(); + let llvm_cmake_dir = llvm_output.cmake_dir(); if !builder.config.dry_run() && !llvm_cmake_dir.is_dir() { builder.info(&format!( "WARNING: {:?} does not exist, Enzyme build will likely fail", @@ -1392,7 +1396,7 @@ impl CommandLineStep for Lld { cfg.out_dir(&out_dir) .profile(profile) - .define("LLVM_CMAKE_DIR", llvm_output.llvm_cmake_dir()) + .define("LLVM_CMAKE_DIR", llvm_output.cmake_dir()) .define("LLVM_INCLUDE_TESTS", "OFF"); if !builder.config.is_host_target(target) { From 58b9dd4cef1cf1d2d3b7412255587e62a2950a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 14:03:30 +0200 Subject: [PATCH 05/10] Add helper function for computing LLVM CMake profile --- src/bootstrap/src/core/build_steps/llvm.rs | 33 ++++++++-------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 2a0095bd0a9c7..2fcd6480d470b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -329,11 +329,7 @@ impl CommandLineStep for Llvm { let mut cfg = cmake::Config::new(builder.src.join(root)); let mut ldflags = LdFlags::default(); - let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { - (false, _) => "Debug", - (true, false) => "Release", - (true, true) => "RelWithDebInfo", - }; + let profile = get_llvm_profile(&builder.config); // NOTE: remember to also update `bootstrap.example.toml` when changing the // defaults! @@ -644,6 +640,14 @@ pub fn get_llvm_version_major(builder: &Builder<'_>, llvm_config: &Path) -> u8 { major_str.parse().unwrap() } +fn get_llvm_profile(config: &Config) -> &'static str { + match (config.llvm_optimize, config.llvm_release_debuginfo) { + (false, _) => "Debug", + (true, false) => "Release", + (true, true) => "RelWithDebInfo", + } +} + fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { if builder.config.dry_run() { return; @@ -1082,12 +1086,7 @@ impl CommandLineStep for OmpOffload { // Re-use the same flags as llvm to control the level of debug information // generated for offload. - let profile = - match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { - (false, _) => "Debug", - (true, false) => "Release", - (true, true) => "RelWithDebInfo", - }; + let profile = get_llvm_profile(&builder.config); trace!(?profile); // FIXME(offload): Once we move from OMP to Offload (Ol) APIs, we should drop the openmp @@ -1258,11 +1257,7 @@ impl CommandLineStep for Enzyme { // Re-use the same flags as llvm to control the level of debug information // generated by Enzyme. // FIXME(ZuseZ4): Find a nicer way to use Enzyme Debug builds. - let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { - (false, _) => "Debug", - (true, false) => "Release", - (true, true) => "RelWithDebInfo", - }; + let profile = get_llvm_profile(&builder.config); trace!(?profile); cfg.out_dir(&out_dir) @@ -1388,11 +1383,7 @@ impl CommandLineStep for Lld { // Re-use the same flags as llvm to control the level of debug information // generated for lld. - let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { - (false, _) => "Debug", - (true, false) => "Release", - (true, true) => "RelWithDebInfo", - }; + let profile = get_llvm_profile(&builder.config); cfg.out_dir(&out_dir) .profile(profile) From c4e0a6120df9f75865c4179b86e4753873f8785d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 14:22:32 +0200 Subject: [PATCH 06/10] Remove unused `root` field of the `Meta` LLVM struct --- src/bootstrap/src/core/build_steps/llvm.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 2fcd6480d470b..64f5709456c5e 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -51,7 +51,6 @@ pub struct Meta { stamp: BuildStamp, res: LlvmOutput, out_dir: PathBuf, - root: String, } pub enum LlvmBuildStatus { @@ -153,7 +152,6 @@ pub fn prebuilt_llvm_config( builder.config.update_submodule("src/llvm-project"); } - let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); let build_llvm_config = if let Some(build_llvm_config) = builder @@ -196,7 +194,7 @@ pub fn prebuilt_llvm_config( return LlvmBuildStatus::AlreadyBuilt(res); } - LlvmBuildStatus::ShouldBuild(Meta { stamp, res, out_dir, root: root.into() }) + LlvmBuildStatus::ShouldBuild(Meta { stamp, res, out_dir }) } /// Paths whose changes invalidate LLVM downloads. @@ -311,7 +309,7 @@ impl CommandLineStep for Llvm { }; // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again. - let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target, true) { + let Meta { stamp, res, out_dir } = match prebuilt_llvm_config(builder, target, true) { LlvmBuildStatus::AlreadyBuilt(p) => return p, LlvmBuildStatus::ShouldBuild(m) => m, }; @@ -326,7 +324,7 @@ impl CommandLineStep for Llvm { t!(fs::create_dir_all(&out_dir)); // https://llvm.org/docs/CMake.html - let mut cfg = cmake::Config::new(builder.src.join(root)); + let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/llvm")); let mut ldflags = LdFlags::default(); let profile = get_llvm_profile(&builder.config); From c4c4d395c8b5b84e0a8258d0ba650db43003ff2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 14:24:36 +0200 Subject: [PATCH 07/10] Remove unused `out_dir` field and rename `Meta` to `LlvmBuildInfo` --- src/bootstrap/src/core/build_steps/llvm.rs | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 64f5709456c5e..64b87a03684ab 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -47,15 +47,14 @@ impl LlvmOutput { } } -pub struct Meta { +pub struct LlvmBuildInfo { stamp: BuildStamp, - res: LlvmOutput, - out_dir: PathBuf, + output: LlvmOutput, } pub enum LlvmBuildStatus { AlreadyBuilt(LlvmOutput), - ShouldBuild(Meta), + ShouldBuild(LlvmBuildInfo), } impl LlvmBuildStatus { @@ -70,7 +69,7 @@ impl LlvmBuildStatus { pub fn llvm_result(&self) -> &LlvmOutput { match self { LlvmBuildStatus::AlreadyBuilt(res) => res, - LlvmBuildStatus::ShouldBuild(meta) => &meta.res, + LlvmBuildStatus::ShouldBuild(meta) => &meta.output, } } } @@ -194,7 +193,7 @@ pub fn prebuilt_llvm_config( return LlvmBuildStatus::AlreadyBuilt(res); } - LlvmBuildStatus::ShouldBuild(Meta { stamp, res, out_dir }) + LlvmBuildStatus::ShouldBuild(LlvmBuildInfo { stamp, output: res }) } /// Paths whose changes invalidate LLVM downloads. @@ -309,7 +308,7 @@ impl CommandLineStep for Llvm { }; // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again. - let Meta { stamp, res, out_dir } = match prebuilt_llvm_config(builder, target, true) { + let LlvmBuildInfo { stamp, output } = match prebuilt_llvm_config(builder, target, true) { LlvmBuildStatus::AlreadyBuilt(p) => return p, LlvmBuildStatus::ShouldBuild(m) => m, }; @@ -321,7 +320,7 @@ impl CommandLineStep for Llvm { let _guard = builder.msg_unstaged(Kind::Build, "LLVM", target); t!(stamp.remove()); let _time = helpers::timeit(builder); - t!(fs::create_dir_all(&out_dir)); + t!(fs::create_dir_all(&output.root_dir())); // https://llvm.org/docs/CMake.html let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/llvm")); @@ -349,7 +348,7 @@ impl CommandLineStep for Llvm { let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" }; let enable_warnings = if builder.config.llvm_enable_warnings { "ON" } else { "OFF" }; - cfg.out_dir(&out_dir) + cfg.out_dir(&output.root_dir()) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF") @@ -562,14 +561,14 @@ impl CommandLineStep for Llvm { } if builder.config.dry_run() { - return res; + return output; } cfg.build(); // Helper to find the name of LLVM's shared library on darwin and linux. let find_llvm_lib_name = |extension| { - let major = get_llvm_version_major(builder, &res.host_llvm_config); + let major = get_llvm_version_major(builder, &output.host_llvm_config); match &llvm_version_suffix { Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"), None => format!("libLLVM-{major}.{extension}"), @@ -582,7 +581,7 @@ impl CommandLineStep for Llvm { // link to make llvm-config happy. if builder.llvm_link_shared() && target.contains("apple-darwin") { let lib_name = find_llvm_lib_name("dylib"); - let lib_llvm = out_dir.join("build").join("lib").join(lib_name); + let lib_llvm = output.root_dir().join("build").join("lib").join(lib_name); if !lib_llvm.exists() { t!(builder.symlink_file("libLLVM.dylib", &lib_llvm)); } @@ -603,18 +602,18 @@ impl CommandLineStep for Llvm { crate::core::build_steps::compile::strip_debug( builder, target, - &out_dir.join("lib").join(&lib_name), + &output.root_dir().join("lib").join(&lib_name), ); crate::core::build_steps::compile::strip_debug( builder, target, - &out_dir.join("build").join("lib").join(&lib_name), + &output.root_dir().join("build").join("lib").join(&lib_name), ); } t!(stamp.write()); - res + output } fn metadata(&self) -> Option { From 07b88f2f50135aba5f6ce27bf8efdd25c7288edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 14:31:10 +0200 Subject: [PATCH 08/10] Remove the `builder::llvm_filecheck` function And replace it with an explicit `FileCheck` step --- src/bootstrap/src/core/build_steps/dist.rs | 3 +- src/bootstrap/src/core/build_steps/llvm.rs | 61 +++++++++++++++++++++- src/bootstrap/src/core/build_steps/test.rs | 4 +- src/bootstrap/src/core/sanity.rs | 11 ---- src/bootstrap/src/lib.rs | 44 ---------------- 5 files changed, 65 insertions(+), 58 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 09edcd2d17daf..abe6100c4e3fc 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2888,7 +2888,8 @@ impl CommandLineStep for RustDev { } } - tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable); + let filecheck = builder.ensure(llvm::FileCheck { target }); + tarball.add_file(filecheck, "bin", FileType::Executable); // Copy the include directory as well; needed mostly to build // librustc_llvm properly (e.g., llvm-config.h is in here). But also diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 64b87a03684ab..fa069c1d9e3c4 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -17,7 +17,7 @@ use std::{env, fs}; use build_helper::git::PathFreshness; use crate::core::build_steps::llvm; -use crate::core::builder::{Builder, CommandLineStep, RunConfig, ShouldRun, StepMetadata}; +use crate::core::builder::{Builder, CommandLineStep, RunConfig, ShouldRun, Step, StepMetadata}; use crate::core::config::{Config, LlvmPgoGenerationMode, TargetSelection}; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; use crate::utils::exec::command; @@ -1849,3 +1849,62 @@ impl CommandLineStep for Libunwind { out_dir } } + +/// Returns the path to `FileCheck` LLVM binary for the specified target. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct FileCheck { + pub target: TargetSelection, +} + +impl Step for FileCheck { + type Output = PathBuf; + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let target_config = builder.config.target_config.get(&self.target); + + // The target configured filecheck, prefer it + if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) { + return s.clone(); + }; + + // There is a LLVM config set, take filecheck from it + // Note: because `download-ci-llvm` currently overrides `llvm-config`, when the LLVM is + // downloaded, we go through this branch. Ideally, this should be changed so that + // `download-ci-llvm` doesn't override the config. + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + let llvm_bindir = command(s).arg("--bindir").run_capture_stdout(builder).stdout(); + let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", self.target)); + let filecheck = if filecheck.exists() { + filecheck + } else { + // On Fedora the system LLVM installs FileCheck in the + // llvm subdirectory of the libdir. + let llvm_libdir = command(s).arg("--libdir").run_capture_stdout(builder).stdout(); + let lib_filecheck = + Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", self.target)); + if lib_filecheck.exists() { + lib_filecheck + } else { + // Return the most normal file name, even though + // it doesn't exist, so that any error message + // refers to that. + filecheck + } + }; + return filecheck; + } + // We have to take the filecheck from the built LLVM + let llvm_output = builder.ensure(Llvm { target: self.target }); + + let base = llvm_output.root_dir().join("build"); + // FIXME: this should ideally be encoded directly in `LlvmOutput`, rather than use computing + // the correct directory here... + let base = if !builder.ninja() && self.target.is_msvc() { + let profile = get_llvm_profile(&builder.config); + base.join(profile) + } else { + base + }; + base.join("bin").join(exe("FileCheck", self.target)) + } +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 2ebca2e77eefc..b71bbe5a0a9d9 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2352,7 +2352,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--mode").arg(mode.as_str()); cmd.arg("--target").arg(target.rustc_target_arg()); cmd.arg("--host").arg(&*test_compiler.host.triple); - cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target)); + + let filecheck = builder.ensure(llvm::FileCheck { target: builder.config.host_target }); + cmd.arg("--llvm-filecheck").arg(filecheck); if let Some(codegen_backend) = builder.config.cmd.test_codegen_backend() { if !builder diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 400d0715a4738..84165b08715af 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -309,17 +309,6 @@ than building it. if !skip_tools_checks { for host in &build.hosts { cmd_finder.must_have(build.cxx(*host).unwrap()); - - if build.config.llvm_enabled(*host) { - // Externally configured LLVM requires FileCheck to exist - let filecheck = build.llvm_filecheck(build.host_target); - if !filecheck.starts_with(&build.out) - && !filecheck.exists() - && build.config.codegen_tests - { - panic!("FileCheck executable {filecheck:?} does not exist"); - } - } } } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7d119247b3bac..9d54fac30509e 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1020,50 +1020,6 @@ impl Build { if self.config.vendor { Some(self.src.join(VENDOR_DIR)) } else { None } } - /// Returns the path to `FileCheck` binary for the specified target - fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf { - let target_config = self.config.target_config.get(&target); - if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) { - s.to_path_buf() - } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - let llvm_bindir = command(s).arg("--bindir").run_capture_stdout(self).stdout(); - let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)); - if filecheck.exists() { - filecheck - } else { - // On Fedora the system LLVM installs FileCheck in the - // llvm subdirectory of the libdir. - let llvm_libdir = command(s).arg("--libdir").run_capture_stdout(self).stdout(); - let lib_filecheck = - Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target)); - if lib_filecheck.exists() { - lib_filecheck - } else { - // Return the most normal file name, even though - // it doesn't exist, so that any error message - // refers to that. - filecheck - } - } - } else { - let base = self.llvm_out(target).join("build"); - let base = if !self.ninja() && target.is_msvc() { - if self.config.llvm_optimize { - if self.config.llvm_release_debuginfo { - base.join("RelWithDebInfo") - } else { - base.join("Release") - } - } else { - base.join("Debug") - } - } else { - base - }; - base.join("bin").join(exe("FileCheck", target)) - } - } - /// Directory for libraries built from C/C++ code and shared between stages. fn native_dir(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("native") From 3271e3dd43ee1d98798fabb4071d3c48b9401f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 14:52:20 +0200 Subject: [PATCH 09/10] Remove `lld_out`, `enzyme_out` and `offload_out` functions To avoid someone depending on implicit paths. Instead, the step should be executed and the path should be taken from its output. --- src/bootstrap/src/core/build_steps/llvm.rs | 6 +++--- src/bootstrap/src/lib.rs | 13 +------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index fa069c1d9e3c4..47003b07b386d 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1006,7 +1006,7 @@ impl CommandLineStep for OmpOffload { // Running cmake twice in the same folder is known to cause issues, like deleting existing // binaries. We therefore write our offload artifacts into it's own folder, instead of // using the llvm build dir. - let out_dir = builder.offload_out(target); + let out_dir = builder.out.join(self.target.triple).join("offload"); let mut files = vec![]; let lib_ext = std::env::consts::DLL_EXTENSION; @@ -1194,7 +1194,7 @@ impl CommandLineStep for Enzyme { ) }); - let out_dir = builder.enzyme_out(target); + let out_dir = builder.out.join(self.target.triple).join("enzyme"); let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash); let llvm_version_major = @@ -1322,7 +1322,7 @@ impl CommandLineStep for Lld { } } - let out_dir = builder.lld_out(target); + let out_dir = builder.out.join(target).join("lld"); let lld_stamp = BuildStamp::new(&out_dir).with_prefix("lld"); if lld_stamp.path().exists() { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 9d54fac30509e..14d459388f306 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -56,6 +56,7 @@ pub use utils::helpers::{PanicTracker, symlink_dir}; #[cfg(feature = "tracing")] pub use utils::tracing::setup_tracing; +use crate::core::build_steps::llvm; use crate::core::build_steps::vendor::VENDOR_DIR; const LLVM_TOOLS: &[&str] = &[ @@ -979,18 +980,6 @@ impl Build { } } - fn enzyme_out(&self, target: TargetSelection) -> PathBuf { - self.out.join(&*target.triple).join("enzyme") - } - - fn offload_out(&self, target: TargetSelection) -> PathBuf { - self.out.join(&*target.triple).join("offload") - } - - fn lld_out(&self, target: TargetSelection) -> PathBuf { - self.out.join(target).join("lld") - } - /// Output directory for all documentation for a target fn doc_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("doc") From d29b734363e147ea56afc267784d5458e0c2c4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 6 Aug 2026 16:46:32 +0200 Subject: [PATCH 10/10] Stop overwriting `llvm_filecheck` in config parsing when `download-ci-llvm` is enabled Note: this commit removed reading `FileCheck` from `/build//bin`, and instead reads it from `/bin` directly. It should still work with MSVC and without Ninja. --- src/bootstrap/src/core/build_steps/llvm.rs | 19 +++++-------------- src/bootstrap/src/core/config/config.rs | 2 +- src/bootstrap/src/lib.rs | 1 - 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 47003b07b386d..2c669f312ddf4 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -37,6 +37,7 @@ pub struct LlvmOutput { impl LlvmOutput { /// Directory containing the built LLVM artifacts. + /// Contains `bin`/`lib` directories. pub fn root_dir(&self) -> &Path { &self.llvm_root_dir } @@ -320,7 +321,7 @@ impl CommandLineStep for Llvm { let _guard = builder.msg_unstaged(Kind::Build, "LLVM", target); t!(stamp.remove()); let _time = helpers::timeit(builder); - t!(fs::create_dir_all(&output.root_dir())); + t!(fs::create_dir_all(output.root_dir())); // https://llvm.org/docs/CMake.html let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/llvm")); @@ -348,7 +349,7 @@ impl CommandLineStep for Llvm { let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" }; let enable_warnings = if builder.config.llvm_enable_warnings { "ON" } else { "OFF" }; - cfg.out_dir(&output.root_dir()) + cfg.out_dir(output.root_dir()) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF") @@ -1893,18 +1894,8 @@ impl Step for FileCheck { }; return filecheck; } - // We have to take the filecheck from the built LLVM + // Here we take the filecheck from LLVM directly let llvm_output = builder.ensure(Llvm { target: self.target }); - - let base = llvm_output.root_dir().join("build"); - // FIXME: this should ideally be encoded directly in `LlvmOutput`, rather than use computing - // the correct directory here... - let base = if !builder.ninja() && self.target.is_msvc() { - let profile = get_llvm_profile(&builder.config); - base.join(profile) - } else { - base - }; - base.join("bin").join(exe("FileCheck", self.target)) + llvm_output.root_dir().join("bin").join(exe("FileCheck", self.target)) } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d9ca3632eb8f6..7a3b0adf8e93f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1118,8 +1118,8 @@ impl Config { target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple)); check_ci_llvm!(build_target.llvm_config); check_ci_llvm!(build_target.llvm_filecheck); + // FIXME: Do not overwrite the LLVM config here build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", host_target))); - build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", host_target))); } for (target, linker_override) in default_linux_linker_overrides() { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 14d459388f306..54e04ca43c189 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -56,7 +56,6 @@ pub use utils::helpers::{PanicTracker, symlink_dir}; #[cfg(feature = "tracing")] pub use utils::tracing::setup_tracing; -use crate::core::build_steps::llvm; use crate::core::build_steps::vendor::VENDOR_DIR; const LLVM_TOOLS: &[&str] = &[