Change:
I tried this code: I expected to see this happen: bootstrap rebuilds LLVM, since it's changed. Instead, this happened: bootstrap does nothing. The problem is that we 're using a stamp file and assume that if the commit hasn't changed then none of the files have changed either: I am not sure why we do that? Are we assuming that CMake rebuilds too frequently? That seems like something we should fix upstream ... cc I think this would make your lives easier. HEAD is branched from .
hmm, looks related. I am not sure why that would be the correct behavior? If CFLAGS has changed we should rebuild; I would expect distros to make sure CFLAGS matches between invocations of bootstrap.
The stamp checking for the "normal" case, when not building from a source tarball, has been there since the initial commit of bootstrap:
Are you trying to address the git "dirty" case, or the non-git case, or both?
Both, but primarily the git case since that's how most people are developing I think.
Ok, I agree the git case is where folks may actually be making changes, and I still think it's ok not to automatically "notice" changes in the non-git case. LLVM is big enough that checking for dirty git may not be cheap though. On my Linux system with NVME, it takes ~0.5s after dropping page caches, and ~0.15s cached. On systems with slower disks, virus scanners, etc., it may be a lot worse.
Yeah, I don't think this is particularly important. The main issue with making changes to LLVM is , which prevents the change from being picked up even if you do commit it.

Discussion:
use crate::core::config::{Config, TargetSelection}; use crate::utils::channel; use crate::utils::helpers::{self, exe, get_clang_cl_resource_dir, output, t, up_to_date}; <del> use crate::{CLang, GitRepo, Kind}; </del> <ins> use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; </ins> use build_helper::ci::CiEnv; use build_helper::git::get_git_merge_base;

let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir }; <ins> let smart_stamp_hash = generate_smart_stamp_hash( &builder.config.src.join("src/llvm-project"), &builder.in_tree_llvm_info.sha().unwrap_or_default(), ); </ins> let stamp = out_dir.join("llvm-finished-building"); <del> let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); </del> <ins> let stamp = HashStamp::new(stamp, Some(&smart_stamp_hash)); </ins> if stamp.is_done() { if stamp.hash.is_none() {

use build_helper::util::fail; use filetime::FileTime; use once_cell::sync::OnceCell; <ins> use sha2::digest::Digest; </ins> use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::channel::GitInfo;

.cloned() .collect() } <ins> /// Computes a hash representing the state of a repository/submodule and additional input. /// /// It uses `git diff` for the actual changes, and `git status` for including the untracked /// files in the specified directory. The additional input is also incorporated into the /// computation of the hash. /// /// # Parameters /// /// - `dir`: A reference to the directory path of the target repository/submodule. /// - `additional_input`: An additional input to be included in the hash. /// /// # Panics /// /// In case of errors during `git` command execution (e.g., in tarball sources), default values /// are used to prevent panics. pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { let diff = Command::new("git") .current_dir(dir) .arg("diff") .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); let status = Command::new("git") .current_dir(dir) .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); let mut hasher = sha2::Sha256::new(); hasher.update(diff); hasher.update(status); hasher.update(additional_input); hex::encode(hasher.finalize().as_slice()) } </ins>