@@ -60,7 +60,7 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default
60
60
// The third parameter is for env vars, used on windows to set up the
61
61
// path for MSVC to find its DLLs, and gcc to find its bundled
62
62
// toolchain
63
- pub fn get_linker ( sess : & Session ) -> ( PathBuf , Command ) {
63
+ pub fn get_linker ( sess : & Session , linker : & Path , flavor : LinkerFlavor ) -> ( PathBuf , Command ) {
64
64
// If our linker looks like a batch script on Windows then to execute this
65
65
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
66
66
// emscripten where the linker is `emcc.bat` and needs to be spawned as
@@ -69,36 +69,21 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
69
69
// This worked historically but is needed manually since #42436 (regression
70
70
// was tagged as #42791) and some more info can be found on #44443 for
71
71
// emscripten itself.
72
- let cmd = | linker : & Path | {
72
+ let mut cmd = ( | | {
73
73
if let Some ( linker) = linker. to_str ( ) {
74
74
if cfg ! ( windows) && linker. ends_with ( ".bat" ) {
75
75
return Command :: bat_script ( linker)
76
76
}
77
77
}
78
- match sess . linker_flavor ( ) {
78
+ match flavor {
79
79
LinkerFlavor :: Lld ( f) => Command :: lld ( linker, f) ,
80
80
_ => Command :: new ( linker) ,
81
81
82
82
}
83
- } ;
83
+ } ) ( ) ;
84
84
85
85
let msvc_tool = windows_registry:: find_tool ( & sess. opts . target_triple . triple ( ) , "link.exe" ) ;
86
86
87
- let linker_path = sess. opts . cg . linker . as_ref ( ) . map ( |s| & * * s)
88
- . or ( sess. target . target . options . linker . as_ref ( ) . map ( |s| s. as_ref ( ) ) )
89
- . unwrap_or ( match sess. linker_flavor ( ) {
90
- LinkerFlavor :: Msvc => {
91
- msvc_tool. as_ref ( ) . map ( |t| t. path ( ) ) . unwrap_or ( "link.exe" . as_ref ( ) )
92
- }
93
- LinkerFlavor :: Em if cfg ! ( windows) => "emcc.bat" . as_ref ( ) ,
94
- LinkerFlavor :: Em => "emcc" . as_ref ( ) ,
95
- LinkerFlavor :: Gcc => "cc" . as_ref ( ) ,
96
- LinkerFlavor :: Ld => "ld" . as_ref ( ) ,
97
- LinkerFlavor :: Lld ( _) => "lld" . as_ref ( ) ,
98
- } ) ;
99
-
100
- let mut cmd = cmd ( linker_path) ;
101
-
102
87
// The compiler's sysroot often has some bundled tools, so add it to the
103
88
// PATH for the child.
104
89
let mut new_path = sess. host_filesearch ( PathKind :: All )
@@ -125,7 +110,7 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
125
110
}
126
111
cmd. env ( "PATH" , env:: join_paths ( new_path) . unwrap ( ) ) ;
127
112
128
- ( linker_path . to_path_buf ( ) , cmd)
113
+ ( linker . to_path_buf ( ) , cmd)
129
114
}
130
115
131
116
pub fn remove ( sess : & Session , path : & Path ) {
@@ -615,6 +600,71 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
615
600
}
616
601
}
617
602
603
+ pub fn linker_and_flavor ( sess : & Session ) -> Result < ( PathBuf , LinkerFlavor ) , ( ) > {
604
+ fn from < F > (
605
+ sess : & Session ,
606
+ linker : Option < PathBuf > ,
607
+ flavor : Option < LinkerFlavor > ,
608
+ otherwise : F ,
609
+ ) -> Result < ( PathBuf , LinkerFlavor ) , ( ) >
610
+ where
611
+ F : FnOnce ( ) -> Result < ( PathBuf , LinkerFlavor ) , ( ) >
612
+ {
613
+ match ( linker, flavor) {
614
+ ( Some ( linker) , Some ( flavor) ) => Ok ( ( linker, flavor) ) ,
615
+ // only the linker flavor is known; use the default linker for the selected flavor
616
+ ( None , Some ( flavor) ) => Ok ( ( PathBuf :: from ( match flavor {
617
+ LinkerFlavor :: Em => "emcc" ,
618
+ LinkerFlavor :: Gcc => "gcc" ,
619
+ LinkerFlavor :: Ld => "ld" ,
620
+ LinkerFlavor :: Msvc => "link.exe" ,
621
+ LinkerFlavor :: Lld ( _) => "lld" ,
622
+ } ) , flavor) ) ,
623
+ // infer the linker flavor from the linker name
624
+ ( Some ( linker) , None ) => {
625
+ let stem = linker. file_stem ( ) . and_then ( |stem| stem. to_str ( ) ) . ok_or_else ( || {
626
+ sess
627
+ . struct_err ( & format ! ( "couldn't extract file stem from specified linker" ) )
628
+ . emit ( ) ;
629
+ } ) ?. to_owned ( ) ;
630
+
631
+ let flavor = if stem == "emcc" {
632
+ LinkerFlavor :: Em
633
+ } else if stem == "gcc" || stem. ends_with ( "-gcc" ) {
634
+ LinkerFlavor :: Gcc
635
+ } else if stem == "ld" || stem == "ld.lld" || stem. ends_with ( "-ld" ) {
636
+ LinkerFlavor :: Ld
637
+ } else if stem == "link" || stem == "lld-link" {
638
+ LinkerFlavor :: Msvc
639
+ } else {
640
+ sess
641
+ . struct_err ( & format ! ( "couldn't infer linker flavor from specified linker" ) )
642
+ . emit ( ) ;
643
+ return Err ( ( ) ) ;
644
+ } ;
645
+
646
+ Ok ( ( linker, flavor) )
647
+ } ,
648
+ ( None , None ) => otherwise ( ) ,
649
+ }
650
+ }
651
+
652
+ // linker and linker flavor specified via command line have precedence over what the target
653
+ // specification specifies
654
+ from ( sess, sess. opts . cg . linker . clone ( ) , sess. opts . debugging_opts . linker_flavor , || {
655
+ from (
656
+ sess,
657
+ sess. target . target . options . linker . clone ( ) . map ( PathBuf :: from) ,
658
+ Some ( sess. target . target . linker_flavor ) ,
659
+ || {
660
+ sess
661
+ . struct_err ( & format ! ( "no linker or linker flavor information provided" ) )
662
+ . emit ( ) ;
663
+ Err ( ( ) )
664
+ } )
665
+ } )
666
+ }
667
+
618
668
// Create a dynamic library or executable
619
669
//
620
670
// This will invoke the system linker/cc to create the resulting file. This
@@ -625,10 +675,15 @@ fn link_natively(sess: &Session,
625
675
codegen_results : & CodegenResults ,
626
676
tmpdir : & Path ) {
627
677
info ! ( "preparing {:?} to {:?}" , crate_type, out_filename) ;
628
- let flavor = sess. linker_flavor ( ) ;
678
+ let ( linker, flavor) = if let Ok ( ( linker, flavor) ) = linker_and_flavor ( sess) {
679
+ ( linker, flavor)
680
+ } else {
681
+ sess. abort_if_errors ( ) ;
682
+ return ;
683
+ } ;
629
684
630
685
// The invocations of cc share some flags across platforms
631
- let ( pname, mut cmd) = get_linker ( sess) ;
686
+ let ( pname, mut cmd) = get_linker ( sess, & linker , flavor ) ;
632
687
633
688
let root = sess. target_filesearch ( PathKind :: Native ) . get_lib_path ( ) ;
634
689
if let Some ( args) = sess. target . target . options . pre_link_args . get ( & flavor) {
@@ -669,8 +724,8 @@ fn link_natively(sess: &Session,
669
724
}
670
725
671
726
{
672
- let mut linker = codegen_results. linker_info . to_linker ( cmd, & sess) ;
673
- link_args ( & mut * linker, sess, crate_type, tmpdir,
727
+ let mut linker = codegen_results. linker_info . to_linker ( cmd, & sess, flavor ) ;
728
+ link_args ( & mut * linker, flavor , sess, crate_type, tmpdir,
674
729
out_filename, codegen_results) ;
675
730
cmd = linker. finalize ( ) ;
676
731
}
@@ -742,7 +797,7 @@ fn link_natively(sess: &Session,
742
797
// linking executables as pie. Different versions of gcc seem to use
743
798
// different quotes in the error message so don't check for them.
744
799
if sess. target . target . options . linker_is_gnu &&
745
- sess . linker_flavor ( ) != LinkerFlavor :: Ld &&
800
+ flavor != LinkerFlavor :: Ld &&
746
801
( out. contains ( "unrecognized command line option" ) ||
747
802
out. contains ( "unknown argument" ) ) &&
748
803
out. contains ( "-no-pie" ) &&
@@ -991,6 +1046,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &
991
1046
}
992
1047
993
1048
fn link_args ( cmd : & mut dyn Linker ,
1049
+ flavor : LinkerFlavor ,
994
1050
sess : & Session ,
995
1051
crate_type : config:: CrateType ,
996
1052
tmpdir : & Path ,
@@ -1075,7 +1131,7 @@ fn link_args(cmd: &mut dyn Linker,
1075
1131
// independent executables by default. We have to pass -no-pie to
1076
1132
// explicitly turn that off. Not applicable to ld.
1077
1133
if sess. target . target . options . linker_is_gnu
1078
- && sess . linker_flavor ( ) != LinkerFlavor :: Ld {
1134
+ && flavor != LinkerFlavor :: Ld {
1079
1135
cmd. no_position_independent_executable ( ) ;
1080
1136
}
1081
1137
}
0 commit comments