@@ -268,7 +268,12 @@ pub trait Linker {
268268 false
269269 }
270270 fn set_output_kind ( & mut self , output_kind : LinkOutputKind , out_filename : & Path ) ;
271- fn link_dylib_by_name ( & mut self , name : & str , verbatim : bool , as_needed : bool ) ;
271+ fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
272+ bug ! ( "dylib linked with unsupported linker" )
273+ }
274+ fn link_dylib_by_path ( & mut self , _path : & Path , _as_needed : bool ) {
275+ bug ! ( "dylib linked with unsupported linker" )
276+ }
272277 fn link_framework_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
273278 bug ! ( "framework linked with unsupported linker" )
274279 }
@@ -403,28 +408,53 @@ impl<'a> GccLinker<'a> {
403408 }
404409 } else {
405410 self . link_or_cc_arg ( "-shared" ) ;
406- if self . sess . target . is_like_windows {
407- // The output filename already contains `dll_suffix` so
408- // the resulting import library will have a name in the
409- // form of libfoo.dll.a
410- let implib_name =
411- out_filename . file_name ( ) . and_then ( |file| file . to_str ( ) ) . map ( |file| {
412- format ! (
413- "{}{}{}" ,
414- self . sess . target . staticlib_prefix ,
415- file ,
416- self . sess . target . staticlib_suffix
417- )
418- } ) ;
419- if let Some ( implib_name ) = implib_name {
420- let implib = out_filename . parent ( ) . map ( |dir| dir . join ( & implib_name ) ) ;
421- if let Some ( implib ) = implib {
422- self . link_arg ( & format ! ( "--out-implib={}" , ( * implib ) . to_str ( ) . unwrap ( ) ) ) ;
423- }
411+ if let Some ( name ) = out_filename . file_name ( ) {
412+ if self . sess . target . is_like_windows {
413+ // The output filename already contains `dll_suffix` so
414+ // the resulting import library will have a name in the
415+ // form of libfoo.dll.a
416+ let mut implib_name = OsString :: from ( & * self . sess . target . staticlib_prefix ) ;
417+ implib_name . push ( name ) ;
418+ implib_name . push ( & * self . sess . target . staticlib_suffix ) ;
419+ let mut out_implib = OsString :: from ( "--out-implib=" ) ;
420+ out_implib . push ( out_filename . with_file_name ( implib_name ) ) ;
421+ self . link_arg ( out_implib ) ;
422+ } else {
423+ // When dylibs are linked by a full path this value will get into `DT_NEEDED`
424+ // instead of the full path, so the library can be later found in some other
425+ // location than that specific path.
426+ let mut soname = OsString :: from ( "-soname=" ) ;
427+ soname . push ( name ) ;
428+ self . link_arg ( soname ) ;
424429 }
425430 }
426431 }
427432 }
433+
434+ fn with_as_needed ( & mut self , as_needed : bool , f : impl FnOnce ( & mut Self ) ) {
435+ if !as_needed {
436+ if self . sess . target . is_like_osx {
437+ // FIXME(81490): ld64 doesn't support these flags but macOS 11
438+ // has -needed-l{} / -needed_library {}
439+ // but we have no way to detect that here.
440+ self . sess . dcx ( ) . emit_warn ( errors:: Ld64UnimplementedModifier ) ;
441+ } else if self . is_gnu && !self . sess . target . is_like_windows {
442+ self . link_arg ( "--no-as-needed" ) ;
443+ } else {
444+ self . sess . dcx ( ) . emit_warn ( errors:: LinkerUnsupportedModifier ) ;
445+ }
446+ }
447+
448+ f ( self ) ;
449+
450+ if !as_needed {
451+ if self . sess . target . is_like_osx {
452+ // See above FIXME comment
453+ } else if self . is_gnu && !self . sess . target . is_like_windows {
454+ self . link_arg ( "--as-needed" ) ;
455+ }
456+ }
457+ }
428458}
429459
430460impl < ' a > Linker for GccLinker < ' a > {
@@ -506,27 +536,18 @@ impl<'a> Linker for GccLinker<'a> {
506536 // to the linker.
507537 return ;
508538 }
509- if !as_needed {
510- if self . sess . target . is_like_osx {
511- // FIXME(81490): ld64 doesn't support these flags but macOS 11
512- // has -needed-l{} / -needed_library {}
513- // but we have no way to detect that here.
514- self . sess . dcx ( ) . emit_warn ( errors:: Ld64UnimplementedModifier ) ;
515- } else if self . is_gnu && !self . sess . target . is_like_windows {
516- self . link_arg ( "--no-as-needed" ) ;
517- } else {
518- self . sess . dcx ( ) . emit_warn ( errors:: LinkerUnsupportedModifier ) ;
519- }
520- }
521539 self . hint_dynamic ( ) ;
522- self . link_or_cc_arg ( format ! ( "-l{}{name}" , if verbatim && self . is_gnu { ":" } else { "" } , ) ) ;
523- if !as_needed {
524- if self . sess . target . is_like_osx {
525- // See above FIXME comment
526- } else if self . is_gnu && !self . sess . target . is_like_windows {
527- self . link_arg ( "--as-needed" ) ;
528- }
529- }
540+ self . with_as_needed ( as_needed, |this| {
541+ let colon = if verbatim && this. is_gnu { ":" } else { "" } ;
542+ this. link_or_cc_arg ( format ! ( "-l{colon}{name}" ) ) ;
543+ } ) ;
544+ }
545+
546+ fn link_dylib_by_path ( & mut self , path : & Path , as_needed : bool ) {
547+ self . hint_dynamic ( ) ;
548+ self . with_as_needed ( as_needed, |this| {
549+ this. link_or_cc_arg ( path) ;
550+ } )
530551 }
531552
532553 fn link_framework_by_name ( & mut self , name : & str , _verbatim : bool , as_needed : bool ) {
@@ -861,6 +882,15 @@ impl<'a> Linker for MsvcLinker<'a> {
861882 self . link_arg ( format ! ( "{}{}" , name, if verbatim { "" } else { ".lib" } ) ) ;
862883 }
863884
885+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
886+ // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export
887+ // any symbols, so we skip linking if the implib file is not present.
888+ let implib_path = path. with_extension ( "dll.lib" ) ;
889+ if implib_path. exists ( ) {
890+ self . link_or_cc_arg ( implib_path) ;
891+ }
892+ }
893+
864894 fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
865895 let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" } ;
866896 let suffix = if verbatim { "" } else { ".lib" } ;
@@ -1083,6 +1113,10 @@ impl<'a> Linker for EmLinker<'a> {
10831113 self . link_or_cc_args ( & [ "-l" , name] ) ;
10841114 }
10851115
1116+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1117+ self . link_or_cc_arg ( path) ;
1118+ }
1119+
10861120 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , _whole_archive : bool ) {
10871121 self . link_or_cc_args ( & [ "-l" , name] ) ;
10881122 }
@@ -1240,6 +1274,10 @@ impl<'a> Linker for WasmLd<'a> {
12401274 self . link_or_cc_args ( & [ "-l" , name] ) ;
12411275 }
12421276
1277+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1278+ self . link_or_cc_arg ( path) ;
1279+ }
1280+
12431281 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
12441282 if !whole_archive {
12451283 self . link_or_cc_args ( & [ "-l" , name] ) ;
@@ -1368,10 +1406,6 @@ impl<'a> Linker for L4Bender<'a> {
13681406
13691407 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
13701408
1371- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1372- bug ! ( "dylibs are not supported on L4Re" ) ;
1373- }
1374-
13751409 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
13761410 self . hint_static ( ) ;
13771411 if !whole_archive {
@@ -1536,6 +1570,11 @@ impl<'a> Linker for AixLinker<'a> {
15361570 self . link_or_cc_arg ( format ! ( "-l{name}" ) ) ;
15371571 }
15381572
1573+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1574+ self . hint_dynamic ( ) ;
1575+ self . link_or_cc_arg ( path) ;
1576+ }
1577+
15391578 fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
15401579 self . hint_static ( ) ;
15411580 if !whole_archive {
@@ -1721,10 +1760,6 @@ impl<'a> Linker for PtxLinker<'a> {
17211760
17221761 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
17231762
1724- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1725- panic ! ( "external dylibs not supported" )
1726- }
1727-
17281763 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
17291764 panic ! ( "staticlibs not supported" )
17301765 }
@@ -1791,10 +1826,6 @@ impl<'a> Linker for LlbcLinker<'a> {
17911826
17921827 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
17931828
1794- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1795- panic ! ( "external dylibs not supported" )
1796- }
1797-
17981829 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
17991830 panic ! ( "staticlibs not supported" )
18001831 }
@@ -1866,10 +1897,6 @@ impl<'a> Linker for BpfLinker<'a> {
18661897
18671898 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
18681899
1869- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1870- panic ! ( "external dylibs not supported" )
1871- }
1872-
18731900 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
18741901 panic ! ( "staticlibs not supported" )
18751902 }
0 commit comments