@@ -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
104103pub 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
110110impl < ' 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
116136impl < ' 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
316333pub 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
497504pub 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
645642fn exported_symbols ( scx : & SharedCrateContext ,
0 commit comments