Browse Source

Merge branch 'backport-vs-sdk-selection' into vs-sdk-selection

Brad King 2 years ago
parent
commit
d5118ed2e5

+ 17 - 1
Help/release/3.27.rst

@@ -33,7 +33,7 @@ Generators
   linker will cause a relink if they change (typically modified timestamps).
   See the :variable:`CMAKE_LINK_DEPENDS_USE_LINKER` variable.
 
-* The :ref:`Visual Studio Generators` for VS 2015 and above learned to
+* The :ref:`Visual Studio Generators` for VS 14 (2015) and above learned to
   select the Windows SDK version explicitly using a ``version=`` field
   in the :variable:`CMAKE_GENERATOR_PLATFORM` variable.
   See :ref:`Visual Studio Platform Selection`.
@@ -257,6 +257,9 @@ Other Changes
 * :ref:`Visual Studio Generators`, for VS 15.8 (2017) and newer, now
   build custom commands in parallel.  See policy :policy:`CMP0147`.
 
+* :ref:`Visual Studio Generators` for VS 14 (2015) and above now prefer
+  to select the latest Windows SDK version.  See policy :policy:`CMP0149`.
+
 Updates
 =======
 
@@ -268,3 +271,16 @@ Changes made since CMake 3.27.0 include the following.
 * This version made no changes to documented features or interfaces.
   Some implementation updates were made to support ecosystem changes
   and/or fix regressions.
+
+3.27.2
+------
+
+* :ref:`Visual Studio Generators` for VS 14 (2015) and above now prefer to
+  select the latest Windows SDK, as documented by policy :policy:`CMP0149`,
+  when targeting any version of Windows.  In CMake 3.27.[0-1] the
+  preference was limited to targeting Windows 10 and above.
+
+* :ref:`Visual Studio Generators` for VS 14 (2015) and above now support
+  using ``version=8.1`` in the :variable:`CMAKE_GENERATOR_PLATFORM` variable
+  to select the Windows 8.1 SDK.  In CMake 3.27.[0-1] the ``version=`` field
+  was limited to selecting Windows 10 SDKs.

+ 5 - 1
Help/variable/CMAKE_GENERATOR_PLATFORM.rst

@@ -50,7 +50,7 @@ Supported pairs are:
   .. versionadded:: 3.27
 
   Specify the Windows SDK version to use.  This is supported by VS 2015 and
-  above when targeting Windows 10.0+ or Windows Store.  CMake will set the
+  above when targeting Windows or Windows Store.  CMake will set the
   :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable to the
   selected SDK version.
 
@@ -66,6 +66,10 @@ Supported pairs are:
     the value of :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM`,
     if that variable is set.
 
+  ``8.1``
+    Specify the 8.1 SDK version.  This is always supported by VS 2015.
+    On VS 2017 and above the 8.1 SDK must be installed.
+
   If the ``version`` field is not specified, CMake selects a version as
   described in the :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION`
   variable documentation.

+ 1 - 1
Source/cmGlobalVisualStudio10Generator.cxx

@@ -548,7 +548,7 @@ bool cmGlobalVisualStudio10Generator::InitializePlatformWindows(cmMakefile*)
 }
 
 bool cmGlobalVisualStudio10Generator::VerifyNoGeneratorPlatformVersion(
-  cmMakefile*, cm::optional<std::string>) const
+  cmMakefile*) const
 {
   return true;
 }

+ 1 - 2
Source/cmGlobalVisualStudio10Generator.h

@@ -187,8 +187,7 @@ protected:
 
   bool InitializePlatform(cmMakefile* mf) override;
   virtual bool InitializePlatformWindows(cmMakefile* mf);
-  virtual bool VerifyNoGeneratorPlatformVersion(
-    cmMakefile* mf, cm::optional<std::string> reason = cm::nullopt) const;
+  virtual bool VerifyNoGeneratorPlatformVersion(cmMakefile* mf) const;
 
   virtual bool ProcessGeneratorToolsetField(std::string const& key,
                                             std::string const& value);

+ 99 - 27
Source/cmGlobalVisualStudio14Generator.cxx

