@@ -43,7 +43,7 @@ impl<'a, 'tcx> LinkerInfo {
43
43
}
44
44
45
45
pub fn to_linker ( & ' a self ,
46
- cmd : & ' a mut Command ,
46
+ cmd : Command ,
47
47
sess : & ' a Session ) -> Box < Linker +' a > {
48
48
if sess. target . target . options . is_like_msvc {
49
49
Box :: new ( MsvcLinker {
@@ -61,7 +61,8 @@ impl<'a, 'tcx> LinkerInfo {
61
61
Box :: new ( GnuLinker {
62
62
cmd : cmd,
63
63
sess : sess,
64
- info : self
64
+ info : self ,
65
+ hinted_static : false ,
65
66
} ) as Box < Linker >
66
67
}
67
68
}
@@ -93,30 +94,49 @@ pub trait Linker {
93
94
fn no_default_libraries ( & mut self ) ;
94
95
fn build_dylib ( & mut self , out_filename : & Path ) ;
95
96
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 ) ;
100
97
fn export_symbols ( & mut self , tmpdir : & Path , crate_type : CrateType ) ;
101
98
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 ;
102
101
}
103
102
104
103
pub struct GnuLinker < ' a > {
105
- cmd : & ' a mut Command ,
104
+ cmd : Command ,
106
105
sess : & ' a Session ,
107
- info : & ' a LinkerInfo
106
+ info : & ' a LinkerInfo ,
107
+ hinted_static : bool , // Keeps track of the current hinting mode.
108
108
}
109
109
110
110
impl < ' a > GnuLinker < ' a > {
111
111
fn takes_hints ( & self ) -> bool {
112
112
!self . sess . target . target . options . is_like_osx
113
113
}
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
+ }
114
134
}
115
135
116
136
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) ; }
120
140
fn include_path ( & mut self , path : & Path ) { self . cmd . arg ( "-L" ) . arg ( path) ; }
121
141
fn framework_path ( & mut self , path : & Path ) { self . cmd . arg ( "-F" ) . arg ( path) ; }
122
142
fn output_filename ( & mut self , path : & Path ) { self . cmd . arg ( "-o" ) . arg ( path) ; }
@@ -125,14 +145,23 @@ impl<'a> Linker for GnuLinker<'a> {
125
145
fn args ( & mut self , args : & [ String ] ) { self . cmd . args ( args) ; }
126
146
127
147
fn link_rust_dylib ( & mut self , lib : & str , _path : & Path ) {
148
+ self . hint_dynamic ( ) ;
128
149
self . cmd . arg ( "-l" ) . arg ( lib) ;
129
150
}
130
151
131
152
fn link_framework ( & mut self , framework : & str ) {
153
+ self . hint_dynamic ( ) ;
132
154
self . cmd . arg ( "-framework" ) . arg ( framework) ;
133
155
}
134
156
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.
135
163
fn link_whole_staticlib ( & mut self , lib : & str , search_path : & [ PathBuf ] ) {
164
+ self . hint_static ( ) ;
136
165
let target = & self . sess . target . target ;
137
166
if !target. options . is_like_osx {
138
167
self . cmd . arg ( "-Wl,--whole-archive" )
@@ -148,6 +177,7 @@ impl<'a> Linker for GnuLinker<'a> {
148
177
}
149
178
150
179
fn link_whole_rlib ( & mut self , lib : & Path ) {
180
+ self . hint_static ( ) ;
151
181
if self . sess . target . target . options . is_like_osx {
152
182
let mut v = OsString :: from ( "-Wl,-force_load," ) ;
153
183
v. push ( lib) ;
@@ -228,26 +258,6 @@ impl<'a> Linker for GnuLinker<'a> {
228
258
}
229
259
}
230
260
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
-
251
261
fn export_symbols ( & mut self , tmpdir : & Path , crate_type : CrateType ) {
252
262
// If we're compiling a dylib, then we let symbol visibility in object
253
263
// files to take care of whether they're exported or not.
@@ -311,10 +321,17 @@ impl<'a> Linker for GnuLinker<'a> {
311
321
fn subsystem ( & mut self , subsystem : & str ) {
312
322
self . cmd . arg ( & format ! ( "-Wl,--subsystem,{}" , subsystem) ) ;
313
323
}
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
+ }
314
331
}
315
332
316
333
pub struct MsvcLinker < ' a > {
317
- cmd : & ' a mut Command ,
334
+ cmd : Command ,
318
335
sess : & ' a Session ,
319
336
info : & ' a LinkerInfo
320
337
}
@@ -416,22 +433,6 @@ impl<'a> Linker for MsvcLinker<'a> {
416
433
self . cmd . arg ( "/DEBUG" ) ;
417
434
}
418
435
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
-
435
436
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
436
437
// export symbols from a dynamic library. When building a dynamic library,
437
438
// however, we're going to want some symbols exported, so this function
@@ -492,10 +493,16 @@ impl<'a> Linker for MsvcLinker<'a> {
492
493
self . cmd . arg ( "/ENTRY:mainCRTStartup" ) ;
493
494
}
494
495
}
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
+ }
495
502
}
496
503
497
504
pub struct EmLinker < ' a > {
498
- cmd : & ' a mut Command ,
505
+ cmd : Command ,
499
506
sess : & ' a Session ,
500
507
info : & ' a LinkerInfo
501
508
}
@@ -591,22 +598,6 @@ impl<'a> Linker for EmLinker<'a> {
591
598
bug ! ( "building dynamic library is unsupported on Emscripten" )
592
599
}
593
600
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
-
610
601
fn export_symbols ( & mut self , _tmpdir : & Path , crate_type : CrateType ) {
611
602
let symbols = & self . info . exports [ & crate_type] ;
612
603
@@ -640,6 +631,12 @@ impl<'a> Linker for EmLinker<'a> {
640
631
fn subsystem ( & mut self , _subsystem : & str ) {
641
632
// noop
642
633
}
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
+ }
643
640
}
644
641
645
642
fn exported_symbols ( scx : & SharedCrateContext ,
0 commit comments