Skip to content

Commit 41f9b14

Browse files
committed
Add support for Native ARM64 and x64 if available
1 parent 29d95b5 commit 41f9b14

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

dev-tools/gen-windows-sys-binding/windows_sys.list

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Windows.Win32.System.Com.COINIT_MULTITHREADED
1919
Windows.Win32.System.Com.CoCreateInstance
2020
Windows.Win32.System.Com.CoInitializeEx
2121

22+
Windows.Win32.System.LibraryLoader.GetProcAddress
23+
Windows.Win32.System.LibraryLoader.LoadLibraryA
24+
2225
Windows.Win32.System.Pipes.PeekNamedPipe
2326

2427
Windows.Win32.System.Registry.RegCloseKey
@@ -31,9 +34,13 @@ Windows.Win32.System.Registry.KEY_READ
3134
Windows.Win32.System.Registry.KEY_WOW64_32KEY
3235
Windows.Win32.System.Registry.REG_SZ
3336

37+
Windows.Win32.System.SystemInformation.IMAGE_FILE_MACHINE_AMD64
38+
39+
Windows.Win32.System.Threading.GetMachineTypeAttributes
3440
Windows.Win32.System.Threading.ReleaseSemaphore
3541
Windows.Win32.System.Threading.WaitForSingleObject
3642
Windows.Win32.System.Threading.SEMAPHORE_MODIFY_STATE
3743
Windows.Win32.System.Threading.THREAD_SYNCHRONIZE
44+
Windows.Win32.System.Threading.UserEnabled
3845

3946
Windows.Win32.System.WindowsProgramming.OpenSemaphoreA

