@@ -169,7 +169,12 @@ pub fn get_linker<'a>(
169169pub trait Linker {
170170 fn cmd ( & mut self ) -> & mut Command ;
171171 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+ }
173178 fn link_framework_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
174179 bug ! ( "framework linked with unsupported linker" )
175180 }
@@ -320,28 +325,53 @@ impl<'a> GccLinker<'a> {
320325 }
321326 } else {
322327 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 ) ;
341346 }
342347 }
343348 }
344349 }
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+ }
345375}
346376
347377impl < ' a > Linker for GccLinker < ' a > {
@@ -443,27 +473,17 @@ impl<'a> Linker for GccLinker<'a> {
443473 // to the linker.
444474 return ;
445475 }
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- }
458476 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+ } )
467487 }
468488
469489 fn link_framework_by_name ( & mut self , name : & str , _verbatim : bool , as_needed : bool ) {
@@ -813,6 +833,15 @@ impl<'a> Linker for MsvcLinker<'a> {
813833 self . cmd . arg ( format ! ( "{}{}" , name, if verbatim { "" } else { ".lib" } ) ) ;
814834 }
815835
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+
816845 fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
817846 let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" } ;
818847 let suffix = if verbatim { "" } else { ".lib" } ;
@@ -1039,6 +1068,10 @@ impl<'a> Linker for EmLinker<'a> {
10391068 self . cmd . arg ( "-l" ) . arg ( name) ;
10401069 }
10411070
1071+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1072+ self . cmd ( ) . arg ( path) ;
1073+ }
1074+
10421075 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , _whole_archive : bool ) {
10431076 self . cmd . arg ( "-l" ) . arg ( name) ;
10441077 }
@@ -1212,6 +1245,10 @@ impl<'a> Linker for WasmLd<'a> {
12121245 self . cmd . arg ( "-l" ) . arg ( name) ;
12131246 }
12141247
1248+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1249+ self . cmd ( ) . arg ( path) ;
1250+ }
1251+
12151252 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
12161253 if !whole_archive {
12171254 self . cmd . arg ( "-l" ) . arg ( name) ;
@@ -1355,10 +1392,6 @@ impl<'a> Linker for L4Bender<'a> {
13551392
13561393 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
13571394
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-
13621395 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
13631396 self . hint_static ( ) ;
13641397 if !whole_archive {
@@ -1537,6 +1570,11 @@ impl<'a> Linker for AixLinker<'a> {
15371570 self . cmd . arg ( format ! ( "-l{name}" ) ) ;
15381571 }
15391572
1573+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1574+ self . hint_dynamic ( ) ;
1575+ self . cmd ( ) . arg ( path) ;
1576+ }
1577+
15401578 fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
15411579 self . hint_static ( ) ;
15421580 if !whole_archive {
@@ -1738,10 +1776,6 @@ impl<'a> Linker for PtxLinker<'a> {
17381776
17391777 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
17401778
1741- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1742- panic ! ( "external dylibs not supported" )
1743- }
1744-
17451779 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
17461780 panic ! ( "staticlibs not supported" )
17471781 }
@@ -1820,10 +1854,6 @@ impl<'a> Linker for LlbcLinker<'a> {
18201854
18211855 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
18221856
1823- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1824- panic ! ( "external dylibs not supported" )
1825- }
1826-
18271857 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
18281858 panic ! ( "staticlibs not supported" )
18291859 }
@@ -1911,10 +1941,6 @@ impl<'a> Linker for BpfLinker<'a> {
19111941
19121942 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
19131943
1914- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1915- panic ! ( "external dylibs not supported" )
1916- }
1917-
19181944 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
19191945 panic ! ( "staticlibs not supported" )
19201946 }
0 commit comments