@@ -53,7 +53,9 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default
53
53
// The third parameter is for env vars, used on windows to set up the
54
54
// path for MSVC to find its DLLs, and gcc to find its bundled
55
55
// toolchain
56
- pub fn get_linker ( sess : & Session ) -> ( PathBuf , Command ) {
56
+ pub fn get_linker ( sess : & Session , linker : & Path , flavor : LinkerFlavor ) -> ( PathBuf , Command ) {
57
+ let msvc_tool = windows_registry:: find_tool ( & sess. opts . target_triple . triple ( ) , "link.exe" ) ;
58
+
57
59
// If our linker looks like a batch script on Windows then to execute this
58
60
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
59
61
// emscripten where the linker is `emcc.bat` and needs to be spawned as
@@ -62,36 +64,19 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
62
64
// This worked historically but is needed manually since #42436 (regression
63
65
// was tagged as #42791) and some more info can be found on #44443 for
64
66
// emscripten itself.
65
- let cmd = |linker : & Path | {
66
- if let Some ( linker) = linker. to_str ( ) {
67
- if cfg ! ( windows) && linker. ends_with ( ".bat" ) {
68
- return Command :: bat_script ( linker)
69
- }
70
- }
71
- match sess. linker_flavor ( ) {
67
+ let mut cmd = match linker. to_str ( ) {
68
+ Some ( linker) if cfg ! ( windows) && linker. ends_with ( ".bat" ) => Command :: bat_script ( linker) ,
69
+ _ => match flavor {
72
70
LinkerFlavor :: Lld ( f) => Command :: lld ( linker, f) ,
71
+ LinkerFlavor :: Msvc
72
+ if sess. opts . cg . linker . is_none ( ) && sess. target . target . options . linker . is_none ( ) =>
73
+ {
74
+ Command :: new ( msvc_tool. as_ref ( ) . map ( |t| t. path ( ) ) . unwrap_or ( linker) )
75
+ } ,
73
76
_ => Command :: new ( linker) ,
74
-
75
77
}
76
78
} ;
77
79
78
- let msvc_tool = windows_registry:: find_tool ( & sess. opts . target_triple . triple ( ) , "link.exe" ) ;
79
-
80
- let linker_path = sess. opts . cg . linker . as_ref ( ) . map ( |s| & * * s)
81
- . or ( sess. target . target . options . linker . as_ref ( ) . map ( |s| s. as_ref ( ) ) )
82
- . unwrap_or ( match sess. linker_flavor ( ) {
83
- LinkerFlavor :: Msvc => {
84
- msvc_tool. as_ref ( ) . map ( |t| t. path ( ) ) . unwrap_or ( "link.exe" . as_ref ( ) )
85
- }
86
- LinkerFlavor :: Em if cfg ! ( windows) => "emcc.bat" . as_ref ( ) ,
87
- LinkerFlavor :: Em => "emcc" . as_ref ( ) ,
88
- LinkerFlavor :: Gcc => "cc" . as_ref ( ) ,
89
- LinkerFlavor :: Ld => "ld" . as_ref ( ) ,
90
- LinkerFlavor :: Lld ( _) => "lld" . as_ref ( ) ,
91
- } ) ;
92
-
93
- let mut cmd = cmd ( linker_path) ;
94
-
95
80
// The compiler's sysroot often has some bundled tools, so add it to the
96
81
// PATH for the child.
97
82
let mut new_path = sess. host_filesearch ( PathKind :: All )
@@ -118,7 +103,7 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
118
103
}
119
104
cmd. env ( "PATH" , env:: join_paths ( new_path) . unwrap ( ) ) ;
120
105
121
- ( linker_path . to_path_buf ( ) , cmd)
106
+ ( linker . to_path_buf ( ) , cmd)
122
107
}
123
108
124
109
pub fn remove ( sess : & Session , path : & Path ) {
@@ -608,6 +593,69 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
608
593
}
609
594
}
610
595
596
+ pub fn linker_and_flavor ( sess : & Session ) -> ( PathBuf , LinkerFlavor ) {
597
+ fn infer_from (
598
+ sess : & Session ,
599
+ linker : Option < PathBuf > ,
600
+ flavor : Option < LinkerFlavor > ,
601
+ ) -> Option < ( PathBuf , LinkerFlavor ) > {
602
+ match ( linker, flavor) {
603
+ ( Some ( linker) , Some ( flavor) ) => Some ( ( linker, flavor) ) ,
604
+ // only the linker flavor is known; use the default linker for the selected flavor
605
+ ( None , Some ( flavor) ) => Some ( ( PathBuf :: from ( match flavor {
606
+ LinkerFlavor :: Em => if cfg ! ( windows) { "emcc.bat" } else { "emcc" } ,
607
+ LinkerFlavor :: Gcc => "cc" ,
608
+ LinkerFlavor :: Ld => "ld" ,
609
+ LinkerFlavor :: Msvc => "link.exe" ,
610
+ LinkerFlavor :: Lld ( _) => "lld" ,
611
+ } ) , flavor) ) ,
612
+ ( Some ( linker) , None ) => {
613
+ let stem = linker. file_stem ( ) . and_then ( |stem| stem. to_str ( ) ) . unwrap_or_else ( || {
614
+ sess. fatal ( "couldn't extract file stem from specified linker" ) ;
615
+ } ) . to_owned ( ) ;
616
+
617
+ let flavor = if stem == "emcc" {
618
+ LinkerFlavor :: Em
619
+ } else if stem == "gcc" || stem. ends_with ( "-gcc" ) {
620
+ LinkerFlavor :: Gcc
621
+ } else if stem == "ld" || stem == "ld.lld" || stem. ends_with ( "-ld" ) {
622
+ LinkerFlavor :: Ld
623
+ } else if stem == "link" || stem == "lld-link" {
624
+ LinkerFlavor :: Msvc
625
+ } else if stem == "lld" || stem == "rust-lld" {
626
+ LinkerFlavor :: Lld ( sess. target . target . options . lld_flavor )
627
+ } else {
628
+ // fall back to the value in the target spec
629
+ sess. target . target . linker_flavor
630
+ } ;
631
+
632
+ Some ( ( linker, flavor) )
633
+ } ,
634
+ ( None , None ) => None ,
635
+ }
636
+ }
637
+
638
+ // linker and linker flavor specified via command line have precedence over what the target
639
+ // specification specifies
640
+ if let Some ( ret) = infer_from (
641
+ sess,
642
+ sess. opts . cg . linker . clone ( ) ,
643
+ sess. opts . debugging_opts . linker_flavor ,
644
+ ) {
645
+ return ret;
646
+ }
647
+
648
+ if let Some ( ret) = infer_from (
649
+ sess,
650
+ sess. target . target . options . linker . clone ( ) . map ( PathBuf :: from) ,
651
+ Some ( sess. target . target . linker_flavor ) ,
652
+ ) {
653
+ return ret;
654
+ }
655
+
656
+ bug ! ( "Not enough information provided to determine how to invoke the linker" ) ;
657
+ }
658
+
611
659
// Create a dynamic library or executable
612
660
//
613
661
// This will invoke the system linker/cc to create the resulting file. This
@@ -618,10 +666,10 @@ fn link_natively(sess: &Session,
618
666
codegen_results : & CodegenResults ,
619
667
tmpdir : & Path ) {
620
668
info ! ( "preparing {:?} to {:?}" , crate_type, out_filename) ;
621
- let flavor = sess . linker_flavor ( ) ;
669
+ let ( linker , flavor) = linker_and_flavor ( sess ) ;
622
670
623
671
// The invocations of cc share some flags across platforms
624
- let ( pname, mut cmd) = get_linker ( sess) ;
672
+ let ( pname, mut cmd) = get_linker ( sess, & linker , flavor ) ;
625
673
626
674
let root = sess. target_filesearch ( PathKind :: Native ) . get_lib_path ( ) ;
627
675
if let Some ( args) = sess. target . target . options . pre_link_args . get ( & flavor) {
@@ -662,8 +710,8 @@ fn link_natively(sess: &Session,
662
710
}
663
711
664
712
{
665
- let mut linker = codegen_results. linker_info . to_linker ( cmd, & sess) ;
666
- link_args ( & mut * linker, sess, crate_type, tmpdir,
713
+ let mut linker = codegen_results. linker_info . to_linker ( cmd, & sess, flavor ) ;
714
+ link_args ( & mut * linker, flavor , sess, crate_type, tmpdir,
667
715
out_filename, codegen_results) ;
668
716
cmd = linker. finalize ( ) ;
669
717
}
@@ -735,7 +783,7 @@ fn link_natively(sess: &Session,
735
783
// linking executables as pie. Different versions of gcc seem to use
736
784
// different quotes in the error message so don't check for them.
737
785
if sess. target . target . options . linker_is_gnu &&
738
- sess . linker_flavor ( ) != LinkerFlavor :: Ld &&
786
+ flavor != LinkerFlavor :: Ld &&
739
787
( out. contains ( "unrecognized command line option" ) ||
740
788
out. contains ( "unknown argument" ) ) &&
741
789
out. contains ( "-no-pie" ) &&
@@ -984,6 +1032,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &
984
1032
}
985
1033
986
1034
fn link_args ( cmd : & mut dyn Linker ,
1035
+ flavor : LinkerFlavor ,
987
1036
sess : & Session ,
988
1037
crate_type : config:: CrateType ,
989
1038
tmpdir : & Path ,
@@ -1068,7 +1117,7 @@ fn link_args(cmd: &mut dyn Linker,
1068
1117
// independent executables by default. We have to pass -no-pie to
1069
1118
// explicitly turn that off. Not applicable to ld.
1070
1119
if sess. target . target . options . linker_is_gnu
1071
- && sess . linker_flavor ( ) != LinkerFlavor :: Ld {
1120
+ && flavor != LinkerFlavor :: Ld {
1072
1121
cmd. no_position_independent_executable ( ) ;
1073
1122
}
1074
1123
}
0 commit comments