@@ -141,14 +141,103 @@ bool cmGlobalVisualStudio14Generator::MatchesGeneratorName(
 
 bool cmGlobalVisualStudio14Generator::InitializePlatformWindows(cmMakefile* mf)
 {
-  if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
+  // If a Windows SDK version is explicitly requested, search for it.
+  if (this->GeneratorPlatformVersion) {
+    std::string const& version = *this->GeneratorPlatformVersion;
+
+    // VS 2019 and above support specifying plain "10.0".
+    if (version == "10.0"_s) {
+      if (this->Version >= VSVersion::VS16) {
+        this->SetWindowsTargetPlatformVersion("10.0", mf);
+        return true;
+      }
+      /* clang-format off */
+      mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat(
+          "Generator\n"
+          "  ", this->GetName(), "\n"
+          "given platform specification containing a\n"
+          "  version=10.0\n"
+          "field.  The value 10.0 is only supported by VS 2019 and above.\n"
+          ));
+      /* clang-format on */
+      return false;
+    }
+
+    if (cmHasLiteralPrefix(version, "10.0.")) {
+      return this->SelectWindows10SDK(mf);
+    }
+
+    if (version == "8.1"_s) {
+      if (this->IsWin81SDKInstalled()) {
+        this->SetWindowsTargetPlatformVersion("8.1", mf);
+        return true;
+      }
+      /* clang-format off */
+      mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat(
+          "Generator\n"
+          "  ", this->GetName(), "\n"
+          "given platform specification containing a\n"
+          "  version=8.1\n"
+          "field, but the Windows 8.1 SDK is not installed.\n"
+          ));
+      /* clang-format on */
+      return false;
+    }
+
+    if (version.empty()) {
+      /* clang-format off */
+      mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat(
+          "Generator\n"
+          "  ", this->GetName(), "\n"
+          "given platform specification with empty\n"
+          "  version=\n"
+          "field.\n"
+          ));
+      /* clang-format on */
+      return false;
+    }
+
+    /* clang-format off */
+    mf->IssueMessage(MessageType::FATAL_ERROR, cmStrCat(
+        "Generator\n"
+        "  ", this->GetName(), "\n"
+        "given platform specification containing a\n"
+        "  version=", version, "\n"
+        "field with unsupported value.\n"
+        ));
+    /* clang-format on */
+    return false;
+  }
+
+  // If we are targeting Windows 10+, we select a Windows 10 SDK.
+  // If no Windows 8.1 SDK is installed, which is possible with VS 2017 and
+  // higher, then we must choose a Windows 10 SDK anyway.
+  if (cmHasLiteralPrefix(this->SystemVersion, "10.0") ||
+      !this->IsWin81SDKInstalled()) {
     return this->SelectWindows10SDK(mf);
   }
