@@ -169,7 +169,12 @@ pub fn get_linker<'a>(
169
169
pub trait Linker {
170
170
fn cmd ( & mut self ) -> & mut Command ;
171
171
fn set_output_kind ( & mut self , output_kind : LinkOutputKind , out_filename : & Path ) ;
172
- fn link_dylib_by_name ( & mut self , name : & str , verbatim : bool , as_needed : bool ) ;
172
+ fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
173
+ bug ! ( "dylib linked with unsupported linker" )
174
+ }
175
+ fn link_dylib_by_path ( & mut self , _path : & Path , _as_needed : bool ) {
176
+ bug ! ( "dylib linked with unsupported linker" )
177
+ }
173
178
fn link_framework_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
174
179
bug ! ( "framework linked with unsupported linker" )
175
180
}
@@ -320,28 +325,53 @@ impl<'a> GccLinker<'a> {
320
325
}
321
326
} else {
322
327
self . cmd . arg ( "-shared" ) ;
323
- if self . sess . target . is_like_windows {
324
- // The output filename already contains `dll_suffix` so
325
- // the resulting import library will have a name in the
326
- // form of libfoo.dll.a
327
- let implib_name =
328
- out_filename . file_name ( ) . and_then ( |file| file . to_str ( ) ) . map ( |file| {
329
- format ! (
330
- "{}{}{}" ,
331
- self . sess . target . staticlib_prefix ,
332
- file ,
333
- self . sess . target . staticlib_suffix
334
- )
335
- } ) ;
336
- if let Some ( implib_name ) = implib_name {
337
- let implib = out_filename . parent ( ) . map ( |dir| dir . join ( & implib_name ) ) ;
338
- if let Some ( implib ) = implib {
339
- self . linker_arg ( & format ! ( "--out-implib={}" , ( * implib ) . to_str ( ) . unwrap ( ) ) ) ;
340
- }
328
+ if let Some ( name ) = out_filename . file_name ( ) {
329
+ if self . sess . target . is_like_windows {
330
+ // The output filename already contains `dll_suffix` so
331
+ // the resulting import library will have a name in the
332
+ // form of libfoo.dll.a
333
+ let mut implib_name = OsString :: from ( & * self . sess . target . staticlib_prefix ) ;
334
+ implib_name . push ( name ) ;
335
+ implib_name . push ( & * self . sess . target . staticlib_suffix ) ;
336
+ let mut out_implib = OsString :: from ( "--out-implib=" ) ;
337
+ out_implib . push ( out_filename . with_file_name ( implib_name ) ) ;
338
+ self . linker_arg ( out_implib ) ;
339
+ } else {
340
+ // When dylibs are linked by a full path this value will get into `DT_NEEDED`
341
+ // instead of the full path, so the library can be later found in some other
342
+ // location than that specific path.
343
+ let mut soname = OsString :: from ( "-soname=" ) ;
344
+ soname . push ( name ) ;
345
+ self . linker_arg ( soname ) ;
341
346
}
342
347
}
343
348
}
344
349
}
350
+
351
+ fn with_as_needed ( & mut self , as_needed : bool , f : impl FnOnce ( & mut Self ) ) {
352
+ if !as_needed {
353
+ if self . sess . target . is_like_osx {
354
+ // FIXME(81490): ld64 doesn't support these flags but macOS 11
355
+ // has -needed-l{} / -needed_library {}
356
+ // but we have no way to detect that here.
357
+ self . sess . dcx ( ) . emit_warn ( errors:: Ld64UnimplementedModifier ) ;
358
+ } else if self . is_gnu && !self . sess . target . is_like_windows {
359
+ self . linker_arg ( "--no-as-needed" ) ;
360
+ } else {
361
+ self . sess . dcx ( ) . emit_warn ( errors:: LinkerUnsupportedModifier ) ;
362
+ }
363
+ }
364
+
365
+ f ( self ) ;
366
+
367
+ if !as_needed {
368
+ if self . sess . target . is_like_osx {
369
+ // See above FIXME comment
370
+ } else if self . is_gnu && !self . sess . target . is_like_windows {
371
+ self . linker_arg ( "--as-needed" ) ;
372
+ }
373
+ }
374
+ }
345
375
}
346
376
347
377
impl < ' a > Linker for GccLinker < ' a > {
@@ -443,27 +473,17 @@ impl<'a> Linker for GccLinker<'a> {
443
473
// to the linker.
444
474
return ;
445
475
}
446
- if !as_needed {
447
- if self . sess . target . is_like_osx {
448
- // FIXME(81490): ld64 doesn't support these flags but macOS 11
449
- // has -needed-l{} / -needed_library {}
450
- // but we have no way to detect that here.
451
- self . sess . dcx ( ) . emit_warn ( errors:: Ld64UnimplementedModifier ) ;
452
- } else if self . is_gnu && !self . sess . target . is_like_windows {
453
- self . linker_arg ( "--no-as-needed" ) ;
454
- } else {
455
- self . sess . dcx ( ) . emit_warn ( errors:: LinkerUnsupportedModifier ) ;
456
- }
457
- }
458
476
self . hint_dynamic ( ) ;
459
- self . cmd . arg ( format ! ( "-l{}{name}" , if verbatim && self . is_gnu { ":" } else { "" } , ) ) ;
460
- if !as_needed {
461
- if self . sess . target . is_like_osx {
462
- // See above FIXME comment
463
- } else if self . is_gnu && !self . sess . target . is_like_windows {
464
- self . linker_arg ( "--as-needed" ) ;
465
- }
466
- }
477
+ self . with_as_needed ( as_needed, |this| {
478
+ this. cmd . arg ( format ! ( "-l{}{name}" , if verbatim && this. is_gnu { ":" } else { "" } ) ) ;
479
+ } ) ;
480
+ }
481
+
482
+ fn link_dylib_by_path ( & mut self , path : & Path , as_needed : bool ) {
483
+ self . hint_dynamic ( ) ;
484
+ self . with_as_needed ( as_needed, |this| {
485
+ this. cmd . arg ( path) ;
486
+ } )
467
487
}
468
488
469
489
fn link_framework_by_name ( & mut self , name : & str , _verbatim : bool , as_needed : bool ) {
@@ -813,6 +833,15 @@ impl<'a> Linker for MsvcLinker<'a> {
813
833
self . cmd . arg ( format ! ( "{}{}" , name, if verbatim { "" } else { ".lib" } ) ) ;
814
834
}
815
835
836
+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
837
+ // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export
838
+ // any symbols, so we skip linking if the implib file is not present.
839
+ let implib_path = path. with_extension ( "dll.lib" ) ;
840
+ if implib_path. exists ( ) {
841
+ self . cmd ( ) . arg ( implib_path) ;
842
+ }
843
+ }
844
+
816
845
fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
817
846
let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" } ;
818
847
let suffix = if verbatim { "" } else { ".lib" } ;
@@ -1039,6 +1068,10 @@ impl<'a> Linker for EmLinker<'a> {
1039
1068
self . cmd . arg ( "-l" ) . arg ( name) ;
1040
1069
}
1041
1070
1071
+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1072
+ self . cmd ( ) . arg ( path) ;
1073
+ }
1074
+
1042
1075
fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , _whole_archive : bool ) {
1043
1076
self . cmd . arg ( "-l" ) . arg ( name) ;
1044
1077
}
@@ -1212,6 +1245,10 @@ impl<'a> Linker for WasmLd<'a> {
1212
1245
self . cmd . arg ( "-l" ) . arg ( name) ;
1213
1246
}
1214
1247
1248
+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1249
+ self . cmd ( ) . arg ( path) ;
1250
+ }
1251
+
1215
1252
fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
1216
1253
if !whole_archive {
1217
1254
self . cmd . arg ( "-l" ) . arg ( name) ;
@@ -1355,10 +1392,6 @@ impl<'a> Linker for L4Bender<'a> {
1355
1392
1356
1393
fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
1357
1394
1358
- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1359
- bug ! ( "dylibs are not supported on L4Re" ) ;
1360
- }
1361
-
1362
1395
fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
1363
1396
self . hint_static ( ) ;
1364
1397
if !whole_archive {
@@ -1537,6 +1570,11 @@ impl<'a> Linker for AixLinker<'a> {
1537
1570
self . cmd . arg ( format ! ( "-l{name}" ) ) ;
1538
1571
}
1539
1572
1573
+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1574
+ self . hint_dynamic ( ) ;
1575
+ self . cmd ( ) . arg ( path) ;
1576
+ }
1577
+
1540
1578
fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
1541
1579
self . hint_static ( ) ;
1542
1580
if !whole_archive {
@@ -1738,10 +1776,6 @@ impl<'a> Linker for PtxLinker<'a> {
1738
1776
1739
1777
fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
1740
1778
1741
- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1742
- panic ! ( "external dylibs not supported" )
1743
- }
1744
-
1745
1779
fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
1746
1780
panic ! ( "staticlibs not supported" )
1747
1781
}
@@ -1820,10 +1854,6 @@ impl<'a> Linker for LlbcLinker<'a> {
1820
1854
1821
1855
fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
1822
1856
1823
- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1824
- panic ! ( "external dylibs not supported" )
1825
- }
1826
-
1827
1857
fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
1828
1858
panic ! ( "staticlibs not supported" )
1829
1859
}
@@ -1911,10 +1941,6 @@ impl<'a> Linker for BpfLinker<'a> {
1911
1941
1912
1942
fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
1913
1943
1914
- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1915
- panic ! ( "external dylibs not supported" )
1916
- }
1917
-
1918
1944
fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
1919
1945
panic ! ( "staticlibs not supported" )
1920
1946
}
0 commit comments