From 418fd8556918fa5639d79aca832f0213fb359a02 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 26 Jul 2022 10:27:36 -0400 Subject: 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 --- Source/cmGlobalVisualStudioVersionedGenerator.cxx | 126 +++++++++++++++------- 1 file changed, 90 insertions(+), 36 deletions(-) diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index b72fc4e..7eca963 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(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"; -- cgit v0.12