Skip to content

Commit 78c3a49

Browse files
committed
Emit linker hints for all library kinds.
1 parent 5c94997 commit 78c3a49

File tree

2 files changed

+68
-90
lines changed

2 files changed

+68
-90
lines changed

src/librustc_trans/back/link.rs

+6-25
Original file line numberDiff line numberDiff line change
@@ -734,9 +734,10 @@ fn link_natively(sess: &Session,
734734
}
735735

736736
{
737-
let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
737+
let mut linker = trans.linker_info.to_linker(cmd, &sess);
738738
link_args(&mut *linker, sess, crate_type, tmpdir,
739739
objects, out_filename, outputs, trans);
740+
cmd = linker.finalize();
740741
}
741742
cmd.args(&sess.target.target.options.late_link_args);
742743
for obj in &sess.target.target.options.post_link_objects {
@@ -1021,38 +1022,18 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
10211022
}
10221023
});
10231024

1024-
let pair = sess.cstore.used_libraries().into_iter().filter(|l| {
1025+
let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| {
10251026
relevant_lib(sess, l)
1026-
}).partition(|lib| {
1027-
lib.kind == NativeLibraryKind::NativeStatic
10281027
});
1029-
let (staticlibs, others): (Vec<_>, Vec<_>) = pair;
1030-
1031-
// Some platforms take hints about whether a library is static or dynamic.
1032-
// For those that support this, we ensure we pass the option if the library
1033-
// was flagged "static" (most defaults are dynamic) to ensure that if
1034-
// libfoo.a and libfoo.so both exist that the right one is chosen.
1035-
cmd.hint_static();
10361028

10371029
let search_path = archive_search_paths(sess);
1038-
for l in staticlibs {
1039-
// Here we explicitly ask that the entire archive is included into the
1040-
// result artifact. For more details see #15460, but the gist is that
1041-
// the linker will strip away any unused objects in the archive if we
1042-
// don't otherwise explicitly reference them. This can occur for
1043-
// libraries which are just providing bindings, libraries with generic
1044-
// functions, etc.
1045-
cmd.link_whole_staticlib(&l.name.as_str(), &search_path);
1046-
}
1047-
1048-
cmd.hint_dynamic();
1049-
1050-
for lib in others {
1030+
for lib in relevant_libs {
10511031
match lib.kind {
10521032
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
10531033
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
10541034
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()),
1055-
NativeLibraryKind::NativeStatic => bug!(),
1035+
NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(),
1036+
&search_path)
10561037
}
10571038
}
10581039
}

src/librustc_trans/back/linker.rs

+62-65
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl<'a, 'tcx> LinkerInfo {
4343
}
4444

4545
pub fn to_linker(&'a self,
46-
cmd: &'a mut Command,
46+
cmd: Command,
4747
sess: &'a Session) -> Box<Linker+'a> {
4848
if sess.target.target.options.is_like_msvc {
4949
Box::new(MsvcLinker {
@@ -61,7 +61,8 @@ impl<'a, 'tcx> LinkerInfo {
6161
Box::new(GnuLinker {
6262
cmd: cmd,
6363
sess: sess,
64-
info: self
64+
info: self,
65+
hinted_static: false,
6566
}) as Box<Linker>
6667
}
6768
}
@@ -93,30 +94,49 @@ pub trait Linker {
9394
fn no_default_libraries(&mut self);
9495
fn build_dylib(&mut self, out_filename: &Path);
9596
fn args(&mut self, args: &[String]);
96-
fn hint_static(&mut self);
97-
fn hint_dynamic(&mut self);
98-
fn whole_archives(&mut self);
99-
fn no_whole_archives(&mut self);
10097
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
10198
fn subsystem(&mut self, subsystem: &str);
99+
// Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
100+
fn finalize(&mut self) -> Command;
102101
}
103102

104103
pub struct GnuLinker<'a> {
105-
cmd: &'a mut Command,
104+
cmd: Command,
106105
sess: &'a Session,
107-
info: &'a LinkerInfo
106+
info: &'a LinkerInfo,
107+
hinted_static: bool, // Keeps track of the current hinting mode.
108108
}
109109

110110
impl<'a> GnuLinker<'a> {
111111
fn takes_hints(&self) -> bool {
112112
!self.sess.target.target.options.is_like_osx
113113
}
114+
115+
// Some platforms take hints about whether a library is static or dynamic.
116+
// For those that support this, we ensure we pass the option if the library
117+
// was flagged "static" (most defaults are dynamic) to ensure that if
118+
// libfoo.a and libfoo.so both exist that the right one is chosen.
119+
fn hint_static(&mut self) {
120+
if !self.takes_hints() { return }
121+
if !self.hinted_static {
122+
self.cmd.arg("-Wl,-Bstatic");
123+
self.hinted_static = true;
124+
}
125+
}
126+
127+
fn hint_dynamic(&mut self) {
128+
if !self.takes_hints() { return }
129+
if self.hinted_static {
130+
self.cmd.arg("-Wl,-Bdynamic");
131+
self.hinted_static = false;
132+
}
133+
}
114134
}
115135

116136
impl<'a> Linker for GnuLinker<'a> {
117-
fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
118-
fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
119-
fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
137+
fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); }
138+
fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); }
139+
fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
120140
fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
121141
fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
122142
fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
@@ -125,14 +145,23 @@ impl<'a> Linker for GnuLinker<'a> {
125145
fn args(&mut self, args: &[String]) { self.cmd.args(args); }
126146

127147
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
148+
self.hint_dynamic();
128149
self.cmd.arg("-l").arg(lib);
129150
}
130151

