Skip to content

Commit edf0ac5

Browse files
authored
Parse env-deps from dep-info (#1107)
* Refactor sccache cargo test - Improve cleanup by using Result instead of panicking, to ensure that the temporary folder gets cleaned up. Previously, when a test failed, no clean up would happen. Now the cleanup happens, unless there is an unexpected panic somewhere in the intergration test code. - this commit aims to make it easier to add new tests Split sccache cargo tests To make it clearer what is failing, split the cargo test into multiple tests. Since Sccache can't be invoked in parallel, we use the `serial_test` to serialize testing,otherwise cargo by default would start them in parallel. The logger is now also lazily initialized, so the first test to run will initialize it. It now writes a linebreak, because otherwise the output is hard to read with `RUST_LOG=debug cargo test --test sccache_cargo -- --nocapture`. We catch panics (which are not intended by the tests ) to ensure that the temporary directory for the test gets cleaned up. Signed-off-by: Jonathan Schwender <[email protected]> Remove panic=abort from CI coverage test I suspect the commandline was just taken like that from the example here: https://doc.rust-lang.org/stable/unstable-book/compiler-flags/profile.html However, there seems to be no reason to actually abort, since we don't have a custom test harness or anything. Since we want to catch panics, so we can correctly clean up, we need panic=unwind. Signed-off-by: Jonathan Schwender <[email protected]> * Parse env_deps from dep-info This will trigger rebuilds if environment variables changed that the rust code depended on with env!. On the Rust side this requires at least Rust 1.46, otherwise there will be no env-dep info in the dep-info file. In that case we cannot detect the dependency on the env-value, and behaviour is unchanged compared to the current sccache behaviour. With recent Rust versions however, we can trigger a rebuild if a variable that is referenced via env! or option_env! is changed. Other env variables like `CARGO_*` or `RUSTFLAGS` which may affect the compilation are not listed in the dep-info file, so they have to be blanket added (as is currently already the case). Signed-off-by: Jonathan Schwender <[email protected]> * Add test for cargo env_deps The previous commit added support for parsing "env_dep" information from dep_info files. This commit adds a test for changing an environment variable, that is referenced in rust code via env!, and asserts that sccache rebuilds and the rust code uses the new value of the changed environment variable. Signed-off-by: Jonathan Schwender <[email protected]>
1 parent 586c308 commit edf0ac5

File tree

9 files changed

+357
-130
lines changed

9 files changed

+357
-130
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ jobs:
200200
env:
201201
CARGO_INCREMENTAL: '0'
202202
RUSTC_WRAPPER: ''
203-
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
203+
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off'
204204

205205
- name: Generate coverage data (via `grcov`)
206206
id: coverage

Cargo.lock

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ chrono = "0.4"
100100
itertools = "0.10"
101101
predicates = "=2.1.1"
102102
thirtyfour_sync = "0.27"
103+
once_cell = "1.9"
104+
serial_test = "0.5"
103105

104106
[target.'cfg(unix)'.dependencies]
105107
daemonize = "0.4"

docs/Rust.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sccache includes support for caching Rust compilation. This includes many caveat
55
* `--out-dir` is required.
66
* `-o file` is not supported.
77
* Compilation from stdin is not supported, a source file must be provided.
8-
* Values from `env!` will not be tracked in caching.
8+
* Values from `env!` require Rust >= 1.46 to be tracked in caching.
99
* Procedural macros that read files from the filesystem may not be cached properly
1010
* Target specs aren't hashed (e.g. custom target specs)
1111

src/compiler/rust.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,16 @@ lazy_static! {
197197
/// Version number for cache key.
198198
const CACHE_VERSION: &[u8] = b"6";
199199

200-
/// Get absolute paths for all source files listed in rustc's dep-info output.
201-
async fn get_source_files<T>(
200+
/// Get absolute paths for all source files and env-deps listed in rustc's dep-info output.
201+
async fn get_source_files_and_env_deps<T>(
202202
creator: &T,
203203
crate_name: &str,
204204
executable: &Path,
205205
arguments: &[OsString],
206206
cwd: &Path,
207207
env_vars: &[(OsString, OsString)],
208208
pool: &tokio::runtime::Handle,
209-
) -> Result<Vec<PathBuf>>
209+
) -> Result<(Vec<PathBuf>, Vec<(OsString, OsString)>)>
210210
where
211211
T: CommandCreatorSync,
212212
{
@@ -238,30 +238,31 @@ where
238238
})
239239
.await?;
240240

241-
parsed.map(move |files| {
241+
parsed.map(move |(files, env_deps)| {
242242
trace!(
243-
"[{}]: got {} source files from dep-info in {}",
243+
"[{}]: got {} source files and {} env-deps from dep-info in {}",
244244
crate_name,
245245
files.len(),
246+
env_deps.len(),
246247
fmt_duration_as_secs(&start.elapsed())
247248
);
248249
// Just to make sure we capture temp_dir.
249250
drop(temp_dir);
250-
files
251+
(files, env_deps)
251252
})
252253
}
253254

254255
/// Parse dependency info from `file` and return a Vec of files mentioned.
255256
/// Treat paths as relative to `cwd`.
256-
fn parse_dep_file<T, U>(file: T, cwd: U) -> Result<Vec<PathBuf>>
257+
fn parse_dep_file<T, U>(file: T, cwd: U) -> Result<(Vec<PathBuf>, Vec<(OsString, OsString)>)>
257258
where
258259
T: AsRef<Path>,
259260
U: AsRef<Path>,
260261
{
261262
let mut f = fs::File::open(file)?;
262263
let mut deps = String::new();
263264
f.read_to_string(&mut deps)?;
264-
Ok(parse_dep_info(&deps, cwd))
265+
Ok((parse_dep_info(&deps, cwd), parse_env_dep_info(&deps)))
265266
}
266267

267268
fn parse_dep_info<T>(dep_info: &str, cwd: T) -> Vec<PathBuf>
@@ -315,6 +316,20 @@ where
315316
deps
316317
}
317318

319+
fn parse_env_dep_info(dep_info: &str) -> Vec<(OsString, OsString)> {
320+
let mut env_deps = Vec::new();
321+
for line in dep_info.lines() {
322+
if let Some(env_dep) = line.strip_prefix("# env-dep:") {
323+
let mut split = env_dep.splitn(2, '=');
324+
match (split.next(), split.next()) {
325+
(Some(var), Some(val)) => env_deps.push((var.into(), val.into())),
326+
_ => env_deps.push((env_dep.into(), "".into())),
327+
}
328+
}
329+
}
330+
env_deps
331+
}
332+
318333
/// Run `rustc --print file-names` to get the outputs of compilation.
319334
async fn get_compiler_outputs<T>(
320335
creator: &T,
@@ -1300,8 +1315,8 @@ where
13001315
.collect::<Vec<_>>();
13011316
// Find all the source files and hash them
13021317
let source_hashes_pool = pool.clone();
1303-
let source_files_and_hashes = async {
1304-
let source_files = get_source_files(
1318+
let source_files_and_hashes_and_env_deps = async {
1319+
let (source_files, env_deps) = get_source_files_and_env_deps(
13051320
creator,
13061321
&crate_name,
13071322
&executable,
@@ -1312,7 +1327,7 @@ where
13121327
)
13131328
.await?;
13141329
let source_hashes = hash_all(&source_files, &source_hashes_pool).await?;
1315-
Ok((source_files, source_hashes))
1330+
Ok((source_files, source_hashes, env_deps))
13161331
};
13171332

13181333
// Hash the contents of the externs listed on the commandline.
@@ -1324,8 +1339,11 @@ where
13241339
let abs_staticlibs = staticlibs.iter().map(|s| cwd.join(s)).collect::<Vec<_>>();
13251340
let staticlib_hashes = hash_all(&abs_staticlibs, pool);
13261341

1327-
let ((source_files, source_hashes), extern_hashes, staticlib_hashes) =
1328-
futures::try_join!(source_files_and_hashes, extern_hashes, staticlib_hashes)?;
1342+
let ((source_files, source_hashes, mut env_deps), extern_hashes, staticlib_hashes) = futures::try_join!(
1343+
source_files_and_hashes_and_env_deps,
1344+
extern_hashes,
1345+
staticlib_hashes
1346+
)?;
13291347
// If you change any of the inputs to the hash, you should change `CACHE_VERSION`.
13301348
let mut m = Digest::new();
13311349
// Hash inputs:
@@ -1375,12 +1393,15 @@ where
13751393
{
13761394
m.update(h.as_bytes());
13771395
}
1378-
// 7. Environment variables. Ideally we'd use anything referenced
1379-
// via env! in the program, but we don't have a way to determine that
1380-
// currently, and hashing all environment variables is too much, so
1381-
// we'll just hash the CARGO_ env vars and hope that's sufficient.
1382-
// Upstream Rust issue tracking getting information about env! usage:
1383-
// https://github.com/rust-lang/rust/issues/40364
1396+
// 7. Environment variables: Hash all environment variables listed in the rustc dep-info
1397+
// output. Additionally also has all environment variables starting with `CARGO_`,
1398+
// since those are not listed in dep-info but affect cacheability.
1399+
env_deps.sort();
1400+
for &(ref var, ref val) in env_deps.iter() {
1401+
var.hash(&mut HashToDigest { digest: &mut m });
1402+
m.update(b"=");
1403+
val.hash(&mut HashToDigest { digest: &mut m });
1404+
}
13841405
let mut env_vars: Vec<_> = env_vars
13851406
.iter()
13861407
// Filter out RUSTC_COLOR since we control color usage with command line flags.

0 commit comments

Comments
 (0)