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
This commit is contained in:
Brad King 2022-07-26 10:27:36 -04:00
parent c508b3625a
commit 418fd85569

View File

@ -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";