@@ -7,19 +7,22 @@ use std::ffi::{OsStr, OsString};
7
7
use std:: fs:: { self , File } ;
8
8
use std:: io:: prelude:: * ;
9
9
use std:: io:: { self , BufWriter } ;
10
- use std:: mem;
11
10
use std:: path:: { Path , PathBuf } ;
11
+ use std:: { env, mem, str} ;
12
12
13
13
use rustc_data_structures:: fx:: FxHashMap ;
14
14
use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
15
15
use rustc_middle:: middle:: dependency_format:: Linkage ;
16
16
use rustc_middle:: ty:: TyCtxt ;
17
17
use rustc_serialize:: { json, Encoder } ;
18
18
use rustc_session:: config:: { self , CrateType , DebugInfo , LinkerPluginLto , Lto , OptLevel , Strip } ;
19
+ use rustc_session:: search_paths:: PathKind ;
19
20
use rustc_session:: Session ;
20
21
use rustc_span:: symbol:: Symbol ;
21
22
use rustc_target:: spec:: { LinkOutputKind , LinkerFlavor , LldFlavor } ;
22
23
24
+ use cc:: windows_registry;
25
+
23
26
/// Disables non-English messages from localized linkers.
24
27
/// Such messages may cause issues with text encoding on Windows (#35785)
25
28
/// and prevent inspection of linker output in case of errors, which we occasionally do.
@@ -90,6 +93,97 @@ impl LinkerInfo {
90
93
}
91
94
}
92
95
96
+ // The third parameter is for env vars, used on windows to set up the
97
+ // path for MSVC to find its DLLs, and gcc to find its bundled
98
+ // toolchain
99
+ pub fn get_linker (
100
+ sess : & Session ,
101
+ linker : & Path ,
102
+ flavor : LinkerFlavor ,
103
+ self_contained : bool ,
104
+ ) -> Command {
105
+ let msvc_tool = windows_registry:: find_tool ( & sess. opts . target_triple . triple ( ) , "link.exe" ) ;
106
+
107
+ // If our linker looks like a batch script on Windows then to execute this
108
+ // we'll need to spawn `cmd` explicitly. This is primarily done to handle
109
+ // emscripten where the linker is `emcc.bat` and needs to be spawned as
110
+ // `cmd /c emcc.bat ...`.
111
+ //
112
+ // This worked historically but is needed manually since #42436 (regression
113
+ // was tagged as #42791) and some more info can be found on #44443 for
114
+ // emscripten itself.
115
+ let mut cmd = match linker. to_str ( ) {
116
+ Some ( linker) if cfg ! ( windows) && linker. ends_with ( ".bat" ) => Command :: bat_script ( linker) ,
117
+ _ => match flavor {
118
+ LinkerFlavor :: Lld ( f) => Command :: lld ( linker, f) ,
119
+ LinkerFlavor :: Msvc if sess. opts . cg . linker . is_none ( ) && sess. target . linker . is_none ( ) => {
120
+ Command :: new ( msvc_tool. as_ref ( ) . map_or ( linker, |t| t. path ( ) ) )
121
+ }
122
+ _ => Command :: new ( linker) ,
123
+ } ,
124
+ } ;
125
+
126
+ // UWP apps have API restrictions enforced during Store submissions.
127
+ // To comply with the Windows App Certification Kit,
128
+ // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
129
+ let t = & sess. target ;
130
+ if ( flavor == LinkerFlavor :: Msvc || flavor == LinkerFlavor :: Lld ( LldFlavor :: Link ) )
131
+ && t. vendor == "uwp"
132
+ {
133
+ if let Some ( ref tool) = msvc_tool {
134
+ let original_path = tool. path ( ) ;
135
+ if let Some ( ref root_lib_path) = original_path. ancestors ( ) . nth ( 4 ) {
136
+ let arch = match t. arch . as_str ( ) {
137
+ "x86_64" => Some ( "x64" ) ,
138
+ "x86" => Some ( "x86" ) ,
139
+ "aarch64" => Some ( "arm64" ) ,
140
+ "arm" => Some ( "arm" ) ,
141
+ _ => None ,
142
+ } ;
143
+ if let Some ( ref a) = arch {
144
+ // FIXME: Move this to `fn linker_with_args`.
145
+ let mut arg = OsString :: from ( "/LIBPATH:" ) ;
146
+ arg. push ( format ! ( "{}\\ lib\\ {}\\ store" , root_lib_path. display( ) , a) ) ;
147
+ cmd. arg ( & arg) ;
148
+ } else {
149
+ warn ! ( "arch is not supported" ) ;
150
+ }
151
+ } else {
152
+ warn ! ( "MSVC root path lib location not found" ) ;
153
+ }
154
+ } else {
155
+ warn ! ( "link.exe not found" ) ;
156
+ }
157
+ }
158
+
159
+ // The compiler's sysroot often has some bundled tools, so add it to the
160
+ // PATH for the child.
161
+ let mut new_path = sess. host_filesearch ( PathKind :: All ) . get_tools_search_paths ( self_contained) ;
162
+ let mut msvc_changed_path = false ;
163
+ if sess. target . is_like_msvc {
164
+ if let Some ( ref tool) = msvc_tool {
165
+ cmd. args ( tool. args ( ) ) ;
166
+ for & ( ref k, ref v) in tool. env ( ) {
167
+ if k == "PATH" {
168
+ new_path. extend ( env:: split_paths ( v) ) ;
169
+ msvc_changed_path = true ;
170
+ } else {
171
+ cmd. env ( k, v) ;
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ if !msvc_changed_path {
178
+ if let Some ( path) = env:: var_os ( "PATH" ) {
179
+ new_path. extend ( env:: split_paths ( & path) ) ;
180
+ }
181
+ }
182
+ cmd. env ( "PATH" , env:: join_paths ( new_path) . unwrap ( ) ) ;
183
+
184
+ cmd
185
+ }
186
+
93
187
/// Linker abstraction used by `back::link` to build up the command to invoke a
94
188
/// linker.
95
189
///
0 commit comments