Skip to content

Commit

Permalink
Add support for caching target json specs for Rust compilation.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinFinck committed Oct 7, 2024
1 parent 2932b22 commit c3d0777
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 7 deletions.
1 change: 0 additions & 1 deletion docs/Rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
47 changes: 41 additions & 6 deletions src/compiler/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PathBuf>,
}

/// A struct on which to hang a `Compilation` impl.
Expand Down Expand Up @@ -1060,6 +1062,7 @@ fn parse_arguments(arguments: &[OsString], cwd: &Path) -> CompilerArguments<Pars
let mut color_mode = ColorMode::Auto;
let mut has_json = false;
let mut profile = false;
let mut target_json = None;

for arg in ArgsIter::new(arguments.iter().cloned(), &ARGS[..]) {
let arg = try_or_cannot_cache!(arg, "argument parse");
Expand Down Expand Up @@ -1145,7 +1148,8 @@ fn parse_arguments(arguments: &[OsString], cwd: &Path) -> CompilerArguments<Pars
}
Some(PassThrough(_)) => (),
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 => {
Expand Down Expand Up @@ -1271,6 +1275,7 @@ fn parse_arguments(arguments: &[OsString], cwd: &Path) -> CompilerArguments<Pars
emit,
color_mode,
has_json,
target_json,
})
}

Expand Down Expand Up @@ -1312,6 +1317,7 @@ where
emit,
has_json,
gcno,
target_json,
..
},
} = *self;
Expand Down Expand Up @@ -1367,11 +1373,33 @@ where
let abs_staticlibs = staticlibs.iter().map(|s| cwd.join(s)).collect::<Vec<_>>();
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:
Expand All @@ -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.
Expand All @@ -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();
Expand All @@ -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<OsString> to calculate outputs.
Expand Down Expand Up @@ -3214,6 +3248,7 @@ proc_macro false
color_mode: ColorMode::Auto,
has_json: false,
gcno: None,
target_json: None,
},
});
let creator = new_creator();
Expand Down

0 comments on commit c3d0777

Please sign in to comment.