Merge topic 'verify-interface-header-sets-add-compile-definitions' into release-3.24

27fd172d8d VERIFY_INTERFACE_HEADER_SETS: Finalize compile info for verify targets
626e641a19 cmTarget: Factor out FinalizeTargetCompileInfo()

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !7516
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst
index 6fd3cf6..eb7da07 100644
--- a/Help/command/cmake_path.rst
+++ b/Help/command/cmake_path.rst
@@ -482,8 +482,9 @@
   cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
 
 Compares the lexical representations of two paths provided as string literals.
-No normalization is performed on either path.  Equality is determined
-according to the following pseudo-code logic:
+No normalization is performed on either path, except multiple consecutive
+directory separators are effectively collapsed into a single separator.
+Equality is determined according to the following pseudo-code logic:
 
 ::
 
diff --git a/Help/command/if.rst b/Help/command/if.rst
index c096725..301cdce 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -320,13 +320,18 @@
 .. _PATH_EQUAL:
 
 ``if(<variable|string> PATH_EQUAL <variable|string>)``
- .. versionadded:: 3.24
-  Compares the lexical representations of two paths provided as string
-  literals or variables. No normalization is performed on either path.
+  .. versionadded:: 3.24
 
-  Lexical comparison has the advantage over string comparison to have a
-  knowledge of the structure of the path. So, the following comparison is
-  ``TRUE`` using ``PATH_EQUAL`` operator, but ``FALSE`` with ``STREQUAL``:
+  Compares the two paths component-by-component.  Only if every component of
+  both paths match will the two paths compare equal.  Multiple path separators
+  are effectively collapsed into a single separator, but note that backslashes
+  are not converted to forward slashes.  No other
+  :ref:`path normalization <Normalization>` is performed.
+
+  Component-wise comparison is superior to string-based comparison due to the
+  handling of multiple path separators.  In the following example, the
+  expression evaluates to true using ``PATH_EQUAL``, but false with
+  ``STREQUAL``:
 
   .. code-block:: cmake
 
diff --git a/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst b/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst
index 30c02f5..1cf4a69 100644
--- a/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst
+++ b/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst
@@ -7,13 +7,13 @@
 header sets can be included on their own.
 
 When this property is set to true, and the target is an object library, static
-library, shared library, or executable with exports enabled, and the target
-has one or more ``PUBLIC`` or ``INTERFACE`` header sets, an object library
-target named ``<target_name>_verify_interface_header_sets`` is created. This
-verification target has one source file per header in the ``PUBLIC`` and
-``INTERFACE`` header sets. Each source file only includes its associated
-header file. The verification target links against the original target to get
-all of its usage requirements. The verification target has its
+library, shared library, interface library, or executable with exports enabled,
+and the target has one or more ``PUBLIC`` or ``INTERFACE`` header sets, an
+object library target named ``<target_name>_verify_interface_header_sets`` is
+created. This verification target has one source file per header in the
+``PUBLIC`` and ``INTERFACE`` header sets. Each source file only includes its
+associated header file. The verification target links against the original
+target to get all of its usage requirements. The verification target has its
 :prop_tgt:`EXCLUDE_FROM_ALL` and :prop_tgt:`DISABLE_PRECOMPILE_HEADERS`
 properties set to true, and its :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC`,
 :prop_tgt:`AUTOUIC`, and :prop_tgt:`UNITY_BUILD` properties set to false.
diff --git a/Help/release/3.24.rst b/Help/release/3.24.rst
index f9e66b6..02252e0 100644
--- a/Help/release/3.24.rst
+++ b/Help/release/3.24.rst
@@ -220,6 +220,10 @@
   gained a ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` option to disable
   automatic linking of MATLAB libraries.
 
+* The :module:`FindVulkan` module now supports components to select which
+  VulkanSDK tool and libraries to find in addition to the Vulkan SDK headers
+  and library.
+
 * The :module:`FindZLIB` gained a new ``ZLIB_USE_STATIC_LIBS`` variable to
   search only for static libraries.
 
diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake
index 8b322ed..2c70227 100644
--- a/Modules/FindVulkan.cmake
+++ b/Modules/FindVulkan.cmake
@@ -15,10 +15,29 @@
 
 .. versionadded:: 3.24
 
