From c3d0777d6bf928fd804ed1f0fda2d546c519031a Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Mon, 7 Oct 2024 13:01:48 +0200 Subject: [PATCH] Add support for caching target json specs for Rust compilation. Fixes #2174 --- docs/Rust.md | 1 - src/compiler/rust.rs | 47 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/docs/Rust.md b/docs/Rust.md index 9b805d7b1..ef266e726 100644 --- a/docs/Rust.md +++ b/docs/Rust.md @@ -7,6 +7,5 @@ sccache includes support for caching Rust compilation. This includes many caveat * Compilation from stdin is not supported, a source file must be provided. * Values from `env!` require Rust >= 1.46 to be tracked in caching. * Procedural macros that read files from the filesystem may not be cached properly -* Target specs aren't hashed (e.g. custom target specs) If you are using Rust 1.18 or later, you can ask cargo to wrap all compilation with sccache by setting `RUSTC_WRAPPER=sccache` in your build environment. diff --git a/src/compiler/rust.rs b/src/compiler/rust.rs index c72fdc51b..d72756e5e 100644 --- a/src/compiler/rust.rs +++ b/src/compiler/rust.rs @@ -168,6 +168,8 @@ pub struct ParsedArguments { color_mode: ColorMode, /// Whether `--json` was passed to this invocation. has_json: bool, + /// A `--target` parameter that specifies a path to a JSON file. + target_json: Option, } /// A struct on which to hang a `Compilation` impl. @@ -1060,6 +1062,7 @@ fn parse_arguments(arguments: &[OsString], cwd: &Path) -> CompilerArguments CompilerArguments (), Some(Target(target)) => match target { - ArgTarget::Path(_) | ArgTarget::Unsure(_) => cannot_cache!("target"), + ArgTarget::Path(json_path) => target_json = Some(json_path.to_owned()), + ArgTarget::Unsure(_) => cannot_cache!("target unsure"), ArgTarget::Name(_) => (), }, None => { @@ -1271,6 +1275,7 @@ fn parse_arguments(arguments: &[OsString], cwd: &Path) -> CompilerArguments>(); let staticlib_hashes = hash_all_archives(&abs_staticlibs, pool); - let ((source_files, source_hashes, mut env_deps), extern_hashes, staticlib_hashes) = futures::try_join!( + // Hash the content of the specified target json file, if any. + let mut target_json_files = Vec::new(); + if let Some(path) = &target_json { + trace!( + "[{}]: hashing target json file {}", + crate_name, + path.display() + ); + let abs_target_json = cwd.join(path); + target_json_files.push(abs_target_json); + } + + let target_json_hash = hash_all(&target_json_files, pool); + + // Perform all hashing operations on the files. + let ( + (source_files, source_hashes, mut env_deps), + extern_hashes, + staticlib_hashes, + target_json_hash, + ) = futures::try_join!( source_files_and_hashes_and_env_deps, extern_hashes, - staticlib_hashes + staticlib_hashes, + target_json_hash )?; + // If you change any of the inputs to the hash, you should change `CACHE_VERSION`. let mut m = Digest::new(); // Hash inputs: @@ -1397,6 +1425,10 @@ where // in those paths (rlibs and static libs used in the compilation) are used as hash // inputs below. .filter(|&(arg, _)| !(arg == "--extern" || arg == "-L" || arg == "--out-dir")) + // We also exclude `--target` if it specifies a path to a .json file. The file content + // is used as hash input below. + // If `--target` specifies a string, it continues to be hashed as part of the arguments. + .filter(|&(arg, _)| target_json.is_none() || arg != "--target") // A few argument types were not passed in a deterministic order // by older versions of cargo: --extern, -L, --cfg. We'll filter the rest of those // out, sort them, and append them to the rest of the arguments. @@ -1414,14 +1446,16 @@ where // 4. The digest of all source files (this includes src file from cmdline). // 5. The digest of all files listed on the commandline (self.externs). // 6. The digest of all static libraries listed on the commandline (self.staticlibs). + // 7. The digest of the content of the target json file specified via `--target` (if any). for h in source_hashes .into_iter() .chain(extern_hashes) .chain(staticlib_hashes) + .chain(target_json_hash) { m.update(h.as_bytes()); } - // 7. Environment variables: Hash all environment variables listed in the rustc dep-info + // 8. Environment variables: Hash all environment variables listed in the rustc dep-info // output. Additionally also has all environment variables starting with `CARGO_`, // since those are not listed in dep-info but affect cacheability. env_deps.sort(); @@ -1446,9 +1480,9 @@ where val.hash(&mut HashToDigest { digest: &mut m }); } } - // 8. The cwd of the compile. This will wind up in the rlib. + // 9. The cwd of the compile. This will wind up in the rlib. cwd.hash(&mut HashToDigest { digest: &mut m }); - // 9. The version of the compiler. + // 10. The version of the compiler. version.hash(&mut HashToDigest { digest: &mut m }); // Turn arguments into a simple Vec to calculate outputs. @@ -3214,6 +3248,7 @@ proc_macro false color_mode: ColorMode::Auto, has_json: false, gcno: None, + target_json: None, }, }); let creator = new_creator();