131152
fn link_framework(&mut self, framework: &str) {
153+
self.hint_dynamic();
132154
self.cmd.arg("-framework").arg(framework);
133155
}
134156

157+
// Here we explicitly ask that the entire archive is included into the
158+
// result artifact. For more details see #15460, but the gist is that
159+
// the linker will strip away any unused objects in the archive if we
160+
// don't otherwise explicitly reference them. This can occur for
161+
// libraries which are just providing bindings, libraries with generic
162+
// functions, etc.
135163
fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
164+
self.hint_static();
136165
let target = &self.sess.target.target;
137166
if !target.options.is_like_osx {
138167
self.cmd.arg("-Wl,--whole-archive")
@@ -148,6 +177,7 @@ impl<'a> Linker for GnuLinker<'a> {
148177
}
149178

150179
fn link_whole_rlib(&mut self, lib: &Path) {
180+
self.hint_static();
151181
if self.sess.target.target.options.is_like_osx {
152182
let mut v = OsString::from("-Wl,-force_load,");
153183
v.push(lib);
@@ -228,26 +258,6 @@ impl<'a> Linker for GnuLinker<'a> {
228258
}
229259
}
230260

231-
fn whole_archives(&mut self) {
232-
if !self.takes_hints() { return }
233-
self.cmd.arg("-Wl,--whole-archive");
234-
}
235-
236-
fn no_whole_archives(&mut self) {
237-
if !self.takes_hints() { return }
238-
self.cmd.arg("-Wl,--no-whole-archive");
239-
}
240-
241-
fn hint_static(&mut self) {
242-
if !self.takes_hints() { return }
243-
self.cmd.arg("-Wl,-Bstatic");
244-
}
245-
246-
fn hint_dynamic(&mut self) {
247-
if !self.takes_hints() { return }
248-
self.cmd.arg("-Wl,-Bdynamic");
249-
}
250-
251261
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
252262
// If we're compiling a dylib, then we let symbol visibility in object
253263
// files to take care of whether they're exported or not.
@@ -311,10 +321,17 @@ impl<'a> Linker for GnuLinker<'a> {
311321
fn subsystem(&mut self, subsystem: &str) {
312322
self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem));
313323
}
324+
325+
fn finalize(&mut self) -> Command {
326+
self.hint_dynamic(); // Reset to default before returning the composed command line.
327+
let mut cmd = Command::new("");
328+
::std::mem::swap(&mut cmd, &mut self.cmd);
329+
cmd
330+
}
314331
}
315332

316333
pub struct MsvcLinker<'a> {
317-
cmd: &'a mut Command,
334+
cmd: Command,
318335
sess: &'a Session,
319336
info: &'a LinkerInfo
320337
}
@@ -416,22 +433,6 @@ impl<'a> Linker for MsvcLinker<'a> {
416433
self.cmd.arg("/DEBUG");
417434
}
418435

419-
fn whole_archives(&mut self) {
420-
// hints not supported?
421-
}
422-
fn no_whole_archives(&mut self) {
423-
// hints not supported?
424-
}
425-
426-
// On windows static libraries are of the form `foo.lib` and dynamic
427-
// libraries are not linked against directly, but rather through their
428-
// import libraries also called `foo.lib`. As a result there's no
429-
// possibility for a native library to appear both dynamically and
430-
// statically in the same folder so we don't have to worry about hints like
431-
// we do on Unix platforms.
432-
fn hint_static(&mut self) {}
433-
fn hint_dynamic(&mut self) {}
434-
435436
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
436437
// export symbols from a dynamic library. When building a dynamic library,
437438
// however, we're going to want some symbols exported, so this function
@@ -492,10 +493,16 @@ impl<'a> Linker for MsvcLinker<'a> {
492493
self.cmd.arg("/ENTRY:mainCRTStartup");
493494
}
494495
}
496+
497+
fn finalize(&mut self) -> Command {
498+
let mut cmd = Command::new("");
499+
::std::mem::swap(&mut cmd, &mut self.cmd);
500+
cmd
501+
}
495502
}
496503

497504
pub struct EmLinker<'a> {
498-
cmd: &'a mut Command,
505+
cmd: Command,
499506
sess: &'a Session,
500507
info: &'a LinkerInfo
501508
}
@@ -591,22 +598,6 @@ impl<'a> Linker for EmLinker<'a> {
591598
bug!("building dynamic library is unsupported on Emscripten")
592599
}
593600

594-
fn whole_archives(&mut self) {
595-
// noop
596-
}
597-
598-
fn no_whole_archives(&mut self) {
599-
// noop
600-
}
601-
602-
fn hint_static(&mut self) {
603-
// noop
604-
}
605-
606-
fn hint_dynamic(&mut self) {
607-
// noop
608-
}
609-
610601
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
611602
let symbols = &self.info.exports[&crate_type];
612603

@@ -640,6 +631,12 @@ impl<'a> Linker for EmLinker<'a> {
640631
fn subsystem(&mut self, _subsystem: &str) {
641632
// noop
642633
}
634+
635+
fn finalize(&mut self) -> Command {
636+
let mut cmd = Command::new("");
637+
::std::mem::swap(&mut cmd, &mut self.cmd);
638+
cmd
639+
}
643640
}
644641

645642
fn exported_symbols(scx: &SharedCrateContext,

0 commit comments

Comments
 (0)