Skip to content

Commit a8586d7

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

File tree

3 files changed

+88
-12
lines changed

3 files changed

+88
-12
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,10 @@ Windows.Win32.System.Com.COINIT_MULTITHREADED
1919
Windows.Win32.System.Com.CoCreateInstance
2020
Windows.Win32.System.Com.CoInitializeEx
2121

22+
Windows.Win32.System.LibraryLoader.FreeLibrary
23+
Windows.Win32.System.LibraryLoader.GetProcAddress
24+
Windows.Win32.System.LibraryLoader.LoadLibraryA
25+
2226
Windows.Win32.System.Pipes.PeekNamedPipe
2327

2428
Windows.Win32.System.Registry.RegCloseKey
@@ -31,9 +35,12 @@ Windows.Win32.System.Registry.KEY_READ
3135
Windows.Win32.System.Registry.KEY_WOW64_32KEY
3236
Windows.Win32.System.Registry.REG_SZ
3337

38+
Windows.Win32.System.SystemInformation.IMAGE_FILE_MACHINE_AMD64
39+
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: 63 additions & 12 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+
FreeLibrary, GetProcAddress, LoadLibraryA, UserEnabled, HMODULE, HRESULT,
168+
IMAGE_FILE_MACHINE_AMD64, MACHINE_ATTRIBUTES, S_OK,
169+
};
166170
use std::convert::TryFrom;
167171
use std::env;
168172
use std::ffi::OsString;
@@ -199,6 +203,47 @@ mod impl_ {
199203
include: Vec<PathBuf>,
200204
}
201205

