Skip to content

Commit 4bb6882

Browse files
Read metadata from rmeta exclusively, if possible
When we're producing an rlib, we do not need anything more than an rmeta file for each of our dependencies (this is indeed utilized by Cargo for pipelining). Previously, we were still storing the paths of possible rlib/dylib crates, which meant that they could still plausibly be accessed. With -Zbinary-dep-depinfo, that meant that Cargo thought that rustc was using both the rlib and an (earlier emitted) rmeta, and so needed a recompile, as the rlib may have finished writing *after* compilation started (for more detail, see issue 68149). This commit changes metadata loading to not store the filepaths of dylib/rlib if we're going to end up creating an rlib only.
1 parent 4884061 commit 4bb6882

File tree

1 file changed

+38
-6
lines changed

1 file changed

+38
-6
lines changed

src/librustc_metadata/locator.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -656,14 +656,36 @@ impl<'a> CrateLocator<'a> {
656656
dylibs: FxHashMap<PathBuf, PathKind>,
657657
) -> Option<(Svh, Library)> {
658658
let mut slot = None;
659+
// Order here matters, rmeta should come first. See comment in
660+
// `extract_one` below.
659661
let source = CrateSource {
660-
rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
661662
rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
663+
rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
662664
dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
663665
};
664666
slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
665667
}
666668

669+
fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
670+
if flavor == CrateFlavor::Dylib && self.is_proc_macro == Some(true) {
671+
return true;
672+
}
673+
674+
// The all loop is because `--crate-type=rlib --crate-type=rlib` is
675+
// legal and produces both inside this type.
676+
let is_rlib = self.sess.crate_types.borrow().iter().all(|c| *c == config::CrateType::Rlib);
677+
let needs_object_code = self.sess.opts.output_types.should_codegen();
678+
// If we're producing an rlib, then we don't need object code.
679+
// Or, if we're not producing object code, then we don't need it either
680+
// (e.g., if we're a cdylib but emitting just metadata).
681+
if is_rlib || !needs_object_code {
682+
flavor == CrateFlavor::Rmeta
683+
} else {
684+
// we need all flavors (perhaps not true, but what we do for now)
685+
true
686+
}
687+
}
688+
667689
// Attempts to extract *one* library from the set `m`. If the set has no
668690
// elements, `None` is returned. If the set has more than one element, then
669691
// the errors and notes are emitted about the set of libraries.
@@ -681,12 +703,22 @@ impl<'a> CrateLocator<'a> {
681703
let mut ret: Option<(PathBuf, PathKind)> = None;
682704
let mut error = 0;
683705

706+
// If we are producing an rlib, and we've already loaded metadata, then
707+
// we should not attempt to discover further crate sources (unless we're
708+
// locating a proc macro; exact logic is in needs_crate_flavor). This means
709+
// that under -Zbinary-dep-depinfo we will not emit a dependency edge on
710+
// the *unused* rlib, and by returning `None` here immediately we
711+
// guarantee that we do indeed not use it.
712+
//
713+
// See also #68149 which provides more detail on why emitting the
714+
// dependency on the rlib is a bad thing.
715+
//
716+
// We currenty do not verify that these other sources are even in sync,
717+
// and this is arguably a bug (see #10786), but because reading metadata
718+
// is quite slow (especially from dylibs) we currently do not read it
719+
// from the other crate sources.
684720
if slot.is_some() {
685-
// FIXME(#10786): for an optimization, we only read one of the
686-
// libraries' metadata sections. In theory we should
687-
// read both, but reading dylib metadata is quite
688-
// slow.
689-
if m.is_empty() {
721+
if m.is_empty() || !self.needs_crate_flavor(flavor) {
690722
return None;
691723
} else if m.len() == 1 {
692724
return Some(m.into_iter().next().unwrap());

0 commit comments

Comments
 (0)