Skip to content

Commit

Permalink
Detect changes for JSON spec targets.
Browse files Browse the repository at this point in the history
  • Loading branch information
ehuss committed Mar 1, 2021
1 parent ccf781a commit 83487e4
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 96 deletions.
8 changes: 6 additions & 2 deletions src/cargo/core/compiler/build_context/target_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ impl TargetInfo {
kind,
"RUSTFLAGS",
)?;
let extra_fingerprint = kind.fingerprint_hash();
let mut process = rustc.process();
process
.arg("-")
Expand All @@ -163,14 +164,17 @@ impl TargetInfo {
process.arg("--crate-type").arg(crate_type.as_str());
}
let supports_split_debuginfo = rustc
.cached_output(process.clone().arg("-Csplit-debuginfo=packed"))
.cached_output(
process.clone().arg("-Csplit-debuginfo=packed"),
extra_fingerprint,
)
.is_ok();

process.arg("--print=sysroot");
process.arg("--print=cfg");

let (output, error) = rustc
.cached_output(&process)
.cached_output(&process, extra_fingerprint)
.chain_err(|| "failed to run `rustc` to learn about target-specific information")?;

let mut lines = output.lines();
Expand Down
31 changes: 30 additions & 1 deletion src/cargo/core/compiler/compile_kind.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::core::Target;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::interning::InternedString;
use crate::util::Config;
use crate::util::{Config, StableHasher};
use anyhow::bail;
use serde::Serialize;
use std::collections::BTreeSet;
use std::fs;
use std::hash::{Hash, Hasher};
use std::path::Path;

/// Indicator for how a unit is being compiled.
Expand Down Expand Up @@ -78,6 +80,18 @@ impl CompileKind {
};
Ok(vec![kind])
}

/// Hash used for fingerprinting.
///
/// Metadata hashing uses the normal Hash trait, which does not
/// differentiate on `.json` file contents. The fingerprint hash does
/// check the contents.
pub fn fingerprint_hash(&self) -> u64 {
match self {
CompileKind::Host => 0,
CompileKind::Target(target) => target.fingerprint_hash(),
}
}
}

impl serde::ser::Serialize for CompileKind {
Expand Down Expand Up @@ -166,4 +180,19 @@ impl CompileTarget {
&self.name
}
}

/// See [`CompileKind::fingerprint_hash`].
pub fn fingerprint_hash(&self) -> u64 {
let mut hasher = StableHasher::new();
self.name.hash(&mut hasher);
if self.name.ends_with(".json") {
// This may have some performance concerns, since it is called
// fairly often. If that ever seems worth fixing, consider
// embedding this in `CompileTarget`.
if let Ok(contents) = fs::read_to_string(self.name) {
contents.hash(&mut hasher);
}
}
hasher.finish()
}
}
25 changes: 22 additions & 3 deletions src/cargo/core/compiler/fingerprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@
//! `cargo rustc` extra args | ✓ | ✓
//! CompileMode | ✓ | ✓
//! Target Name | ✓ | ✓
//! Target CompileKind (bin/lib/etc.) | ✓ | ✓
//! TargetKind (bin/lib/etc.) | ✓ | ✓
//! Enabled Features | ✓ | ✓
//! Immediate dependency’s hashes | ✓[^1] | ✓
//! Target or Host mode | | ✓
//! CompileKind (host/target) | ✓ | ✓
//! __CARGO_DEFAULT_LIB_METADATA[^4] | | ✓
//! package_id | | ✓
//! authors, description, homepage, repo | ✓ |
Expand Down Expand Up @@ -542,6 +542,9 @@ pub struct Fingerprint {
metadata: u64,
/// Hash of various config settings that change how things are compiled.
config: u64,
/// The rustc target. This is only relevant for `.json` files, otherwise
/// the metadata hash segregates the units.
compile_kind: u64,
/// Description of whether the filesystem status for this unit is up to date
/// or should be considered stale.
#[serde(skip)]
Expand Down Expand Up @@ -780,6 +783,7 @@ impl Fingerprint {
rustflags: Vec::new(),
metadata: 0,
config: 0,
compile_kind: 0,
fs_status: FsStatus::Stale,
outputs: Vec::new(),
}
Expand Down Expand Up @@ -843,6 +847,9 @@ impl Fingerprint {
if self.config != old.config {
bail!("configuration settings have changed")
}
if self.compile_kind != old.compile_kind {
bail!("compile kind (rustc target) changed")
}
let my_local = self.local.lock().unwrap();
let old_local = old.local.lock().unwrap();
if my_local.len() != old_local.len() {
Expand Down Expand Up @@ -1090,12 +1097,22 @@ impl hash::Hash for Fingerprint {
ref local,
metadata,
config,
compile_kind,
ref rustflags,
..
} = *self;
let local = local.lock().unwrap();
(
rustc, features, target, path, profile, &*local, metadata, config, rustflags,
rustc,
features,
target,
path,
profile,
&*local,
metadata,
config,
compile_kind,
rustflags,
)
.hash(h);

Expand Down Expand Up @@ -1318,6 +1335,7 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger
} else {
0
};
let compile_kind = unit.kind.fingerprint_hash();
Ok(Fingerprint {
rustc: util::hash_u64(&cx.bcx.rustc().verbose_version),
target: util::hash_u64(&unit.target),
Expand All @@ -1331,6 +1349,7 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger
memoized_hash: Mutex::new(None),
metadata,
config,
compile_kind,
rustflags: extra_flags,
fs_status: FsStatus::Stale,
outputs,
Expand Down
34 changes: 28 additions & 6 deletions src/cargo/util/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl Rustc {

let mut cmd = util::process(&path);
cmd.arg("-vV");
let verbose_version = cache.cached_output(&cmd)?.0;
let verbose_version = cache.cached_output(&cmd, 0)?.0;

let extract = |field: &str| -> CargoResult<&str> {
verbose_version
Expand Down Expand Up @@ -100,8 +100,25 @@ impl Rustc {
util::process(&self.path)
}

pub fn cached_output(&self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
self.cache.lock().unwrap().cached_output(cmd)
/// Gets the output for the given command.
///
/// This will return the cached value if available, otherwise it will run
/// the command and cache the output.
///
/// `extra_fingerprint` is extra data to include in the cache fingerprint.
/// Use this if there is other information about the environment that may
/// affect the output that is not part of `cmd`.
///
/// Returns a tuple of strings `(stdout, stderr)`.
pub fn cached_output(
&self,
cmd: &ProcessBuilder,
extra_fingerprint: u64,
) -> CargoResult<(String, String)> {
self.cache
.lock()
.unwrap()
.cached_output(cmd, extra_fingerprint)
}
}

Expand Down Expand Up @@ -187,8 +204,12 @@ impl Cache {
}
}

fn cached_output(&mut self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
let key = process_fingerprint(cmd);
fn cached_output(
&mut self,
cmd: &ProcessBuilder,
extra_fingerprint: u64,
) -> CargoResult<(String, String)> {
let key = process_fingerprint(cmd, extra_fingerprint);
if self.data.outputs.contains_key(&key) {
debug!("rustc info cache hit");
} else {
Expand Down Expand Up @@ -295,8 +316,9 @@ fn rustc_fingerprint(path: &Path, rustup_rustc: &Path) -> CargoResult<u64> {
Ok(hasher.finish())
}

fn process_fingerprint(cmd: &ProcessBuilder) -> u64 {
fn process_fingerprint(cmd: &ProcessBuilder, extra_fingerprint: u64) -> u64 {
let mut hasher = StableHasher::new();
extra_fingerprint.hash(&mut hasher);
cmd.get_args().hash(&mut hasher);
let mut env = cmd.get_envs().iter().collect::<Vec<_>>();
env.sort_unstable();
Expand Down
Loading

0 comments on commit 83487e4

Please sign in to comment.