@@ -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,55 @@ 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( ) ) ) ;
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+ if let Some ( implib) = out_filename. parent ( ) . map ( |dir| dir. join ( & implib_name) ) {
337+ let mut out_implib = OsString :: from ( "--out-implib=" ) ;
338+ out_implib. push ( implib) ;
339+ self . linker_arg ( out_implib) ;
340340 }
341+ } else {
342+ // When dylibs are linked by a full path this value will get into `DT_NEEDED`
343+ // instead of the full path, so the library can be later found in some other
344+ // location than that specific path.
345+ let mut soname = OsString :: from ( "-soname=" ) ;
346+ soname. push ( name) ;
347+ self . linker_arg ( soname) ;
341348 }
342349 }
343350 }
344351 }
352+
353+ fn open_as_needed ( & mut self , as_needed : bool ) {
354+ if !as_needed {
355+ if self . sess . target . is_like_osx {
356+ // FIXME(81490): ld64 doesn't support these flags but macOS 11
357+ // has -needed-l{} / -needed_library {}
358+ // but we have no way to detect that here.
359+ self . sess . dcx ( ) . emit_warn ( errors:: Ld64UnimplementedModifier ) ;
360+ } else if self . is_gnu && !self . sess . target . is_like_windows {
361+ self . linker_arg ( "--no-as-needed" ) ;
362+ } else {
363+ self . sess . dcx ( ) . emit_warn ( errors:: LinkerUnsupportedModifier ) ;
364+ }
365+ }
366+ }
367+
368+ fn close_as_needed ( & mut self , as_needed : bool ) {
369+ if !as_needed {
370+ if self . sess . target . is_like_osx {
371+ // See above FIXME comment
372+ } else if self . is_gnu && !self . sess . target . is_like_windows {
373+ self . linker_arg ( "--as-needed" ) ;
374+ }
375+ }
376+ }
345377}
346378
347379impl < ' a > Linker for GccLinker < ' a > {
@@ -443,27 +475,17 @@ impl<'a> Linker for GccLinker<'a> {
443475 // to the linker.
444476 return ;
445477 }
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- }
458478 self . hint_dynamic ( ) ;
479+ self . open_as_needed ( as_needed) ;
459480 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- }
481+ self . close_as_needed ( as_needed) ;
482+ }
483+
484+ fn link_dylib_by_path ( & mut self , path : & Path , as_needed : bool ) {
485+ self . hint_dynamic ( ) ;
486+ self . open_as_needed ( as_needed) ;
487+ self . cmd . arg ( path) ;
488+ self . close_as_needed ( as_needed) ;
467489 }
468490
469491 fn link_framework_by_name ( & mut self , name : & str , _verbatim : bool , as_needed : bool ) {
@@ -813,6 +835,15 @@ impl<'a> Linker for MsvcLinker<'a> {
813835 self . cmd . arg ( format ! ( "{}{}" , name, if verbatim { "" } else { ".lib" } ) ) ;
814836 }
815837
838+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
839+ // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export
840+ // any symbols, so we skip linking if the implib file is not present.
841+ let implib_path = path. with_extension ( "dll.lib" ) ;
842+ if implib_path. exists ( ) {
843+ self . cmd ( ) . arg ( implib_path) ;
844+ }
845+ }
846+
816847 fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
817848 let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" } ;
818849 let suffix = if verbatim { "" } else { ".lib" } ;
@@ -1039,6 +1070,10 @@ impl<'a> Linker for EmLinker<'a> {
10391070 self . cmd . arg ( "-l" ) . arg ( name) ;
10401071 }
10411072
1073+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1074+ self . cmd ( ) . arg ( path) ;
1075+ }
1076+
10421077 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , _whole_archive : bool ) {
10431078 self . cmd . arg ( "-l" ) . arg ( name) ;
10441079 }
@@ -1212,6 +1247,10 @@ impl<'a> Linker for WasmLd<'a> {
12121247 self . cmd . arg ( "-l" ) . arg ( name) ;
12131248 }
12141249
1250+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1251+ self . cmd ( ) . arg ( path) ;
1252+ }
1253+
12151254 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
12161255 if !whole_archive {
12171256 self . cmd . arg ( "-l" ) . arg ( name) ;
@@ -1355,10 +1394,6 @@ impl<'a> Linker for L4Bender<'a> {
13551394
13561395 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
13571396
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-
13621397 fn link_staticlib_by_name ( & mut self , name : & str , _verbatim : bool , whole_archive : bool ) {
13631398 self . hint_static ( ) ;
13641399 if !whole_archive {
@@ -1537,6 +1572,11 @@ impl<'a> Linker for AixLinker<'a> {
15371572 self . cmd . arg ( format ! ( "-l{name}" ) ) ;
15381573 }
15391574
1575+ fn link_dylib_by_path ( & mut self , path : & Path , _as_needed : bool ) {
1576+ self . hint_dynamic ( ) ;
1577+ self . cmd ( ) . arg ( path) ;
1578+ }
1579+
15401580 fn link_staticlib_by_name ( & mut self , name : & str , verbatim : bool , whole_archive : bool ) {
15411581 self . hint_static ( ) ;
15421582 if !whole_archive {
@@ -1738,10 +1778,6 @@ impl<'a> Linker for PtxLinker<'a> {
17381778
17391779 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
17401780
1741- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1742- panic ! ( "external dylibs not supported" )
1743- }
1744-
17451781 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
17461782 panic ! ( "staticlibs not supported" )
17471783 }
@@ -1820,10 +1856,6 @@ impl<'a> Linker for LlbcLinker<'a> {
18201856
18211857 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
18221858
1823- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1824- panic ! ( "external dylibs not supported" )
1825- }
1826-
18271859 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
18281860 panic ! ( "staticlibs not supported" )
18291861 }
@@ -1911,10 +1943,6 @@ impl<'a> Linker for BpfLinker<'a> {
19111943
19121944 fn set_output_kind ( & mut self , _output_kind : LinkOutputKind , _out_filename : & Path ) { }
19131945
1914- fn link_dylib_by_name ( & mut self , _name : & str , _verbatim : bool , _as_needed : bool ) {
1915- panic ! ( "external dylibs not supported" )
1916- }
1917-
19181946 fn link_staticlib_by_name ( & mut self , _name : & str , _verbatim : bool , _whole_archive : bool ) {
19191947 panic ! ( "staticlibs not supported" )
19201948 }
0 commit comments