@@ -42,7 +42,8 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
4242    use  std:: env; 
4343    use  std:: ffi:: OsString ; 
4444    use  std:: fs; 
45-     use  std:: path:: PathBuf ; 
45+     use  std:: io; 
46+     use  std:: path:: { Path ,  PathBuf } ; 
4647    use  self :: registry:: { RegistryKey ,  LOCAL_MACHINE } ; 
4748
4849    // When finding the link.exe binary the 32-bit version is at the top level 
@@ -103,16 +104,32 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
103104    // VS shells, so we only want to start adding our own pieces if it's not 
104105    // set. 
105106    // 
106-     // If we're adding our own pieces, then we need to add two  primary 
107+     // If we're adding our own pieces, then we need to add a few  primary 
107108    // directories to the default search path for the linker. The first is in 
108-     // the VS install direcotry and the next is the Windows SDK directory. 
109+     // the VS install direcotry, the next is the Windows SDK directory, and the 
110+     // last is the possible UCRT installation directory. 
111+     // 
112+     // The UCRT is a recent addition to Visual Studio installs (2015 at the time 
113+     // of this writing), and it's in the normal windows SDK folder, but there 
114+     // apparently aren't registry keys pointing to it. As a result we detect the 
115+     // installation and then add it manually. This logic will probably need to 
116+     // be tweaked over time... 
109117    if  env:: var_os ( "LIB" ) . is_none ( )  { 
110118        if  let  Some ( mut  vs_install_dir)  = vs_install_dir { 
111119            vs_install_dir. push ( "VC/lib" ) ; 
112120            vs_install_dir. push ( extra) ; 
113121            let  mut  arg = OsString :: from ( "/LIBPATH:" ) ; 
114122            arg. push ( & vs_install_dir) ; 
115123            cmd. arg ( arg) ; 
124+ 
125+             if  let  Some ( ( ucrt_root,  vers) )  = ucrt_install_dir ( & vs_install_dir)  { 
126+                 if  let  Some ( arch)  = windows_sdk_v8_subdir ( sess)  { 
127+                     let  mut  arg = OsString :: from ( "/LIBPATH:" ) ; 
128+                     arg. push ( ucrt_root. join ( "Lib" ) . join ( vers) 
129+                                       . join ( "ucrt" ) . join ( arch) ) ; 
130+                     cmd. arg ( arg) ; 
131+                 } 
132+             } 
116133        } 
117134        if  let  Some ( path)  = get_windows_sdk_lib_path ( sess)  { 
118135            let  mut  arg = OsString :: from ( "/LIBPATH:" ) ; 
@@ -189,7 +206,7 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
189206        return  max_key
190207    } 
191208
192-     fn  get_windows_sdk_lib_path ( sess :   & Session )  -> Option < PathBuf >  { 
209+     fn  get_windows_sdk_path ( )  -> Option < ( PathBuf ,   usize ) >  { 
193210        let  key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows" ; 
194211        let  key = LOCAL_MACHINE . open ( key. as_ref ( ) ) ; 
195212        let  ( n,  k)  = match  key. ok ( ) . as_ref ( ) . and_then ( max_version)  { 
@@ -199,10 +216,17 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
199216        let  mut  parts = n. to_str ( ) . unwrap ( ) . trim_left_matches ( "v" ) . splitn ( 2 ,  "." ) ; 
200217        let  major = parts. next ( ) . unwrap ( ) . parse :: < usize > ( ) . unwrap ( ) ; 
201218        let  _minor = parts. next ( ) . unwrap ( ) . parse :: < usize > ( ) . unwrap ( ) ; 
202-         let  path = match  k. query_str ( "InstallationFolder" )  { 
203-             Ok ( p)  => PathBuf :: from ( p) . join ( "Lib" ) , 
204-             Err ( ..)  => return  None , 
219+         k. query_str ( "InstallationFolder" ) . ok ( ) . map ( |folder| { 
220+             ( PathBuf :: from ( folder) ,  major) 
221+         } ) 
222+     } 
223+ 
224+     fn  get_windows_sdk_lib_path ( sess :  & Session )  -> Option < PathBuf >  { 
225+         let  ( mut  path,  major)  = match  get_windows_sdk_path ( )  { 
226+             Some ( p)  => p, 
227+             None  => return  None , 
205228        } ; 
229+         path. push ( "Lib" ) ; 
206230        if  major <= 7  { 
207231            // In Windows SDK 7.x, x86 libraries are directly in the Lib folder, 
208232            // x64 libraries are inside, and it's not necessary to link agains 
@@ -218,11 +242,9 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
218242            // depend on the version of the OS you're targeting. By default 
219243            // choose the newest, which usually corresponds to the version of 
220244            // the OS you've installed the SDK on. 
221-             let  extra = match  & sess. target . target . arch [ ..]  { 
222-                 "x86"  => "x86" , 
223-                 "x86_64"  => "x64" , 
224-                 "arm"  => "arm" , 
225-                 _ => return  None , 
245+             let  extra = match  windows_sdk_v8_subdir ( sess)  { 
246+                 Some ( e)  => e, 
247+                 None  => return  None , 
226248            } ; 
227249            [ "winv6.3" ,  "win8" ,  "win7" ] . iter ( ) . map ( |p| path. join ( p) ) . find ( |part| { 
228250                fs:: metadata ( part) . is_ok ( ) 
@@ -231,6 +253,48 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
231253            } ) 
232254        } 
233255    } 
256+ 
257+     fn  windows_sdk_v8_subdir ( sess :  & Session )  -> Option < & ' static  str >  { 
258+         match  & sess. target . target . arch [ ..]  { 
259+             "x86"  => Some ( "x86" ) , 
260+             "x86_64"  => Some ( "x64" ) , 
261+             "arm"  => Some ( "arm" ) , 
262+             _ => return  None , 
263+         } 
264+     } 
265+ 
266+     fn  ucrt_install_dir ( vs_install_dir :  & Path )  -> Option < ( PathBuf ,  String ) >  { 
267+         let  is_vs_14 = vs_install_dir. iter ( ) . filter_map ( |p| p. to_str ( ) ) . any ( |s| { 
268+             s == "Microsoft Visual Studio 14.0" 
269+         } ) ; 
270+         if  !is_vs_14 { 
271+             return  None 
272+         } 
273+         let  key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots" ; 
274+         let  sdk_dir = LOCAL_MACHINE . open ( key. as_ref ( ) ) . and_then ( |p| { 
275+             p. query_str ( "KitsRoot10" ) 
276+         } ) . map ( PathBuf :: from) ; 
277+         let  sdk_dir = match  sdk_dir { 
278+             Ok ( p)  => p, 
279+             Err ( ..)  => return  None , 
280+         } ; 
281+         ( move  || -> io:: Result < _ >  { 
282+             let  mut  max = None ; 
283+             let  mut  max_s = None ; 
284+             for  entry in  try!( fs:: read_dir ( & sdk_dir. join ( "Lib" ) ) )  { 
285+                 let  entry = try!( entry) ; 
286+                 if  let  Ok ( s)  = entry. file_name ( ) . into_string ( )  { 
287+                     if  let  Ok ( u)  = s. replace ( "." ,  "" ) . parse :: < usize > ( )  { 
288+                         if  Some ( u)  > max { 
289+                             max = Some ( u) ; 
290+                             max_s = Some ( s) ; 
291+                         } 
292+                     } 
293+                 } 
294+             } 
295+             Ok ( max_s. map ( |m| ( sdk_dir,  m) ) ) 
296+         } ) ( ) . ok ( ) . and_then ( |x| x) 
297+     } 
234298} 
235299
236300#[ cfg( not( windows) ) ]  
0 commit comments