summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2022-07-26 10:27:36 -0400
committerBrad King <brad.king@kitware.com>2022-07-27 07:40:46 -0400
commit418fd8556918fa5639d79aca832f0213fb359a02 (patch)
tree6b296b6ec2ccc44782ab4a979a5fecc328115655
parentc508b3625a198cfe4b2f8fbf4acdc2127a28f2cb (diff)
downloadcmake-418fd8556918fa5639d79aca832f0213fb359a02.tar.gz
VS: Detect ARM64 host architecture at runtime
We use the host machine's architecture to select the `MSBuild.exe` binary variant, and the host toolset architecture. When CMake is compiled as `x64` or `x86` it may still run on ARM64 hosts. Detect the actual architecture of the host at runtime instead of relying on the architecture of CMake's own binary. The `arm64/MSBuild.exe` executable is an ARM64 .NET 4 application, which requires the ARM64 version of .NET Framework 4.8.1 to be installed on the machine. That version is not yet released for Windows 10; however, the `MSBuild/Current/Bin/arm64` directory is still created when installing Visual Studio 2022 (a user may upgrade to Windows 11 later). Use it only if the .NET Framework is installed. The `amd64/MSBuild.exe` executable cannot run on Windows 10 ARM64, but can run on Windows 11 ARM64. Fixes: #23755
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx126
1 files changed, 90 insertions, 36 deletions
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index b72fc4e80f..7eca96399c 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -25,53 +25,100 @@
#include "cmVSSetupHelper.h"
#include "cmake.h"
-#if defined(_M_ARM64)
-# define HOST_PLATFORM_NAME "ARM64"
-# define HOST_TOOLS_ARCH(v) \
- (v >= cmGlobalVisualStudioGenerator::VSVersion::VS17) ? "ARM64" : ""
-#elif defined(_M_ARM)
-# define HOST_PLATFORM_NAME "ARM"
-# define HOST_TOOLS_ARCH(v) ""
-#elif defined(_M_IA64)
-# define HOST_PLATFORM_NAME "Itanium"
-# define HOST_TOOLS_ARCH(v) ""
-#elif defined(_WIN64)
-# define HOST_PLATFORM_NAME "x64"
-# define HOST_TOOLS_ARCH(v) "x64"
-#else
+#ifndef IMAGE_FILE_MACHINE_ARM64
+# define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian
+#endif
+
static bool VSIsWow64()
{
BOOL isWow64 = false;
return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64;
}
+
+static bool VSIsArm64Host()
+{
+ typedef BOOL(WINAPI * CM_ISWOW64PROCESS2)(
+ HANDLE hProcess, USHORT * pProcessMachine, USHORT * pNativeMachine);
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# define CM_VS_GCC_DIAGNOSTIC_PUSHED
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
+ static const CM_ISWOW64PROCESS2 s_IsWow64Process2Impl =
+ (CM_ISWOW64PROCESS2)GetProcAddress(
+ GetModuleHandleW(L"api-ms-win-core-wow64-l1-1-1.dll"),
+ "IsWow64Process2");
+#ifdef CM_VS_GCC_DIAGNOSTIC_PUSHED
+# pragma GCC diagnostic pop
+# undef CM_VS_GCC_DIAGNOSTIC_PUSHED
+#endif
+
+ USHORT processMachine, nativeMachine;
+
+ return s_IsWow64Process2Impl != nullptr &&
+ s_IsWow64Process2Impl(GetCurrentProcess(), &processMachine,
+ &nativeMachine) &&
+ nativeMachine == IMAGE_FILE_MACHINE_ARM64;
+}
+
+static bool VSHasDotNETFrameworkArm64()
+{
+ std::string dotNetArm64;
+ return cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\.NETFramework;InstallRootArm64",
+ dotNetArm64);
+}
+
+static bool VSIsWindows11OrGreater()
+{
+ cmSystemTools::WindowsVersion const windowsVersion =
+ cmSystemTools::GetWindowsVersion();
+ return (windowsVersion.dwMajorVersion > 10 ||
+ (windowsVersion.dwMajorVersion == 10 &&
+ windowsVersion.dwMinorVersion > 0) ||
+ (windowsVersion.dwMajorVersion == 10 &&
+ windowsVersion.dwMinorVersion == 0 &&
+ windowsVersion.dwBuildNumber >= 22000));
+}
static std::string VSHostPlatformName()
{
-#ifdef HOST_PLATFORM_NAME
- return HOST_PLATFORM_NAME;
-#else
- if (VSIsWow64()) {
+ if (VSIsArm64Host()) {
+ return "ARM64";
+ } else if (VSIsWow64()) {
return "x64";
} else {
+#if defined(_M_ARM)
+ return "ARM";
+#elif defined(_M_IA64)
+ return "Itanium";
+#elif defined(_WIN64)
+ return "x64";
+#else
return "Win32";
- }
#endif
+ }
}
static std::string VSHostArchitecture(
cmGlobalVisualStudioGenerator::VSVersion v)
{
- static_cast<void>(v);
-#ifdef HOST_TOOLS_ARCH
- return HOST_TOOLS_ARCH(v);
-#else
- if (VSIsWow64()) {
+ if (VSIsArm64Host()) {
+ return v >= cmGlobalVisualStudioGenerator::VSVersion::VS17 ? "ARM64" : "";
+ } else if (VSIsWow64()) {
return "x64";
} else {
+#if defined(_M_ARM)
+ return "";
+#elif defined(_M_IA64)
+ return "";
+#elif defined(_WIN64)
+ return "x64";
+#else
return "x86";
- }
#endif
+ }
}
static unsigned int VSVersionToMajor(
@@ -899,17 +946,24 @@ std::string cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommand()
std::string vs;
if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS17) {
-#if defined(_M_ARM64)
- std::string msbuild_arm64 =
- vs + "/MSBuild/Current/Bin/arm64/MSBuild.exe";
- if (cmSystemTools::FileExists(msbuild_arm64)) {
- return msbuild_arm64;
- }
-#endif
-
- msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
- if (cmSystemTools::FileExists(msbuild)) {
- return msbuild;
+ if (VSIsArm64Host()) {
+ if (VSHasDotNETFrameworkArm64()) {
+ msbuild = vs + "/MSBuild/Current/Bin/arm64/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
+ }
+ if (VSIsWindows11OrGreater()) {
+ msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
+ }
+ } else {
+ msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
}
}
msbuild = vs + "/MSBuild/Current/Bin/MSBuild.exe";