diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c0018c613ba5c..a878c730706cb 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -765,9 +765,17 @@ impl<'a> Builder<'a> { } // Set a flag for `check`/`clippy`/`fix`, so that certain build - // scripts can do less work (e.g. not building/requiring LLVM). + // scripts can do less work (i.e. not building/requiring LLVM). if cmd == "check" || cmd == "clippy" || cmd == "fix" { - cargo.env("RUST_CHECK", "1"); + // If we've not yet built LLVM, or it's stale, then bust + // the librustc_llvm cache. That will always work, even though it + // may mean that on the next non-check build we'll need to rebuild + // librustc_llvm. But if LLVM is stale, that'll be a tiny amount + // of work comparitively, and we'd likely need to rebuild it anyway, + // so that's okay. + if crate::native::prebuilt_llvm_config(self, target).is_err() { + cargo.env("RUST_CHECK", "1"); + } } let stage = if compiler.stage == 0 && self.local_rebuild { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0a193d91244a5..0c754936bc242 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -517,9 +517,13 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne // librustc_llvm and librustc_codegen_llvm. // // Note that this is disabled if LLVM itself is disabled or we're in a check - // build, where if we're in a check build there's no need to build all of - // LLVM and such. - if builder.config.llvm_enabled() && builder.kind != Kind::Check { + // build. If we are in a check build we still go ahead here presuming we've + // detected that LLVM is alreay built and good to go which helps prevent + // busting caches (e.g. like #71152). + if builder.config.llvm_enabled() + && (builder.kind != Kind::Check + || crate::native::prebuilt_llvm_config(builder, target).is_ok()) + { if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 0f39e33c5f46a..bcd79a49eced1 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -24,6 +24,72 @@ use crate::util::{self, exe}; use crate::GitRepo; use build_helper::up_to_date; +pub struct Meta { + stamp: HashStamp, + build_llvm_config: PathBuf, + out_dir: PathBuf, + root: String, +} + +// This returns whether we've already previously built LLVM. +// +// It's used to avoid busting caches during x.py check -- if we've already built +// LLVM, it's fine for us to not try to avoid doing so. +// +// This will return the llvm-config if it can get it (but it will not build it +// if not). +pub fn prebuilt_llvm_config( + builder: &Builder<'_>, + target: Interned, +) -> Result { + // If we're using a custom LLVM bail out here, but we can only use a + // custom LLVM for the build triple. + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref s) = config.llvm_config { + check_llvm_version(builder, s); + return Ok(s.to_path_buf()); + } + } + + let root = "src/llvm-project/llvm"; + let out_dir = builder.llvm_out(target); + let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); + if !builder.config.build.contains("msvc") || builder.config.ninja { + llvm_config_ret_dir.push("build"); + } + llvm_config_ret_dir.push("bin"); + + let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build)); + + let stamp = out_dir.join("llvm-finished-building"); + let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); + + if builder.config.llvm_skip_rebuild && stamp.path.exists() { + builder.info( + "Warning: \ + Using a potentially stale build of LLVM; \ + This may not behave well.", + ); + return Ok(build_llvm_config); + } + + if stamp.is_done() { + if stamp.hash.is_none() { + builder.info( + "Could not determine the LLVM submodule commit hash. \ + Assuming that an LLVM rebuild is not necessary.", + ); + builder.info(&format!( + "To force LLVM to rebuild, remove the file `{}`", + stamp.path.display() + )); + } + return Ok(build_llvm_config); + } + + Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() }) +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Llvm { pub target: Interned, @@ -46,51 +112,11 @@ impl Step for Llvm { fn run(self, builder: &Builder<'_>) -> PathBuf { let target = self.target; - // If we're using a custom LLVM bail out here, but we can only use a - // custom LLVM for the build triple. - if let Some(config) = builder.config.target_config.get(&target) { - if let Some(ref s) = config.llvm_config { - check_llvm_version(builder, s); - return s.to_path_buf(); - } - } - - let root = "src/llvm-project/llvm"; - let out_dir = builder.llvm_out(target); - let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); - if !builder.config.build.contains("msvc") || builder.config.ninja { - llvm_config_ret_dir.push("build"); - } - llvm_config_ret_dir.push("bin"); - - let build_llvm_config = - llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build)); - - let stamp = out_dir.join("llvm-finished-building"); - let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); - - if builder.config.llvm_skip_rebuild && stamp.path.exists() { - builder.info( - "Warning: \ - Using a potentially stale build of LLVM; \ - This may not behave well.", - ); - return build_llvm_config; - } - - if stamp.is_done() { - if stamp.hash.is_none() { - builder.info( - "Could not determine the LLVM submodule commit hash. \ - Assuming that an LLVM rebuild is not necessary.", - ); - builder.info(&format!( - "To force LLVM to rebuild, remove the file `{}`", - stamp.path.display() - )); - } - return build_llvm_config; - } + let Meta { stamp, build_llvm_config, out_dir, root } = + match prebuilt_llvm_config(builder, target) { + Ok(p) => return p, + Err(m) => m, + }; builder.info(&format!("Building LLVM for {}", target)); t!(stamp.remove()); diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index f14fc9fc2eba8..e97fa4345fe7c 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -15,9 +15,9 @@ fn detect_llvm_link() -> (&'static str, &'static str) { } fn main() { + println!("cargo:rerun-if-env-changed=RUST_CHECK"); if env::var_os("RUST_CHECK").is_some() { // If we're just running `check`, there's no need for LLVM to be built. - println!("cargo:rerun-if-env-changed=RUST_CHECK"); return; }