@@ -7,19 +7,22 @@ use std::ffi::{OsStr, OsString};
77use std:: fs:: { self , File } ;
88use std:: io:: prelude:: * ;
99use std:: io:: { self , BufWriter } ;
10- use std:: mem;
1110use std:: path:: { Path , PathBuf } ;
11+ use std:: { env, mem, str} ;
1212
1313use rustc_data_structures:: fx:: FxHashMap ;
1414use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
1515use rustc_middle:: middle:: dependency_format:: Linkage ;
1616use rustc_middle:: ty:: TyCtxt ;
1717use rustc_serialize:: { json, Encoder } ;
1818use rustc_session:: config:: { self , CrateType , DebugInfo , LinkerPluginLto , Lto , OptLevel , Strip } ;
19+ use rustc_session:: search_paths:: PathKind ;
1920use rustc_session:: Session ;
2021use rustc_span:: symbol:: Symbol ;
2122use rustc_target:: spec:: { LinkOutputKind , LinkerFlavor , LldFlavor } ;
2223
24+ use cc:: windows_registry;
25+
2326/// Disables non-English messages from localized linkers.
2427/// Such messages may cause issues with text encoding on Windows (#35785)
2528/// and prevent inspection of linker output in case of errors, which we occasionally do.
@@ -90,6 +93,97 @@ impl LinkerInfo {
9093 }
9194}
9295
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+
93187/// Linker abstraction used by `back::link` to build up the command to invoke a
94188/// linker.
95189///
0 commit comments