Keep last redundant linker flag, not first
When a library (L1) is passed to the linker multiple times, this is
sometimes purposeful: there might be several other libraries in the
linker command (L2 and L3) that all depend on L1. You'd end up with a
(simplified) linker command that looks like:
-l2 -l1 -l3 -l1
With the previous behavior, when rustc encountered a redundant library,
it would keep the first instance, and remove the later ones, resulting
in:
-l2 -l1 -l3
This can cause a linker error, because on some platforms (e.g. Linux),
the linker will only include symbols from L1 that are needed *at the
point it's referenced in the command line*. So if L3 depends on
additional symbols from L1, which aren't needed by L2, the linker won't
know to include them, and you'll end up with "undefined symbols" errors.
A better behavior is to keep the *last* instance of the library:
-l2 -l3 -l1
This ensures that all "downstream" libraries have been included in the
linker command before the "upstream" library is referenced.
Fixes rust-lang#47989
This commit is contained in:
parent
4755e2f3b6
commit
d445e1ccaa
2 changed files with 27 additions and 25 deletions
|
|
@ -13,6 +13,7 @@
|
|||
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
|
||||
#![feature(box_patterns)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(libc)]
|
||||
#![feature(nll)]
|
||||
#![feature(proc_macro_internals)]
|
||||
|
|
|
|||
|
|
@ -208,34 +208,31 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Update kind and, optionally, the name of all native libraries
|
||||
// (there may be more than one) with the specified name.
|
||||
// (there may be more than one) with the specified name. If any
|
||||
// library is mentioned more than once, keep the latest mention
|
||||
// of it, so that any possible dependent libraries appear before
|
||||
// it. (This ensures that the linker is able to see symbols from
|
||||
// all possible dependent libraries before linking in the library
|
||||
// in question.)
|
||||
for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
|
||||
let mut found = false;
|
||||
for lib in self.libs.iter_mut() {
|
||||
let lib_name = match lib.name {
|
||||
Some(n) => n,
|
||||
None => continue,
|
||||
};
|
||||
if lib_name == name as &str {
|
||||
let mut changed = false;
|
||||
if let Some(k) = kind {
|
||||
lib.kind = k;
|
||||
changed = true;
|
||||
// If we've already added any native libraries with the same
|
||||
// name, they will be pulled out into `moved`, so that we can
|
||||
// move them to the end of the list below.
|
||||
let mut existing = self.libs.drain_filter(|lib| {
|
||||
if let Some(lib_name) = lib.name {
|
||||
if lib_name == name as &str {
|
||||
if let Some(k) = kind {
|
||||
lib.kind = k;
|
||||
}
|
||||
if let &Some(ref new_name) = new_name {
|
||||
lib.name = Some(Symbol::intern(new_name));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if let &Some(ref new_name) = new_name {
|
||||
lib.name = Some(Symbol::intern(new_name));
|
||||
changed = true;
|
||||
}
|
||||
if !changed {
|
||||
let msg = format!("redundant linker flag specified for \
|
||||
library `{}`", name);
|
||||
self.tcx.sess.warn(&msg);
|
||||
}
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
false
|
||||
}).collect::<Vec<_>>();
|
||||
if existing.is_empty() {
|
||||
// Add if not found
|
||||
let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
|
||||
let lib = NativeLibrary {
|
||||
|
|
@ -246,6 +243,10 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
|
|||
wasm_import_module: None,
|
||||
};
|
||||
self.register_native_lib(None, lib);
|
||||
} else {
|
||||
// Move all existing libraries with the same name to the
|
||||
// end of the command line.
|
||||
self.libs.append(&mut existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue