From e9458b11bbfddcee697522100ab0c1a03455307e Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 4 Jun 2014 13:40:39 -0700 Subject: [PATCH] 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 #13733, #11195. --- src/librustc/metadata/loader.rs | 65 +++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 471240f10af30..c703a676288b4 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -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, flavor: &str, slot: &mut Option) -> Option { - let mut ret = None::; - 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 @@ -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) { @@ -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 {