src/windows/find_tools.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ mod impl_ {
163163
use crate::windows::registry::{RegistryKey, LOCAL_MACHINE};
164164
use crate::windows::setup_config::SetupConfiguration;
165165
use crate::windows::vs_instances::{VsInstances, VswhereInstance};
166+
use crate::windows::windows_sys::{
167+
GetMachineTypeAttributes, GetProcAddress, LoadLibraryA, UserEnabled,
168+
IMAGE_FILE_MACHINE_AMD64, S_OK,
169+
};
166170
use std::convert::TryFrom;
167171
use std::env;
168172
use std::ffi::OsString;
@@ -199,6 +203,35 @@ mod impl_ {
199203
include: Vec<PathBuf>,
200204
}
201205

206+
unsafe fn cast_to_function<F: Sized>(
207+
raw_func: unsafe extern "system" fn() -> isize,
208+
_func_type: &F,
209+
) -> F {
210+
std::mem::transmute_copy(&raw_func)
211+
}
212+
213+
fn is_amd64_emulation_supported() -> bool {
214+
// In theory we should free the library handle, but since kernel32.dll is loaded in every
215+
// process and we're a short-lived process, leaking the handles doesn't matter.
216+
let kernel32 = unsafe { LoadLibraryA(b"kernel32.dll\0".as_ptr() as _) };
217+
if let Some(get_machine_type_attributes) =
218+
unsafe { GetProcAddress(kernel32, b"GetMachineTypeAttributes\0".as_ptr() as _) }
219+
{
220+
let mut attributes = Default::default();
221+
let get_machine_type_attributes =
222+
unsafe { cast_to_function(get_machine_type_attributes, &GetMachineTypeAttributes) };
223+
if unsafe {
224+
get_machine_type_attributes(IMAGE_FILE_MACHINE_AMD64, &mut attributes) == S_OK
225+
} {
226+
(attributes & UserEnabled) != 0
227+
} else {
228+
false
229+
}
230+
} else {
231+
false
232+
}
233+
}
234+
202235
impl MsvcTool {
203236
fn new(tool: PathBuf) -> MsvcTool {
204237
MsvcTool {
@@ -226,7 +259,6 @@ mod impl_ {
226259

227260
/// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the
228261
/// given target's arch. Returns `None` if the variable does not exist.
229-
#[cfg(windows)]
230262
fn is_vscmd_target(target: TargetArch<'_>) -> Option<bool> {
231263
let vscmd_arch = env::var("VSCMD_ARG_TGT_ARCH").ok()?;
232264
// Convert the Rust target arch to its VS arch equivalent.
@@ -482,13 +514,21 @@ mod impl_ {
482514
) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf, Option<PathBuf>, PathBuf)> {
483515
let version = vs15plus_vc_read_version(instance_path)?;
484516

517+
let _ = is_amd64_emulation_supported();
485518
let hosts = match host_arch() {
486-
X86 => vec!["X86"],
487-
X86_64 => vec!["X64"],
488-
// Starting with VS 17.3, there is a natively hosted compiler on ARM64.
489-
// On older versions of VS, we use the x86 toolchain under emulation.
490-
// We don't want to overcomplicate compatibility checks, so we ignore x64 emulation.
491-
AARCH64 => vec!["ARM64", "X86"],
519+
X86 => &["X86"],
520+
X86_64 => &["X64"],
521+
// Starting with VS 17.4, there is a natively hosted compiler on ARM64:
522+
// https://devblogs.microsoft.com/visualstudio/arm64-visual-studio-is-officially-here/
523+
// On older versions of VS, we use x64 if running under emulation is supported,
524+
// otherwise use x86.
525+
AARCH64 => {
526+
if is_amd64_emulation_supported() {
527+
&["ARM64", "X64", "X86"][..]
528+
} else {
529+
&["ARM64", "X86"]
530+
}
531+
}
492532
_ => return None,
493533
};
494534
let target = lib_subdir(target)?;

src/windows/windows_sys.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ extern "system" {
5454
) -> WIN32_ERROR;
5555
}
5656
#[link(name = "kernel32")]
57+
extern "system" {
58+
pub fn GetMachineTypeAttributes(
59+
machine: u16,
60+
machinetypeattributes: *mut MACHINE_ATTRIBUTES,
61+
) -> HRESULT;
62+
}
63+
#[link(name = "kernel32")]
64+
extern "system" {
65+
pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
66+
}
67+
#[link(name = "kernel32")]
68+
extern "system" {
69+
pub fn LoadLibraryA(lplibfilename: PCSTR) -> HMODULE;
70+
}
71+
#[link(name = "kernel32")]
5772
extern "system" {
5873
pub fn OpenSemaphoreA(dwdesiredaccess: u32, binherithandle: BOOL, lpname: PCSTR) -> HANDLE;
5974
}
@@ -112,6 +127,7 @@ pub const COINIT_MULTITHREADED: COINIT = 0i32;
112127
pub const ERROR_NO_MORE_ITEMS: WIN32_ERROR = 259u32;
113128
pub const ERROR_SUCCESS: WIN32_ERROR = 0u32;
114129
pub const FALSE: BOOL = 0i32;
130+
pub type FARPROC = ::core::option::Option<unsafe extern "system" fn() -> isize>;
115131
#[repr(C)]
116132
pub struct FILETIME {
117133
pub dwLowDateTime: u32,
@@ -149,10 +165,14 @@ impl ::core::clone::Clone for GUID {
149165
pub type HANDLE = *mut ::core::ffi::c_void;
150166
pub type HKEY = *mut ::core::ffi::c_void;
151167
pub const HKEY_LOCAL_MACHINE: HKEY = invalid_mut(-2147483646i32 as _);
168+
pub type HMODULE = *mut ::core::ffi::c_void;
152169
pub type HRESULT = i32;
170+
pub type IMAGE_FILE_MACHINE = u16;
171+
pub const IMAGE_FILE_MACHINE_AMD64: IMAGE_FILE_MACHINE = 34404u16;
153172
pub type IUnknown = *mut ::core::ffi::c_void;
154173
pub const KEY_READ: REG_SAM_FLAGS = 131097u32;
155174
pub const KEY_WOW64_32KEY: REG_SAM_FLAGS = 512u32;
175+
pub type MACHINE_ATTRIBUTES = i32;
156176
pub type PCSTR = *const u8;
157177
pub type PCWSTR = *const u16;
158178
pub type PWSTR = *mut u16;
@@ -191,6 +211,7 @@ pub const S_FALSE: HRESULT = 1i32;
191211
pub const S_OK: HRESULT = 0i32;
192212
pub type THREAD_ACCESS_RIGHTS = u32;
193213
pub const THREAD_SYNCHRONIZE: THREAD_ACCESS_RIGHTS = 1048576u32;
214+
pub const UserEnabled: MACHINE_ATTRIBUTES = 1i32;
194215
pub const WAIT_ABANDONED: WIN32_ERROR = 128u32;
195216
pub const WAIT_FAILED: WIN32_ERROR = 4294967295u32;
196217
pub const WAIT_OBJECT_0: WIN32_ERROR = 0u32;

0 commit comments

Comments
 (0)