Skip to content

Commit e9458b1

Browse files
committed
Prioritize target libs when there's multiple candidates
When multiple candidates for a library are found, if one (and only one) candidate lives in the target library path, prioritize that one. This allows `rustc -L /usr/local/lib lib.rs` to compile successfully, whereas today it complains about multiple candidates for e.g. libstd. Fixes rust-lang#13733, rust-lang#11195.
1 parent 3eeaa84 commit e9458b1

File tree

1 file changed

+41
-24
lines changed

1 file changed

+41
-24
lines changed

src/librustc/metadata/loader.rs

+41-24
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,11 @@ impl<'a> Context<'a> {
347347
// read the metadata from it if `*slot` is `None`. If the metadata couldn't
348348
// be read, it is assumed that the file isn't a valid rust library (no
349349
// errors are emitted).
350+
//
351+
// If there are multiple candidates, and one of them lives in the target
352+
// lib path, pick that candidate instead of erroring out.
350353
fn extract_one(&mut self, m: HashSet<Path>, flavor: &str,
351354
slot: &mut Option<MetadataBlob>) -> Option<Path> {
352-
let mut ret = None::<Path>;
353-
let mut error = 0;
354-
355355
if slot.is_some() {
356356
// FIXME(#10786): for an optimization, we only read one of the
357357
// library's metadata sections. In theory we should
@@ -364,6 +364,8 @@ impl<'a> Context<'a> {
364364
}
365365
}
366366

367+
let mut candidates: Vec<(Path, MetadataBlob)> = Vec::new();
368+
367369
for lib in m.move_iter() {
368370
info!("{} reading metadata from: {}", flavor, lib.display());
369371
let metadata = match get_metadata_section(self.os, &lib) {
@@ -380,30 +382,45 @@ impl<'a> Context<'a> {
380382
continue
381383
}
382384
};
383-
if ret.is_some() {
385+
candidates.push((lib, metadata));
386+
}
387+
let (lib, metadata) = if candidates.len() > 1 {
388+
info!("multiple {} candidates for `{}`", flavor, self.crate_id.name);
389+
// look for one from the target lib path
390+
let target_lib_path = self.filesearch.get_lib_path();
391+
392+
let (idx_opt, has_multiple) = {
393+
let mut idxs = candidates.iter().enumerate().filter_map(|(i,&(ref lib, _))| {
394+
if target_lib_path.is_ancestor_of(lib) { Some(i) } else { None }
395+
});
396+
(idxs.next(), idxs.next().is_some())
397+
};
398+
if idx_opt.is_some() && !has_multiple {
399+
// only one library is in the target lib path
400+
let idx = idx_opt.unwrap();
401+
let (lib, metadata) = candidates.move_iter().nth(idx).unwrap();
402+
info!("found candidate in target lib path: {}", lib.display());
403+
(lib, metadata)
404+
} else {
405+
// either multiple libraries were found in the target lib path, or none
384406
self.sess.span_err(self.span,
385-
format!("multiple {} candidates for `{}` \
386-
found",
387-
flavor,
388-
self.crate_id.name).as_slice());
389-
self.sess.span_note(self.span,
390-
format!(r"candidate \#1: {}",
391-
ret.get_ref()
392-
.display()).as_slice());
393-
error = 1;
394-
ret = None;
407+
format!("multiple {} candidates for `{}` found",
408+
flavor, self.crate_id.name).as_slice());
409+
for (i, (lib, _)) in candidates.move_iter().enumerate() {
410+
self.sess.span_note(self.span,
411+
format!(r"candidate \#{}: {}", i+1,
412+
lib.display()).as_slice());
413+
}
414+
return None;
395415
}
396-
if error > 0 {
397-
error += 1;
398-
self.sess.span_note(self.span,
399-
format!(r"candidate \#{}: {}", error,
400-
lib.display()).as_slice());
401-
continue
416+
} else {
417+
match candidates.move_iter().next() {
418+
Some(x) => x,
419+
None => return None
402420
}
403-
*slot = Some(metadata);
404-
ret = Some(lib);
405-
}
406-
return if error > 0 {None} else {ret}
421+
};
422+
*slot = Some(metadata);
423+
Some(lib)
407424
}
408425

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

0 commit comments

Comments
 (0)