Skip to content

Commit d445e1c

Browse files
committed
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
1 parent 4755e2f commit d445e1c

File tree

2 files changed

+27
-25
lines changed

2 files changed

+27
-25
lines changed

src/librustc_metadata/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
html_root_url = "https://doc.rust-lang.org/nightly/")]
1414

1515
#![feature(box_patterns)]
16+
#![feature(drain_filter)]
1617
#![feature(libc)]
1718
#![feature(nll)]
1819
#![feature(proc_macro_internals)]

src/librustc_metadata/native_libs.rs

+26-25
Original file line numberDiff line numberDiff line change
@@ -208,34 +208,31 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
208208
}
209209

210210
// Update kind and, optionally, the name of all native libraries
211-
// (there may be more than one) with the specified name.
211+
// (there may be more than one) with the specified name. If any
212+
// library is mentioned more than once, keep the latest mention
213+
// of it, so that any possible dependent libraries appear before
214+
// it. (This ensures that the linker is able to see symbols from
215+
// all possible dependent libraries before linking in the library
216+
// in question.)
212217
for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
213-
let mut found = false;
214-
for lib in self.libs.iter_mut() {
215-
let lib_name = match lib.name {
216-
Some(n) => n,
217-
None => continue,
218-
};
219-
if lib_name == name as &str {
220-
let mut changed = false;
221-
if let Some(k) = kind {
222-
lib.kind = k;
223-
changed = true;
224-
}
225-
if let &Some(ref new_name) = new_name {
226-
lib.name = Some(Symbol::intern(new_name));
227-
changed = true;
228-
}
229-
if !changed {
230-
let msg = format!("redundant linker flag specified for \
231-
library `{}`", name);
232-
self.tcx.sess.warn(&msg);
218+
// If we've already added any native libraries with the same
219+
// name, they will be pulled out into `moved`, so that we can
220+
// move them to the end of the list below.
221+
let mut existing = self.libs.drain_filter(|lib| {
222+
if let Some(lib_name) = lib.name {
223+
if lib_name == name as &str {
224+
if let Some(k) = kind {
225+
lib.kind = k;
226+
}
227+
if let &Some(ref new_name) = new_name {
228+
lib.name = Some(Symbol::intern(new_name));
229+
}
230+
return true;
233231
}
234-
235-
found = true;
236232
}
237-
}
238-
if !found {
233+
false
234+
}).collect::<Vec<_>>();
235+
if existing.is_empty() {
239236
// Add if not found
240237
let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
241238
let lib = NativeLibrary {
@@ -246,6 +243,10 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
246243
wasm_import_module: None,
247244
};
248245
self.register_native_lib(None, lib);
246+
} else {
247+
// Move all existing libraries with the same name to the
248+
// end of the command line.
249+
self.libs.append(&mut existing);
249250
}
250251
}
251252
}

0 commit comments

Comments
 (0)