Skip to content

Commit 7892472

Browse files
committed
Handle transitive All dependency edges
We need to synthesize some dependency edges in the dependency graph to get everything ordered correctly! (more details in the commit itself)
1 parent 6b28a0c commit 7892472

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

src/cargo/core/compiler/fingerprint.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -313,17 +313,24 @@ pub fn prepare_target<'a, 'cfg>(
313313
Ok(Job::new(write_fingerprint, Dirty))
314314
}
315315

316-
/// A compilation unit dependency has a fingerprint that is comprised of:
317-
/// * its package ID
318-
/// * its extern crate name
319-
/// * its public/private status
320-
/// * its calculated fingerprint for the dependency
316+
/// Dependency edge information for fingerprints. This is generated for each
317+
/// unit in `dep_targets` and is stored in a `Fingerprint` below.
321318
#[derive(Clone)]
322319
struct DepFingerprint {
320+
/// The hash of the package id that this dependency points to
323321
pkg_id: u64,
322+
/// The crate name we're using for this dependency, which if we change we'll
323+
/// need to recompile!
324324
name: String,
325+
/// Whether or not this dependency is flagged as a public dependency or not.
325326
public: bool,
327+
/// Whether or not this dependency is an rmeta dependency or a "full"
328+
/// dependency. In the case of an rmeta dependency our dependency edge only
329+
/// actually requires the rmeta from what we depend on, so when checking
330+
/// mtime information all files other than the rmeta can be ignored.
326331
only_requires_rmeta: bool,
332+
/// The dependency's fingerprint we recursively point to, containing all the
333+
/// other hash information we'd otherwise need.
327334
fingerprint: Arc<Fingerprint>,
328335
}
329336

@@ -442,11 +449,14 @@ impl<'de> Deserialize<'de> for DepFingerprint {
442449
pkg_id,
443450
name,
444451
public,
445-
only_requires_rmeta: false,
446452
fingerprint: Arc::new(Fingerprint {
447453
memoized_hash: Mutex::new(Some(hash)),
448454
..Fingerprint::new()
449455
}),
456+
// This field is never read since it's only used in
457+
// `check_filesystem` which isn't used by fingerprints loaded from
458+
// disk.
459+
only_requires_rmeta: false,
450460
})
451461
}
452462
}
@@ -878,7 +888,7 @@ impl hash::Hash for Fingerprint {
878888
name,
879889
public,
880890
fingerprint,
881-
only_requires_rmeta: _,
891+
only_requires_rmeta: _, // static property, no need to hash
882892
} in deps
883893
{
884894
pkg_id.hash(h);

src/cargo/core/compiler/job_queue.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::collections::{HashMap, HashSet};
21
use std::cell::Cell;
2+
use std::collections::{HashMap, HashSet};
33
use std::io;
44
use std::marker;
55
use std::sync::mpsc::{channel, Receiver, Sender};
@@ -152,7 +152,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
152152
job: Job,
153153
) -> CargoResult<()> {
154154
let dependencies = cx.dep_targets(unit);
155-
let dependencies = dependencies
155+
let mut queue_deps = dependencies
156156
.iter()
157157
.filter(|unit| {
158158
// Binaries aren't actually needed to *compile* tests, just to run
@@ -171,10 +171,52 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
171171
Artifact::All
172172
};
173173
(dep, artifact)
174-
});
175-
self.queue.queue(*unit, job, dependencies);
174+
})
175+
.collect::<Vec<_>>();
176+
177+
// This is somewhat tricky, but we may need to synthesize some
178+
// dependencies for this target if it requires full upstream
179+
// compilations to have completed. If we're in pipelining mode then some
180+
// dependency edges may be `Metadata` due to the above clause (as
181+
// opposed to everything being `All`). For example consider:
182+
//
183+
// a (binary)
184+
// └ b (lib)
185+
// └ c (lib)
186+
//
187+
// Here the dependency edge from B to C will be `Metadata`, and the
188+
// dependency edge from A to B will be `All`. For A to be compiled,
189+
// however, it currently actually needs the full rlib of C. This means
190+
// that we need to synthesize a dependency edge for the dependency graph
191+
// from A to C. That's done here.
192+
//
193+
// This will walk all dependencies of the current target, and if any of
194+
// *their* dependencies are `Metadata` then we depend on the `All` of
195+
// the target as well. This should ensure that edges changed to
196+
// `Metadata` propagate upwards `All` dependencies to anything that
197+
// transitively contains the `Metadata` edge.
198+
if unit.target.requires_upstream_objects() {
199+
for dep in dependencies.iter() {
200+
depend_on_deps_of_deps(cx, &mut queue_deps, dep);
201+
}
202+
203+
fn depend_on_deps_of_deps<'a>(
204+
cx: &Context<'a, '_>,
205+
deps: &mut Vec<(Unit<'a>, Artifact)>,
206+
unit: &Unit<'a>,
207+
) {
208+
for dep in cx.dep_targets(unit) {
209+
if cx.only_requires_rmeta(unit, &dep) {
210+
deps.push((dep, Artifact::All));
211+
depend_on_deps_of_deps(cx, deps, &dep);
212+
}
213+
}
214+
}
215+
}
216+
217+
self.queue.queue(*unit, job, queue_deps);
176218
*self.counts.entry(unit.pkg.package_id()).or_insert(0) += 1;
177-
Ok(())
219+
return Ok(());
178220
}
179221

180222
/// Executes all jobs necessary to build the dependency graph.
@@ -430,7 +472,6 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
430472
cx: &Context<'a, '_>,
431473
scope: &Scope<'a>,
432474
) -> CargoResult<()> {
433-
434475
let id = self.next_id;
435476
self.next_id = id.checked_add(1).unwrap();
436477

@@ -464,7 +505,9 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
464505
// we need to make sure that the metadata is flagged as produced so
465506
// send a synthetic message here.
466507
if state.rmeta_required.get() && res.is_ok() {
467-
my_tx.send(Message::Finish(id, Artifact::Metadata, Ok(()))).unwrap();
508+
my_tx
509+
.send(Message::Finish(id, Artifact::Metadata, Ok(())))
510+
.unwrap();
468511
}
469512

470513
my_tx.send(Message::Finish(id, Artifact::All, res)).unwrap();
@@ -513,7 +556,12 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
513556
Ok(())
514557
}
515558

516-
fn finish(&mut self, unit: &Unit<'a>, artifact: Artifact, cx: &mut Context<'_, '_>) -> CargoResult<()> {
559+
fn finish(
560+
&mut self,
561+
unit: &Unit<'a>,
562+
artifact: Artifact,
563+
cx: &mut Context<'_, '_>,
564+
) -> CargoResult<()> {
517565
if unit.mode.is_run_custom_build() && cx.bcx.show_warnings(unit.pkg.package_id()) {
518566
self.emit_warnings(None, unit, cx)?;
519567
}

0 commit comments

Comments
 (0)