@@ -229,27 +229,80 @@ impl TargetTriple {
229229 #[ cfg( windows) ]
230230 fn inner ( ) -> Option < TargetTriple > {
231231 use std:: mem;
232- use winapi:: um:: sysinfoapi:: GetNativeSystemInfo ;
233232
234- // First detect architecture
235- const PROCESSOR_ARCHITECTURE_AMD64 : u16 = 9 ;
236- const PROCESSOR_ARCHITECTURE_INTEL : u16 = 0 ;
237- const PROCESSOR_ARCHITECTURE_ARM64 : u16 = 12 ;
233+ /// Get the host architecture using `IsWow64Process2`. This function
234+ /// produces the most accurate results (supports detecting aarch64), but
235+ /// it is only available on Windows 10 1511+, so we use `GetProcAddress`
236+ /// to maintain backward compatibility with older Windows versions.
237+ fn arch_primary ( ) -> Option < & ' static str > {
238+ use winapi:: shared:: minwindef:: BOOL ;
239+ use winapi:: um:: libloaderapi:: { GetModuleHandleA , GetProcAddress } ;
240+ use winapi:: um:: processthreadsapi:: GetCurrentProcess ;
241+ use winapi:: um:: winnt:: HANDLE ;
242+
243+ const IMAGE_FILE_MACHINE_ARM64 : u16 = 0xAA64 ;
244+ const IMAGE_FILE_MACHINE_AMD64 : u16 = 0x8664 ;
245+ const IMAGE_FILE_MACHINE_I386 : u16 = 0x014c ;
246+
247+ #[ allow( non_snake_case) ]
248+ let IsWow64Process2 : unsafe extern "system" fn (
249+ HANDLE ,
250+ * mut u16 ,
251+ * mut u16 ,
252+ )
253+ -> BOOL = unsafe {
254+ let module = GetModuleHandleA ( b"kernel32.dll\0 " as * const u8 as * const i8 ) ;
255+ if module. is_null ( ) {
256+ return None ;
257+ }
258+ let process =
259+ GetProcAddress ( module, b"IsWow64Process2\0 " as * const u8 as * const i8 ) ;
260+ if process. is_null ( ) {
261+ return None ;
262+ }
263+ mem:: transmute ( process)
264+ } ;
238265
239- let mut sys_info;
240- unsafe {
241- sys_info = mem:: zeroed ( ) ;
242- GetNativeSystemInfo ( & mut sys_info) ;
266+ let mut _machine = 0 ;
267+ let mut native_machine = 0 ;
268+ unsafe {
269+ // cannot fail; handle does not need to be closed.
270+ let process = GetCurrentProcess ( ) ;
271+ if IsWow64Process2 ( process, & mut _machine, & mut native_machine) == 0 {
272+ return None ;
273+ }
274+ } ;
275+ match native_machine {
276+ IMAGE_FILE_MACHINE_AMD64 => Some ( "x86_64" ) ,
277+ IMAGE_FILE_MACHINE_I386 => Some ( "i686" ) ,
278+ IMAGE_FILE_MACHINE_ARM64 => Some ( "aarch64" ) ,
279+ _ => None ,
280+ }
243281 }
244282
245- let arch = match unsafe { sys_info. u . s ( ) } . wProcessorArchitecture {
246- PROCESSOR_ARCHITECTURE_AMD64 => "x86_64" ,
247- PROCESSOR_ARCHITECTURE_INTEL => "i686" ,
248- PROCESSOR_ARCHITECTURE_ARM64 => "aarch64" ,
249- _ => return None ,
250- } ;
283+ /// Get the host architecture using `GetNativeSystemInfo`.
284+ /// Does not support detecting aarch64.
285+ fn arch_fallback ( ) -> Option < & ' static str > {
286+ use winapi:: um:: sysinfoapi:: GetNativeSystemInfo ;
287+
288+ const PROCESSOR_ARCHITECTURE_AMD64 : u16 = 9 ;
289+ const PROCESSOR_ARCHITECTURE_INTEL : u16 = 0 ;
290+
291+ let mut sys_info;
292+ unsafe {
293+ sys_info = mem:: zeroed ( ) ;
294+ GetNativeSystemInfo ( & mut sys_info) ;
295+ }
296+
297+ match unsafe { sys_info. u . s ( ) } . wProcessorArchitecture {
298+ PROCESSOR_ARCHITECTURE_AMD64 => Some ( "x86_64" ) ,
299+ PROCESSOR_ARCHITECTURE_INTEL => Some ( "i686" ) ,
300+ _ => None ,
301+ }
302+ }
251303
252304 // Default to msvc
305+ let arch = arch_primary ( ) . or_else ( arch_fallback) ?;
253306 let msvc_triple = format ! ( "{}-pc-windows-msvc" , arch) ;
254307 Some ( TargetTriple ( msvc_triple) )
255308 }
@@ -328,12 +381,13 @@ impl TargetTriple {
328381 let ret = if partial_self. os != partial_other. os {
329382 false
330383 } else if partial_self. os . as_deref ( ) == Some ( "pc-windows" ) {
331- // Windows is a special case here, we know we can run 32bit on 64bit
332- // and we know we can run gnu and msvc on the same system
333- // We don't immediately assume we can cross between x86 and aarch64 though
384+ // Windows is a special case here: we can run gnu and msvc on the same system,
385+ // x86_64 can run i686, and aarch64 can run i686 through emulation
334386 ( partial_self. arch == partial_other. arch )
335387 || ( partial_self. arch . as_deref ( ) == Some ( "x86_64" )
336388 && partial_other. arch . as_deref ( ) == Some ( "i686" ) )
389+ || ( partial_self. arch . as_deref ( ) == Some ( "aarch64" )
390+ && partial_other. arch . as_deref ( ) == Some ( "i686" ) )
337391 } else {
338392 // For other OSes, for now, we assume other toolchains won't run
339393 false
0 commit comments