-  return this->VerifyNoGeneratorPlatformVersion(mf);
+
+  // Under CMP0149 NEW behavior, we search for a Windows 10 SDK even
+  // when targeting older Windows versions, but it is not required.
+  if (mf->GetPolicyStatus(cmPolicies::CMP0149) == cmPolicies::NEW) {
+    std::string const version = this->GetWindows10SDKVersion(mf);
+    if (!version.empty()) {
+      this->SetWindowsTargetPlatformVersion(version, mf);
+      return true;
+    }
+  }
+
+  // We are not targeting Windows 10+, so fall back to the Windows 8.1 SDK.
+  // For VS 2019 and above we must explicitly specify it.
+  if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 &&
+      !cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) {
+    this->SetWindowsTargetPlatformVersion("8.1", mf);
+  }
+  return true;
 }
 
 bool cmGlobalVisualStudio14Generator::VerifyNoGeneratorPlatformVersion(
-  cmMakefile* mf, cm::optional<std::string> reason) const
+  cmMakefile* mf) const
 {
   if (!this->GeneratorPlatformVersion) {
     return true;
@@ -164,9 +253,6 @@ bool cmGlobalVisualStudio14Generator::VerifyNoGeneratorPlatformVersion(
     "  " << this->SystemName << ' ' << this->SystemVersion << '\n'
     ;
   /* clang-format on */
-  if (reason) {
-    e << *reason << '.';
-  }
   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
   return false;
 }
@@ -210,16 +296,6 @@ bool cmGlobalVisualStudio14Generator::ProcessGeneratorPlatformField(
 
 bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf)
 {
-  if (this->GeneratorPlatformVersion &&
-      this->GeneratorPlatformVersion->empty()) {
-    mf->IssueMessage(
-      MessageType::FATAL_ERROR,
-      cmStrCat("Generator\n  ", this->GetName(),
-               "\ngiven platform specification with empty\n  version=\n"
-               "field."));
-    return false;
-  }
-
   // Find the default version of the Windows 10 SDK.
   std::string const version = this->GetWindows10SDKVersion(mf);
 
@@ -251,7 +327,8 @@ void cmGlobalVisualStudio14Generator::SetWindowsTargetPlatformVersion(
   std::string const& version, cmMakefile* mf)
 {
   this->WindowsTargetPlatformVersion = version;
-  if (!cmSystemTools::VersionCompareEqual(this->WindowsTargetPlatformVersion,
+  if (!this->WindowsTargetPlatformVersion.empty() &&
+      !cmSystemTools::VersionCompareEqual(this->WindowsTargetPlatformVersion,
                                           this->SystemVersion)) {
     mf->DisplayStatus(cmStrCat("Selecting Windows SDK version ",
                                this->WindowsTargetPlatformVersion,
@@ -299,6 +376,11 @@ bool cmGlobalVisualStudio14Generator::IsWindowsStoreToolsetInstalled() const
                                           cmSystemTools::KeyWOW64_32);
 }
 
+bool cmGlobalVisualStudio14Generator::IsWin81SDKInstalled() const
+{
+  return true;
+}
+
 std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion(
   cmMakefile* mf) const
 {
@@ -360,16 +442,6 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion(
   cmMakefile* mf)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-  // Accept specific version requests as-is.
-  if (this->GeneratorPlatformVersion) {
-    std::string const& ver = *this->GeneratorPlatformVersion;
-
-    // VS 2019 and above support specifying plain "10.0".
-    if (this->Version >= VSVersion::VS16 && ver == "10.0"_s) {
-      return ver;
-    }
-  }
-
   std::vector<std::string> win10Roots;
 
   {

+ 3 - 3
Source/cmGlobalVisualStudio14Generator.h

@@ -40,10 +40,10 @@ protected:
   // of the toolset is installed
   bool IsWindowsStoreToolsetInstalled() const;
 
+  virtual bool IsWin81SDKInstalled() const;
+
   bool InitializePlatformWindows(cmMakefile* mf) override;
-  bool VerifyNoGeneratorPlatformVersion(
-    cmMakefile* mf,
-    cm::optional<std::string> reason = cm::nullopt) const override;
+  bool VerifyNoGeneratorPlatformVersion(cmMakefile* mf) const override;
 
   bool ProcessGeneratorPlatformField(std::string const& key,
                                      std::string const& value) override;

+ 0 - 20
Source/cmGlobalVisualStudioVersionedGenerator.cxx

@@ -892,26 +892,6 @@ cmGlobalVisualStudioVersionedGenerator::FindAuxToolset(
   return AuxToolset::PropsMissing;
 }
 
-bool cmGlobalVisualStudioVersionedGenerator::InitializePlatformWindows(
-  cmMakefile* mf)
-{
-  // If the Win 8.1 SDK is installed then we can select a SDK matching
-  // the target Windows version.
-  if (this->IsWin81SDKInstalled()) {
-    // VS 2019 does not default to 8.1 so specify it explicitly when needed.
-    if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 &&
-        !cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) {
-      this->SetWindowsTargetPlatformVersion("8.1", mf);
-      return this->VerifyNoGeneratorPlatformVersion(
-        mf, "with the Windows 8.1 SDK installed");
-    }
-    return cmGlobalVisualStudio14Generator::InitializePlatformWindows(mf);
-  }
-  // Otherwise we must choose a Win 10 SDK even if we are not targeting
-  // Windows 10.
-  return this->SelectWindows10SDK(mf);
-}
-
 bool cmGlobalVisualStudioVersionedGenerator::SelectWindowsStoreToolset(
   std::string& toolset) const
 {

+ 1 - 3
Source/cmGlobalVisualStudioVersionedGenerator.h

@@ -72,10 +72,8 @@ protected:
   // of the toolset is installed
   bool IsWindowsStoreToolsetInstalled() const;
 
-  bool InitializePlatformWindows(cmMakefile* mf) override;
-
   // Check for a Win 8 SDK known to the registry or VS installer tool.
-  bool IsWin81SDKInstalled() const;
+  bool IsWin81SDKInstalled() const override;
 
   std::string GetWindows10SDKMaxVersionDefault(cmMakefile*) const override;
 

+ 1 - 1
Tests/RunCMake/GeneratorPlatform/BadVersionMissing-stderr.txt

@@ -6,6 +6,6 @@
 
   given platform specification with
 
-    version=1\.2\.3\.4
+    version=10\.0\.0\.0
 
   field, but no Windows SDK with that version was found\.$

+ 0 - 19
Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-stderr.txt

@@ -1,19 +0,0 @@
-^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
-  Generator
-
-    Visual Studio [^
-]+
-
-  given platform specification (containing a
-
-    version=8\.1
-
-  field\.  The version field is not supported when targeting
-
-    Windows 8\.1(
-
-  with the Windows 8\.1 SDK installed\.)?|with
-
-    version=8\.1
-
-  field, but no Windows SDK with that version was found\.)$

+ 0 - 0
Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-result.txt → Tests/RunCMake/GeneratorPlatform/BadVersionPre2019-result.txt


+ 11 - 0
Tests/RunCMake/GeneratorPlatform/BadVersionPre2019-stderr.txt

@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    Visual Studio [^
+]+
+
+  given platform specification containing a
+
+    version=10\.0
+
+  field\.  The value 10\.0 is only supported by VS 2019 and above\.$

+ 0 - 0
Tests/RunCMake/GeneratorPlatform/BadVersionPlatform.cmake → Tests/RunCMake/GeneratorPlatform/BadVersionPre2019.cmake


+ 1 - 0
Tests/RunCMake/GeneratorPlatform/BadVersionUnsupported-result.txt

@@ -0,0 +1 @@
+1

+ 11 - 0
Tests/RunCMake/GeneratorPlatform/BadVersionUnsupported-stderr.txt

@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    Visual Studio [^
+]+
+
+  given platform specification containing a
+
+    version=1\.2\.3\.4
+
+  field with unsupported value\.$

+ 1 - 0
Tests/RunCMake/GeneratorPlatform/BadVersionUnsupported.cmake

@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")

+ 40 - 27
Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake

@@ -36,12 +36,16 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio (1[4567])( 20[0-9][0-9])?$")
   run_cmake(BadFieldUnknown)
   set(RunCMake_GENERATOR_PLATFORM "version=")
   run_cmake(BadVersionEmpty)
-  set(RunCMake_GENERATOR_PLATFORM "version=1.2.3.4")
+  set(RunCMake_GENERATOR_PLATFORM "version=10.0.0.0")
   run_cmake(BadVersionMissing)
-  set(RunCMake_GENERATOR_PLATFORM "version=8.1")
-  run_cmake_with_options(BadVersionPlatform -DCMAKE_SYSTEM_VERSION=8.1)
+  set(RunCMake_GENERATOR_PLATFORM "version=1.2.3.4")
+  run_cmake(BadVersionUnsupported)
 
-  if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio (1[45]) ")
+  if(RunCMake_GENERATOR MATCHES "^Visual Studio (1[45]) ")
+    set(RunCMake_GENERATOR_PLATFORM "version=10.0")
+    run_cmake(BadVersionPre2019)
+    unset(RunCMake_GENERATOR_PLATFORM)
+  else()
     set(expect_version "10.0")
     set(RunCMake_GENERATOR_PLATFORM "version=${expect_version}")
     set(RunCMake_TEST_VARIANT_DESCRIPTION "-${expect_version}")
@@ -61,6 +65,16 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio (1[4567])( 20[0-9][0-9])?$")
     file(GLOB kits RELATIVE "${kitsInclude}" "${kitsInclude}/*/um/windows.h")
     list(TRANSFORM kits REPLACE "/.*" "")
   endif()
+  cmake_host_system_information(RESULT kitsRoot81
+    QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Microsoft/Windows Kits/Installed Roots"
+    VALUE "KitsRoot81"
+    VIEW 64_32
+    ERROR_VARIABLE kitsRoot81Error
+    )
+  if(NOT kitsRoot81Error AND EXISTS "${kitsRoot81}/include/um/windows.h")
+    list(PREPEND kits "8.1")
+  endif()
+
   if(kits)
     message(STATUS "Available Kits: ${kits}")
     if(RunCMake_GENERATOR MATCHES "^Visual Studio 14 ")
@@ -83,29 +97,28 @@ if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio (1[4567])( 20[0-9][0-9])?$")
     message(FATAL_ERROR "Could not find any Windows SDKs to drive test cases.")
   endif()
 
-  if(kits)
-    foreach(expect_version IN LISTS kits)
-      set(RunCMake_GENERATOR_PLATFORM "version=${expect_version}")
-      set(RunCMake_TEST_VARIANT_DESCRIPTION "-${expect_version}")
-      run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0)
-      unset(RunCMake_GENERATOR_PLATFORM)
-    endforeach()
-    foreach(expect_version IN LISTS kits)
-      set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMP0149-OLD-${expect_version}")
-      run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=${expect_version} -DCMAKE_POLICY_DEFAULT_CMP0149=OLD)
-    endforeach()
-    if(kits MATCHES "(^|;)([0-9.]+)$")
-      set(expect_version "${CMAKE_MATCH_2}")
-      foreach(test_version IN LISTS kits)
-        set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMP0149-NEW-${test_version}")
-        run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=${test_version} -DCMAKE_POLICY_DEFAULT_CMP0149=NEW)
-      endforeach()
-    endif()
-    foreach(expect_version IN LISTS kits)
-      set(RunCMake_TEST_VARIANT_DESCRIPTION "-WindowsSDKVersion-${expect_version}")
-      set(ENV{WindowsSDKVersion} "${expect_version}\\")
-      run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_POLICY_DEFAULT_CMP0149=NEW)
-      unset(ENV{WindowsSDKVersion})
+  foreach(expect_version IN LISTS kits)
+    set(RunCMake_GENERATOR_PLATFORM "version=${expect_version}")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION "-${expect_version}")
+    run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0)
+    unset(RunCMake_GENERATOR_PLATFORM)
+  endforeach()
+  foreach(expect_version IN LISTS kits)
+    set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMP0149-OLD-${expect_version}")
+    run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=${expect_version} -DCMAKE_POLICY_DEFAULT_CMP0149=OLD)
+  endforeach()
+  if(kits MATCHES "(^|;)([0-9.]+)$")
+    set(expect_version "${CMAKE_MATCH_2}")
+    foreach(test_version IN LISTS kits)
+      set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMP0149-NEW-${test_version}")
+      run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=${test_version} -DCMAKE_POLICY_DEFAULT_CMP0149=NEW)
     endforeach()
   endif()
+  list(REMOVE_ITEM kits 8.1)
+  foreach(expect_version IN LISTS kits)
+    set(RunCMake_TEST_VARIANT_DESCRIPTION "-WindowsSDKVersion-${expect_version}")
+    set(ENV{WindowsSDKVersion} "${expect_version}\\")
+    run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_POLICY_DEFAULT_CMP0149=NEW)
+    unset(ENV{WindowsSDKVersion})
+  endforeach()
 endif()

+ 8 - 4
Tests/RunCMake/GeneratorPlatform/VersionExists-check.cmake

@@ -1,9 +1,13 @@
 if(actual_stdout MATCHES "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION='([^']+)'")
   set(actual_version "${CMAKE_MATCH_1}")
-  if(NOT "${actual_version}" STREQUAL "${expect_version}")
-    set(RunCMake_TEST_FAILED "Actual SDK version '${actual_version}' did not match expected '${expect_version}'")
-    return()
-  endif()
+elseif(actual_stdout MATCHES "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=''" AND RunCMake_GENERATOR MATCHES "Visual Studio 1[45] ")
+  set(actual_version "8.1")
 else()
   set(RunCMake_TEST_FAILED "No CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION found in output.")
+  return()
+endif()
+
+if(NOT "${actual_version}" STREQUAL "${expect_version}")
+  set(RunCMake_TEST_FAILED "Actual SDK version '${actual_version}' did not match expected '${expect_version}'")
+  return()
 endif()