-This module respects several optional COMPONENTS: ``glslc``,
-``glslangValidator``, ``glslang``, ``shaderc_combined`` and ``SPIRV-Tools``.
-On macOS, an additional component ``MoltenVK`` is available.
-There are corresponding import targets for each of these flags.
+This module respects several optional COMPONENTS.
+There are corresponding imported targets for each of these.
+
+``glslc``
+  The SPIR-V compiler.
+
+``glslangValidator``
+  The ``glslangValidator`` tool.
+
+``glslang``
+  The SPIR-V generator library.
+
+``shaderc_combined``
+  The static library for Vulkan shader compilation.
+
+``SPIRV-Tools``
+  Tools to process SPIR-V modules.
+
+``MoltenVK``
+  On macOS, an additional component ``MoltenVK`` is available.
+
+The ``glslc`` and ``glslangValidator`` components are provided even
+if not explicitly requested (for backward compatibility).
 
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 9ffa541..edc4118 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -50,6 +50,7 @@
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateTypes.h"
+#include "cmSystemTools.h"
 #include "cmValue.h"
 #include "cmVersion.h"
 #include "cmWorkingDirectory.h"
@@ -63,10 +64,6 @@
 #  include "cmQtAutoGenGlobalInitializer.h"
 #endif
 
-#if defined(_MSC_VER) && _MSC_VER >= 1800
-#  define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-#endif
-
 const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
   "CMAKE_PLATFORM_INFO_INITIALIZED";
 
@@ -617,34 +614,12 @@
   // what platform we are running on
   if (!mf->GetDefinition("CMAKE_SYSTEM")) {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-    /* Windows version number data.  */
-    OSVERSIONINFOEXW osviex;
-    ZeroMemory(&osviex, sizeof(osviex));
-    osviex.dwOSVersionInfoSize = sizeof(osviex);
-
-#  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-#    pragma warning(push)
-#    ifdef __INTEL_COMPILER
-#      pragma warning(disable : 1478)
-#    elif defined __clang__
-#      pragma clang diagnostic push
-#      pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#    else
-#      pragma warning(disable : 4996)
-#    endif
-#  endif
-    GetVersionExW((OSVERSIONINFOW*)&osviex);
-#  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-#    ifdef __clang__
-#      pragma clang diagnostic pop
-#    else
-#      pragma warning(pop)
-#    endif
-#  endif
+    cmSystemTools::WindowsVersion windowsVersion =
+      cmSystemTools::GetWindowsVersion();
     std::ostringstream windowsVersionString;
-    windowsVersionString << osviex.dwMajorVersion << "."
-                         << osviex.dwMinorVersion << "."
-                         << osviex.dwBuildNumber;
+    windowsVersionString << windowsVersion.dwMajorVersion << "."
+                         << windowsVersion.dwMinorVersion << "."
+                         << windowsVersion.dwBuildNumber;
     mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str());
 #endif
     // Read the DetermineSystem file
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<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 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";
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 351386a..78d3ad9 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -107,6 +107,10 @@
 #  include <sys/utsname.h>
 #endif
 
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#  define CM_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+
 namespace {
 
 cmSystemTools::InterruptCallback s_InterruptCallback;
@@ -904,6 +908,40 @@
     InitWindowsDirectoryRetry().Retry;
   return retry;
 }
+
+cmSystemTools::WindowsVersion cmSystemTools::GetWindowsVersion()
+{
+  /* Windows version number data.  */
+  OSVERSIONINFOEXW osviex;
+  ZeroMemory(&osviex, sizeof(osviex));
+  osviex.dwOSVersionInfoSize = sizeof(osviex);
+
+#  ifdef CM_WINDOWS_DEPRECATED_GetVersionEx
+#    pragma warning(push)
+#    ifdef __INTEL_COMPILER
+#      pragma warning(disable : 1478)
+#    elif defined __clang__
+#      pragma clang diagnostic push
+#      pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#    else
+#      pragma warning(disable : 4996)
+#    endif
+#  endif
+  GetVersionExW((OSVERSIONINFOW*)&osviex);
+#  ifdef CM_WINDOWS_DEPRECATED_GetVersionEx
+#    ifdef __clang__
+#      pragma clang diagnostic pop
+#    else
+#      pragma warning(pop)
+#    endif
+#  endif
+
+  WindowsVersion result;
+  result.dwMajorVersion = osviex.dwMajorVersion;
+  result.dwMinorVersion = osviex.dwMinorVersion;
+  result.dwBuildNumber = osviex.dwBuildNumber;
+  return result;
+}
 #endif
 
 std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 5f7a5ec..ec650f7 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -509,6 +509,14 @@
   };
   static WindowsFileRetry GetWindowsFileRetry();
   static WindowsFileRetry GetWindowsDirectoryRetry();
+
+  struct WindowsVersion
+  {
+    unsigned int dwMajorVersion;
+    unsigned int dwMinorVersion;
+    unsigned int dwBuildNumber;
+  };
+  static WindowsVersion GetWindowsVersion();
 #endif
 
   /** Get the real path for a given path, removing all symlinks.