diff --git a/packages/cli/src/build/request.rs b/packages/cli/src/build/request.rs index 3b98f7d068..7b4e1b0f2d 100644 --- a/packages/cli/src/build/request.rs +++ b/packages/cli/src/build/request.rs @@ -3802,7 +3802,7 @@ impl BuildRequest { Ok(()) } - /// update the mtime of the "main" file to bust the fingerprint, forcing rustc to recompile it. + /// Blow away the fingerprint for this package, forcing rustc to recompile it. /// /// This prevents rustc from using the cached version of the binary, which can cause issues /// with our hotpatching setup since it uses linker interception. @@ -3812,13 +3812,29 @@ impl BuildRequest { /// /// This might stop working if/when cargo stabilizes contents-based fingerprinting. fn bust_fingerprint(&self, ctx: &BuildContext) -> Result<()> { - if !matches!(ctx.mode, BuildMode::Thin { .. }) { - std::fs::File::open(&self.crate_target.src_path)?.set_modified(SystemTime::now())?; - - // read and write the file to update the mtime - if cfg!(target_os = "windows") { - let contents = std::fs::read_to_string(&self.crate_target.src_path)?; - _ = std::fs::write(&self.crate_target.src_path, contents); + if matches!(ctx.mode, BuildMode::Fat) { + // `dx` compiles everything with `--target` which ends up with a structure like: + // target///.fingerprint/- + // + // normally you can't rely on this structure (ie with `cargo build`) but the explicit + // target arg guarantees this will work. + let fingerprint_dir = self + .target_dir + .join(self.triple.to_string()) + .join(&self.profile) + .join(".fingerprint"); + + // split at the last `-` used to separate the hash from the name + // This causes to more aggressively bust hashes for all combinations of features + // and fingerprints for this package since we're just ignoring the hash + for entry in std::fs::read_dir(&fingerprint_dir)?.flatten() { + if let Some(fname) = entry.file_name().to_str() { + if let Some((name, _)) = fname.rsplit_once('-') { + if name == self.package().name { + _ = std::fs::remove_dir_all(entry.path()); + } + } + } } } Ok(()) diff --git a/packages/cli/src/rustcwrapper.rs b/packages/cli/src/rustcwrapper.rs index 516bb5dc1d..6f69163009 100644 --- a/packages/cli/src/rustcwrapper.rs +++ b/packages/cli/src/rustcwrapper.rs @@ -54,13 +54,23 @@ pub async fn run_rustc() { link_args: Default::default(), }; - std::fs::create_dir_all(var_file.parent().expect("Failed to get parent dir")) - .expect("Failed to create parent dir"); - std::fs::write( - &var_file, - serde_json::to_string(&rustc_args).expect("Failed to serialize rustc args"), - ) - .expect("Failed to write rustc args to file"); + // Another terrible hack to avoid caching non-sensical args when + // a build is completely fresh (rustc is invoked with --crate-name ___) + if rustc_args + .args + .iter() + .skip_while(|arg| *arg != "--crate-name") + .nth(1) + .is_some_and(|name| name != "___") + { + std::fs::create_dir_all(var_file.parent().expect("Failed to get parent dir")) + .expect("Failed to create parent dir"); + std::fs::write( + &var_file, + serde_json::to_string(&rustc_args).expect("Failed to serialize rustc args"), + ) + .expect("Failed to write rustc args to file"); + } // Run the actual rustc command // We want all stdout/stderr to be inherited, so the running process can see the output