Auto merge of #32317 - taralx:master, r=alexcrichton
Deduplicate libraries on hash instead of filename. Removes the need for canonicalization to prevent #12459. (Now with passing tests!) Canonicalization breaks certain environments where the libraries are symlinks to files that don't end in .rlib (e.g. /remote/cas/$HASH).
This commit is contained in:
commit
76c1a0df2b
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Eq, Hash, PartialEq, Debug)]
|
||||||
pub struct Svh {
|
pub struct Svh {
|
||||||
hash: String,
|
hash: String,
|
||||||
}
|
}
|
||||||
|
@ -470,20 +470,17 @@ impl<'a> Context<'a> {
|
|||||||
// A Library candidate is created if the metadata for the set of
|
// A Library candidate is created if the metadata for the set of
|
||||||
// libraries corresponds to the crate id and hash criteria that this
|
// libraries corresponds to the crate id and hash criteria that this
|
||||||
// search is being performed for.
|
// search is being performed for.
|
||||||
let mut libraries = Vec::new();
|
let mut libraries = HashMap::new();
|
||||||
for (_hash, (rlibs, dylibs)) in candidates {
|
for (_hash, (rlibs, dylibs)) in candidates {
|
||||||
let mut metadata = None;
|
let mut slot = None;
|
||||||
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
|
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
|
||||||
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
|
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
|
||||||
match metadata {
|
if let Some((h, m)) = slot {
|
||||||
Some(metadata) => {
|
libraries.insert(h, Library {
|
||||||
libraries.push(Library {
|
|
||||||
dylib: dylib,
|
dylib: dylib,
|
||||||
rlib: rlib,
|
rlib: rlib,
|
||||||
metadata: metadata,
|
metadata: m,
|
||||||
})
|
});
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,13 +489,13 @@ impl<'a> Context<'a> {
|
|||||||
// libraries or not.
|
// libraries or not.
|
||||||
match libraries.len() {
|
match libraries.len() {
|
||||||
0 => None,
|
0 => None,
|
||||||
1 => Some(libraries.into_iter().next().unwrap()),
|
1 => Some(libraries.into_iter().next().unwrap().1),
|
||||||
_ => {
|
_ => {
|
||||||
let mut err = struct_span_err!(self.sess, self.span, E0464,
|
let mut err = struct_span_err!(self.sess, self.span, E0464,
|
||||||
"multiple matching crates for `{}`",
|
"multiple matching crates for `{}`",
|
||||||
self.crate_name);
|
self.crate_name);
|
||||||
err.note("candidates:");
|
err.note("candidates:");
|
||||||
for lib in &libraries {
|
for (_, lib) in libraries {
|
||||||
match lib.dylib {
|
match lib.dylib {
|
||||||
Some((ref p, _)) => {
|
Some((ref p, _)) => {
|
||||||
err.note(&format!("path: {}",
|
err.note(&format!("path: {}",
|
||||||
@ -532,13 +529,13 @@ impl<'a> Context<'a> {
|
|||||||
// be read, it is assumed that the file isn't a valid rust library (no
|
// be read, it is assumed that the file isn't a valid rust library (no
|
||||||
// errors are emitted).
|
// errors are emitted).
|
||||||
fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: CrateFlavor,
|
fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: CrateFlavor,
|
||||||
slot: &mut Option<MetadataBlob>) -> Option<(PathBuf, PathKind)> {
|
slot: &mut Option<(Svh, MetadataBlob)>) -> Option<(PathBuf, PathKind)> {
|
||||||
let mut ret = None::<(PathBuf, PathKind)>;
|
let mut ret: Option<(PathBuf, PathKind)> = None;
|
||||||
let mut error = 0;
|
let mut error = 0;
|
||||||
|
|
||||||
if slot.is_some() {
|
if slot.is_some() {
|
||||||
// FIXME(#10786): for an optimization, we only read one of the
|
// FIXME(#10786): for an optimization, we only read one of the
|
||||||
// library's metadata sections. In theory we should
|
// libraries' metadata sections. In theory we should
|
||||||
// read both, but reading dylib metadata is quite
|
// read both, but reading dylib metadata is quite
|
||||||
// slow.
|
// slow.
|
||||||
if m.is_empty() {
|
if m.is_empty() {
|
||||||
@ -551,10 +548,10 @@ impl<'a> Context<'a> {
|
|||||||
let mut err: Option<DiagnosticBuilder> = None;
|
let mut err: Option<DiagnosticBuilder> = None;
|
||||||
for (lib, kind) in m {
|
for (lib, kind) in m {
|
||||||
info!("{} reading metadata from: {}", flavor, lib.display());
|
info!("{} reading metadata from: {}", flavor, lib.display());
|
||||||
let metadata = match get_metadata_section(self.target, flavor, &lib) {
|
let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib) {
|
||||||
Ok(blob) => {
|
Ok(blob) => {
|
||||||
if self.crate_matches(blob.as_slice(), &lib) {
|
if let Some(h) = self.crate_matches(blob.as_slice(), &lib) {
|
||||||
blob
|
(h, blob)
|
||||||
} else {
|
} else {
|
||||||
info!("metadata mismatch");
|
info!("metadata mismatch");
|
||||||
continue
|
continue
|
||||||
@ -565,12 +562,8 @@ impl<'a> Context<'a> {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// If we've already found a candidate and we're not matching hashes,
|
// If we see multiple hashes, emit an error about duplicate candidates.
|
||||||
// emit an error about duplicate candidates found. If we're matching
|
if slot.as_ref().map_or(false, |s| s.0 != hash) {
|
||||||
// based on a hash, however, then if we've gotten this far both
|
|
||||||
// candidates have the same hash, so they're not actually
|
|
||||||
// duplicates that we should warn about.
|
|
||||||
if ret.is_some() && self.hash.is_none() {
|
|
||||||
let mut e = struct_span_err!(self.sess, self.span, E0465,
|
let mut e = struct_span_err!(self.sess, self.span, E0465,
|
||||||
"multiple {} candidates for `{}` found",
|
"multiple {} candidates for `{}` found",
|
||||||
flavor, self.crate_name);
|
flavor, self.crate_name);
|
||||||
@ -583,7 +576,7 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
err = Some(e);
|
err = Some(e);
|
||||||
error = 1;
|
error = 1;
|
||||||
ret = None;
|
*slot = None;
|
||||||
}
|
}
|
||||||
if error > 0 {
|
if error > 0 {
|
||||||
error += 1;
|
error += 1;
|
||||||
@ -592,7 +585,7 @@ impl<'a> Context<'a> {
|
|||||||
lib.display()));
|
lib.display()));
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
*slot = Some(metadata);
|
*slot = Some((hash, metadata));
|
||||||
ret = Some((lib, kind));
|
ret = Some((lib, kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,22 +597,20 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool {
|
fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> Option<Svh> {
|
||||||
if self.should_match_name {
|
if self.should_match_name {
|
||||||
match decoder::maybe_get_crate_name(crate_data) {
|
match decoder::maybe_get_crate_name(crate_data) {
|
||||||
Some(ref name) if self.crate_name == *name => {}
|
Some(ref name) if self.crate_name == *name => {}
|
||||||
_ => { info!("Rejecting via crate name"); return false }
|
_ => { info!("Rejecting via crate name"); return None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let hash = match decoder::maybe_get_crate_hash(crate_data) {
|
let hash = match decoder::maybe_get_crate_hash(crate_data) {
|
||||||
Some(hash) => hash, None => {
|
None => { info!("Rejecting via lack of crate hash"); return None; }
|
||||||
info!("Rejecting via lack of crate hash");
|
Some(h) => h,
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let triple = match decoder::get_crate_triple(crate_data) {
|
let triple = match decoder::get_crate_triple(crate_data) {
|
||||||
None => { debug!("triple not present"); return false }
|
None => { debug!("triple not present"); return None }
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
};
|
};
|
||||||
if triple != self.triple {
|
if triple != self.triple {
|
||||||
@ -628,24 +619,21 @@ impl<'a> Context<'a> {
|
|||||||
path: libpath.to_path_buf(),
|
path: libpath.to_path_buf(),
|
||||||
got: triple.to_string()
|
got: triple.to_string()
|
||||||
});
|
});
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.hash {
|
if let Some(myhash) = self.hash {
|
||||||
None => true,
|
|
||||||
Some(myhash) => {
|
|
||||||
if *myhash != hash {
|
if *myhash != hash {
|
||||||
info!("Rejecting via hash: expected {} got {}", *myhash, hash);
|
info!("Rejecting via hash: expected {} got {}", *myhash, hash);
|
||||||
self.rejected_via_hash.push(CrateMismatch {
|
self.rejected_via_hash.push(CrateMismatch {
|
||||||
path: libpath.to_path_buf(),
|
path: libpath.to_path_buf(),
|
||||||
got: myhash.as_str().to_string()
|
got: myhash.as_str().to_string()
|
||||||
});
|
});
|
||||||
false
|
return None;
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -717,13 +705,13 @@ impl<'a> Context<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Extract the rlib/dylib pair.
|
// Extract the rlib/dylib pair.
|
||||||
let mut metadata = None;
|
let mut slot = None;
|
||||||
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
|
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
|
||||||
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
|
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
|
||||||
|
|
||||||
if rlib.is_none() && dylib.is_none() { return None }
|
if rlib.is_none() && dylib.is_none() { return None }
|
||||||
match metadata {
|
match slot {
|
||||||
Some(metadata) => Some(Library {
|
Some((_, metadata)) => Some(Library {
|
||||||
dylib: dylib,
|
dylib: dylib,
|
||||||
rlib: rlib,
|
rlib: rlib,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
|
@ -18,13 +18,21 @@ all: $(TMPDIR)/libnative.a
|
|||||||
$(RUSTC) d.rs -L crate=$(TMPDIR)/native && exit 1 || exit 0
|
$(RUSTC) d.rs -L crate=$(TMPDIR)/native && exit 1 || exit 0
|
||||||
$(RUSTC) d.rs -L native=$(TMPDIR)/native
|
$(RUSTC) d.rs -L native=$(TMPDIR)/native
|
||||||
$(RUSTC) d.rs -L all=$(TMPDIR)/native
|
$(RUSTC) d.rs -L all=$(TMPDIR)/native
|
||||||
|
# Deduplication tests:
|
||||||
|
# Same hash, no errors.
|
||||||
mkdir -p $(TMPDIR)/e1
|
mkdir -p $(TMPDIR)/e1
|
||||||
mkdir -p $(TMPDIR)/e2
|
mkdir -p $(TMPDIR)/e2
|
||||||
$(RUSTC) e.rs -o $(TMPDIR)/e1/libe.rlib
|
$(RUSTC) e.rs -o $(TMPDIR)/e1/libe.rlib
|
||||||
$(RUSTC) e.rs -o $(TMPDIR)/e2/libe.rlib
|
$(RUSTC) e.rs -o $(TMPDIR)/e2/libe.rlib
|
||||||
|
$(RUSTC) f.rs -L $(TMPDIR)/e1 -L $(TMPDIR)/e2
|
||||||
|
$(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L $(TMPDIR)/e2
|
||||||
|
$(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2
|
||||||
|
# Different hash, errors.
|
||||||
|
$(RUSTC) e2.rs -o $(TMPDIR)/e2/libe.rlib
|
||||||
$(RUSTC) f.rs -L $(TMPDIR)/e1 -L $(TMPDIR)/e2 && exit 1 || exit 0
|
$(RUSTC) f.rs -L $(TMPDIR)/e1 -L $(TMPDIR)/e2 && exit 1 || exit 0
|
||||||
$(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L $(TMPDIR)/e2 && exit 1 || exit 0
|
$(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L $(TMPDIR)/e2 && exit 1 || exit 0
|
||||||
$(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2 && exit 1 || exit 0
|
$(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2 && exit 1 || exit 0
|
||||||
|
# Native/dependency paths don't cause errors.
|
||||||
$(RUSTC) f.rs -L native=$(TMPDIR)/e1 -L $(TMPDIR)/e2
|
$(RUSTC) f.rs -L native=$(TMPDIR)/e1 -L $(TMPDIR)/e2
|
||||||
$(RUSTC) f.rs -L dependency=$(TMPDIR)/e1 -L $(TMPDIR)/e2
|
$(RUSTC) f.rs -L dependency=$(TMPDIR)/e1 -L $(TMPDIR)/e2
|
||||||
$(RUSTC) f.rs -L dependency=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2
|
$(RUSTC) f.rs -L dependency=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2
|
||||||
|
14
src/test/run-make/compiler-lookup-paths/e2.rs
Normal file
14
src/test/run-make/compiler-lookup-paths/e2.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![crate_name = "e"]
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
|
pub fn f() {}
|
@ -3,14 +3,15 @@
|
|||||||
all:
|
all:
|
||||||
$(RUSTC) bar.rs --crate-type=rlib
|
$(RUSTC) bar.rs --crate-type=rlib
|
||||||
$(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a
|
$(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a
|
||||||
|
$(RUSTC) bar-alt.rs --crate-type=rlib
|
||||||
$(RUSTC) foo.rs --extern hello && exit 1 || exit 0
|
$(RUSTC) foo.rs --extern hello && exit 1 || exit 0
|
||||||
$(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0
|
$(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0
|
||||||
$(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0
|
$(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0
|
||||||
$(RUSTC) foo.rs \
|
$(RUSTC) foo.rs \
|
||||||
--extern bar=$(TMPDIR)/libbar.rlib \
|
--extern bar=$(TMPDIR)/libbar.rlib \
|
||||||
--extern bar=$(TMPDIR)/libbar-a.rlib \
|
--extern bar=$(TMPDIR)/libbar-alt.rlib \
|
||||||
&& exit 1 || exit 0
|
&& exit 1 || exit 0
|
||||||
$(RUSTC) foo.rs \
|
$(RUSTC) foo.rs \
|
||||||
--extern bar=$(TMPDIR)/libbar.rlib \
|
--extern bar=$(TMPDIR)/libbar.rlib \
|
||||||
--extern bar=$(TMPDIR)/libbar.rlib
|
--extern bar=$(TMPDIR)/libbar-a.rlib
|
||||||
$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib
|
$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib
|
||||||
|
11
src/test/run-make/extern-flag-fun/bar-alt.rs
Normal file
11
src/test/run-make/extern-flag-fun/bar-alt.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub fn f() {}
|
@ -9,15 +9,13 @@
|
|||||||
|
|
||||||
all:
|
all:
|
||||||
mkdir $(TMPDIR)/other
|
mkdir $(TMPDIR)/other
|
||||||
$(RUSTC) foo.rs --crate-type=dylib
|
$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
|
||||||
mv $(call DYLIB,foo) $(TMPDIR)/other
|
mv $(call DYLIB,foo) $(TMPDIR)/other
|
||||||
$(RUSTC) foo.rs --crate-type=dylib
|
$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
|
||||||
$(RUSTC) bar.rs -L $(TMPDIR)/other 2>&1 | \
|
$(RUSTC) bar.rs -L $(TMPDIR)/other
|
||||||
grep "multiple dylib candidates"
|
|
||||||
rm -rf $(TMPDIR)
|
rm -rf $(TMPDIR)
|
||||||
mkdir -p $(TMPDIR)/other
|
mkdir -p $(TMPDIR)/other
|
||||||
$(RUSTC) foo.rs --crate-type=rlib
|
$(RUSTC) foo.rs --crate-type=rlib
|
||||||
mv $(TMPDIR)/libfoo.rlib $(TMPDIR)/other
|
mv $(TMPDIR)/libfoo.rlib $(TMPDIR)/other
|
||||||
$(RUSTC) foo.rs --crate-type=rlib
|
$(RUSTC) foo.rs --crate-type=rlib
|
||||||
$(RUSTC) bar.rs -L $(TMPDIR)/other 2>&1 | \
|
$(RUSTC) bar.rs -L $(TMPDIR)/other
|
||||||
grep "multiple rlib candidates"
|
|
||||||
|
Loading…
Reference in New Issue
Block a user