206+
struct LibraryHandle(HMODULE);
207+
208+
impl LibraryHandle {
209+
fn new(name: &[u8]) -> Option<Self> {
210+
let handle = unsafe { LoadLibraryA(name.as_ptr() as _) };
211+
(!handle.is_null()).then(|| Self(handle))
212+
}
213+
}
214+
215+
impl Drop for LibraryHandle {
216+
fn drop(&mut self) {
217+
unsafe { FreeLibrary(self.0) };
218+
}
219+
}
220+
221+
fn is_amd64_emulation_supported() -> bool {
222+
let kernel32 = LibraryHandle::new(b"kernel32.dll\0").unwrap();
223+
// GetMachineTypeAttributes is only available on Win11 22000+.
224+
if let Some(get_machine_type_attributes) =
225+
unsafe { GetProcAddress(kernel32.0, b"GetMachineTypeAttributes\0".as_ptr() as _) }
226+
{
227+
// SAFETY: We are getting a function pointer to GetMachineTypeAttributes and then transmuting it to match
228+
// the signature that windows-sys would generate: https://docs.rs/windows-sys/0.52.0/windows_sys/Win32/System/Threading/fn.GetMachineTypeAttributes.html
229+
type GetMachineTypeAttributesFuncType =
230+
unsafe extern "system" fn(u16, *mut MACHINE_ATTRIBUTES) -> HRESULT;
231+
let get_machine_type_attributes: GetMachineTypeAttributesFuncType =
232+
unsafe { std::mem::transmute_copy(&get_machine_type_attributes) };
233+
234+
let mut attributes = Default::default();
235+
if unsafe { get_machine_type_attributes(IMAGE_FILE_MACHINE_AMD64, &mut attributes) }
236+
== S_OK
237+
{
238+
(attributes & UserEnabled) != 0
239+
} else {
240+
false
241+
}
242+
} else {
243+
false
244+
}
245+
}
246+
202247
impl MsvcTool {
203248
fn new(tool: PathBuf) -> MsvcTool {
204249
MsvcTool {
@@ -226,7 +271,6 @@ mod impl_ {
226271

227272
/// Checks to see if the `VSCMD_ARG_TGT_ARCH` environment variable matches the
228273
/// given target's arch. Returns `None` if the variable does not exist.
229-
#[cfg(windows)]
230274
fn is_vscmd_target(target: TargetArch<'_>) -> Option<bool> {
231275
let vscmd_arch = env::var("VSCMD_ARG_TGT_ARCH").ok()?;
232276
// Convert the Rust target arch to its VS arch equivalent.
@@ -483,34 +527,41 @@ mod impl_ {
483527
let version = vs15plus_vc_read_version(instance_path)?;
484528

485529
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"],
530+
X86 => &["X86"],
531+
X86_64 => &["X64"],
532+
// Starting with VS 17.4, there is a natively hosted compiler on ARM64:
533+
// https://devblogs.microsoft.com/visualstudio/arm64-visual-studio-is-officially-here/
534+
// On older versions of VS, we use x64 if running under emulation is supported,
535+
// otherwise use x86.
536+
AARCH64 => {
537+
if is_amd64_emulation_supported() {
538+
&["ARM64", "X64", "X86"][..]
539+
} else {
540+
&["ARM64", "X86"]
541+
}
542+
}
492543
_ => return None,
493544
};
494545
let target = lib_subdir(target)?;
495546
// The directory layout here is MSVC/bin/Host$host/$target/
496547
let path = instance_path.join(r"VC\Tools\MSVC").join(version);
497548
// We use the first available host architecture that can build for the target
498549
let (host_path, host) = hosts.iter().find_map(|&x| {
499-
let candidate = path.join("bin").join(&format!("Host{}", x));
500-
if candidate.join(&target).exists() {
550+
let candidate = path.join("bin").join(format!("Host{}", x));
551+
if candidate.join(target).exists() {
501552
Some((candidate, x))
502553
} else {
503554
None
504555
}
505556
})?;
506557
// This is the path to the toolchain for a particular target, running
507558
// on a given host
508-
let bin_path = host_path.join(&target);
559+
let bin_path = host_path.join(target);
509560
// But! we also need PATH to contain the target directory for the host
510561
// architecture, because it contains dlls like mspdb140.dll compiled for
511562
// the host architecture.
512-
let host_dylib_path = host_path.join(&host.to_lowercase());
513-
let lib_path = path.join("lib").join(&target);
563+
let host_dylib_path = host_path.join(host.to_lowercase());
564+
let lib_path = path.join("lib").join(target);
514565
let alt_lib_path = (target == "arm64ec").then(|| path.join("lib").join("arm64ec"));
515566
let include_path = path.join("include");
516567
Some((

src/windows/windows_sys.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ extern "system" {
5454
) -> WIN32_ERROR;
5555
}
5656
#[link(name = "kernel32")]
57+
extern "system" {
58+
pub fn FreeLibrary(hlibmodule: HMODULE) -> BOOL;
59+
}
60+
#[link(name = "kernel32")]
61+
extern "system" {
62+
pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
63+
}
64+
#[link(name = "kernel32")]
65+
extern "system" {
66+
pub fn LoadLibraryA(lplibfilename: PCSTR) -> HMODULE;
67+
}
68+
#[link(name = "kernel32")]
5769
extern "system" {
5870
pub fn OpenSemaphoreA(dwdesiredaccess: u32, binherithandle: BOOL, lpname: PCSTR) -> HANDLE;
5971
}
@@ -112,6 +124,7 @@ pub const COINIT_MULTITHREADED: COINIT = 0i32;
112124
pub const ERROR_NO_MORE_ITEMS: WIN32_ERROR = 259u32;
113125
pub const ERROR_SUCCESS: WIN32_ERROR = 0u32;
114126
pub const FALSE: BOOL = 0i32;
127+
pub type FARPROC = ::core::option::Option<unsafe extern "system" fn() -> isize>;
115128
#[repr(C)]
116129
pub struct FILETIME {
117130
pub dwLowDateTime: u32,
@@ -149,10 +162,14 @@ impl ::core::clone::Clone for GUID {
149162
pub type HANDLE = *mut ::core::ffi::c_void;
150163
pub type HKEY = *mut ::core::ffi::c_void;
151164
pub const HKEY_LOCAL_MACHINE: HKEY = invalid_mut(-2147483646i32 as _);
165+
pub type HMODULE = *mut ::core::ffi::c_void;
152166
pub type HRESULT = i32;
167+
pub type IMAGE_FILE_MACHINE = u16;
168+
pub const IMAGE_FILE_MACHINE_AMD64: IMAGE_FILE_MACHINE = 34404u16;
153169
pub type IUnknown = *mut ::core::ffi::c_void;
154170
pub const KEY_READ: REG_SAM_FLAGS = 131097u32;
155171
pub const KEY_WOW64_32KEY: REG_SAM_FLAGS = 512u32;
172+
pub type MACHINE_ATTRIBUTES = i32;
156173
pub type PCSTR = *const u8;
157174
pub type PCWSTR = *const u16;
158175
pub type PWSTR = *mut u16;
@@ -191,6 +208,7 @@ pub const S_FALSE: HRESULT = 1i32;
191208
pub const S_OK: HRESULT = 0i32;
192209
pub type THREAD_ACCESS_RIGHTS = u32;
193210
pub const THREAD_SYNCHRONIZE: THREAD_ACCESS_RIGHTS = 1048576u32;
211+
pub const UserEnabled: MACHINE_ATTRIBUTES = 1i32;
194212
pub const WAIT_ABANDONED: WIN32_ERROR = 128u32;
195213
pub const WAIT_FAILED: WIN32_ERROR = 4294967295u32;
196214
pub const WAIT_OBJECT_0: WIN32_ERROR = 0u32;

0 commit comments

Comments
 (0)