Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prioritize target libs when there's multiple candidates #14650

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 41 additions & 24 deletions src/librustc/metadata/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,11 @@ impl<'a> Context<'a> {
// read the metadata from it if `*slot` is `None`. If the metadata couldn't
// be read, it is assumed that the file isn't a valid rust library (no
// errors are emitted).
//
// If there are multiple candidates, and one of them lives in the target
// lib path, pick that candidate instead of erroring out.
fn extract_one(&mut self, m: HashSet<Path>, flavor: &str,
slot: &mut Option<MetadataBlob>) -> Option<Path> {
let mut ret = None::<Path>;
let mut error = 0;

if slot.is_some() {
// FIXME(#10786): for an optimization, we only read one of the
// library's metadata sections. In theory we should
Expand All @@ -364,6 +364,8 @@ impl<'a> Context<'a> {
}
}

let mut candidates: Vec<(Path, MetadataBlob)> = Vec::new();

for lib in m.move_iter() {
info!("{} reading metadata from: {}", flavor, lib.display());
let metadata = match get_metadata_section(self.os, &lib) {
Expand All @@ -380,30 +382,45 @@ impl<'a> Context<'a> {
continue
}
};
if ret.is_some() {
candidates.push((lib, metadata));
}
let (lib, metadata) = if candidates.len() > 1 {
info!("multiple {} candidates for `{}`", flavor, self.crate_id.name);
// look for one from the target lib path
let target_lib_path = self.filesearch.get_lib_path();

let (idx_opt, has_multiple) = {
let mut idxs = candidates.iter().enumerate().filter_map(|(i,&(ref lib, _))| {
if target_lib_path.is_ancestor_of(lib) { Some(i) } else { None }
});
(idxs.next(), idxs.next().is_some())
};
if idx_opt.is_some() && !has_multiple {
// only one library is in the target lib path
let idx = idx_opt.unwrap();
let (lib, metadata) = candidates.move_iter().nth(idx).unwrap();
info!("found candidate in target lib path: {}", lib.display());
(lib, metadata)
} else {
// either multiple libraries were found in the target lib path, or none
self.sess.span_err(self.span,
format!("multiple {} candidates for `{}` \
found",
flavor,
self.crate_id.name).as_slice());
self.sess.span_note(self.span,
format!(r"candidate \#1: {}",
ret.get_ref()
.display()).as_slice());
error = 1;
ret = None;
format!("multiple {} candidates for `{}` found",
flavor, self.crate_id.name).as_slice());
for (i, (lib, _)) in candidates.move_iter().enumerate() {
self.sess.span_note(self.span,
format!(r"candidate \#{}: {}", i+1,
lib.display()).as_slice());
}
return None;
}
if error > 0 {
error += 1;
self.sess.span_note(self.span,
format!(r"candidate \#{}: {}", error,
lib.display()).as_slice());
continue
} else {
match candidates.move_iter().next() {
Some(x) => x,
None => return None
}
*slot = Some(metadata);
ret = Some(lib);
}
return if error > 0 {None} else {ret}
};
*slot = Some(metadata);
Some(lib)
}

fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool {
Expand Down