Browse Source

VS: Add option to select the version of the toolset used by VS 2017

Add new `version=` parameter in the toolset setting to select the
version.  Add variable `CMAKE_VS_PLATFORM_TOOLSET_VERSION` to hold the
version, if one is set (blank indicates default).

Fixes: #17549
Basil Fierz 7 years ago
parent
commit
5f13168419

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -100,6 +100,7 @@ Variables that Provide Information
    /variable/CMAKE_VS_PLATFORM_TOOLSET
    /variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA
    /variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
+   /variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION
    /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
    /variable/CMAKE_XCODE_GENERATE_SCHEME
    /variable/CMAKE_XCODE_PLATFORM_TOOLSET

+ 7 - 0
Help/release/dev/vs-toolset-version.rst

@@ -0,0 +1,7 @@
+vs-toolset-version
+------------------
+
+* The :ref:`Visual Studio Generators` for VS 2017 learned to support a
+  ``version=14.##`` option in the :variable:`CMAKE_GENERATOR_TOOLSET`
+  value (e.g. via the :manual:`cmake(1)` ``-T`` option) to specify a
+  toolset version number.

+ 5 - 0
Help/variable/CMAKE_GENERATOR_TOOLSET.rst

@@ -48,3 +48,8 @@ Supported pairs are:
   Supported by VS 2013 and above.
   See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE`
   variable.
+
+``version=<version>``
+  Specify the toolset version to use.  Supported by VS 2017
+  and above with the specified toolset installed.
+  See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_VERSION` variable.

+ 11 - 0
Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst

@@ -0,0 +1,11 @@
+CMAKE_VS_PLATFORM_TOOLSET_VERSION
+---------------------------------
+
+Visual Studio Platform Toolset version.
+
+The :ref:`Visual Studio Generators` for VS 2017 and above allow to
+select minor versions of the same toolset. The toolset version number
+may be specified by a field in :variable:`CMAKE_GENERATOR_TOOLSET` of
+the form ``version=14.11``. If none is specified CMake will choose a default
+toolset. The value may be empty if no minor version was selected and the
+default is used.

+ 4 - 0
Modules/CMakeDetermineCompilerId.cmake

@@ -213,9 +213,13 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
         if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "Intel")
           set(id_cl icl.exe)
         endif()
+        if(CMAKE_VS_PLATFORM_TOOLSET_VERSION)
+          set(id_toolset_version_props "<Import Project=\"${CMAKE_GENERATOR_INSTANCE}\\VC\\Auxiliary\\Build\\${CMAKE_VS_PLATFORM_TOOLSET_VERSION}\\Microsoft.VCToolsVersion.${CMAKE_VS_PLATFORM_TOOLSET_VERSION}.props\" />")
+        endif()
       endif()
     else()
       set(id_toolset "")
+      set(id_toolset_version_props "")
     endif()
     if(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE)
       set(id_PreferredToolArchitecture "<PreferredToolArchitecture>${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}</PreferredToolArchitecture>")

+ 1 - 0
Modules/CompilerId/VS-10.vcxproj.in

@@ -15,6 +15,7 @@
     @id_WindowsTargetPlatformVersion@
     @id_WindowsSDKDesktopARMSupport@
   </PropertyGroup>
+  @id_toolset_version_props@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup>
     @id_PreferredToolArchitecture@

+ 85 - 0
Source/cmGlobalVisualStudio10Generator.cxx

@@ -231,9 +231,66 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
     }
   }
 
+  if (!this->GeneratorToolsetVersion.empty() &&
+      this->GeneratorToolsetVersion != "Test Toolset Version") {
+    // If a specific minor version of the toolset was requested, verify that it
+    // is compatible to the major version and that is exists on disk.
+    // If not clear the value.
+    std::string version = this->GeneratorToolsetVersion;
+    cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9][0-9]");
+    if (regex.find(version)) {
+      version = "v" + version.erase(2, 1);
+    } else {
+      // Version not recognized. Clear it.
+      version.clear();
+    }
+
+    if (version.find(this->GetPlatformToolsetString()) != 0) {
+      std::ostringstream e;
+      /* clang-format off */
+      e <<
+        "Generator\n"
+        "  " << this->GetName() << "\n"
+        "given toolset and version specification\n"
+        "  " << this->GetPlatformToolsetString() << ",version=" <<
+        this->GeneratorToolsetVersion << "\n"
+        "contains an invalid version specification."
+      ;
+      /* clang-format on */
+      mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+
+      // Clear the configured tool-set
+      this->GeneratorToolsetVersion.clear();
+    }
+
+    std::string const toolsetPath = this->GetAuxiliaryToolset();
+    if (!toolsetPath.empty() && !cmSystemTools::FileExists(toolsetPath)) {
+
+      std::ostringstream e;
+      /* clang-format off */
+      e <<
+        "Generator\n"
+        "  " << this->GetName() << "\n"
+        "given toolset and version specification\n"
+        "  " << this->GetPlatformToolsetString() << ",version=" <<
+        this->GeneratorToolsetVersion << "\n"
+        "does not seem to be installed at\n" <<
+        "  " << toolsetPath;
+      ;
+      /* clang-format on */
+      mf->IssueMessage(cmake::FATAL_ERROR, e.str());
+
+      // Clear the configured tool-set
+      this->GeneratorToolsetVersion.clear();
+    }
+  }
+
   if (const char* toolset = this->GetPlatformToolset()) {
     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
   }
+  if (const char* version = this->GetPlatformToolsetVersion()) {
+    mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VERSION", version);
+  }
   if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch);
   }
@@ -319,6 +376,10 @@ bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
     this->GeneratorToolsetCuda = value;
     return true;
   }
+  if (key == "version") {
+    this->GeneratorToolsetVersion = value;
+    return true;
+  }
   return false;
 }
 
@@ -512,6 +573,25 @@ std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString()
   return empty;
 }
 
+const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetVersion() const
+{
+  std::string const& version = this->GetPlatformToolsetVersionString();
+  if (version.empty()) {
+    return nullptr;
+  }
+  return version.c_str();
+}
+
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetVersionString() const
+{
+  if (!this->GeneratorToolsetVersion.empty()) {
+    return this->GeneratorToolsetVersion;
+  }
+  static std::string const empty;
+  return empty;
+}
+
 const char*
 cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
 {
@@ -535,6 +615,11 @@ cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
   return this->GeneratorToolsetCuda;
 }
 
+std::string cmGlobalVisualStudio10Generator::GetAuxiliaryToolset() const
+{
+  return {};
+}
+
 bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
 {
   if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {

+ 7 - 0
Source/cmGlobalVisualStudio10Generator.h

@@ -54,6 +54,10 @@ public:
   const char* GetPlatformToolset() const;
   std::string const& GetPlatformToolsetString() const;
 
+  /** The toolset version.  */
+  const char* GetPlatformToolsetVersion() const;
+  std::string const& GetPlatformToolsetVersionString() const;
+
   /** The toolset host architecture name (e.g. x64 for 64-bit host tools).  */
   const char* GetPlatformToolsetHostArchitecture() const;
 
@@ -101,6 +105,8 @@ public:
   std::string Encoding() override;
   virtual const char* GetToolsVersion() { return "4.0"; }
 
+  virtual std::string GetAuxiliaryToolset() const;
+
   bool FindMakeProgram(cmMakefile* mf) override;
 
   static std::string GetInstalledNsightTegraVersion();
@@ -135,6 +141,7 @@ protected:
   std::string const& GetMSBuildCommand();
 
   std::string GeneratorToolset;
+  std::string GeneratorToolsetVersion;
   std::string GeneratorToolsetHostArchitecture;
   std::string GeneratorToolsetCuda;
   std::string DefaultPlatformToolset;

+ 19 - 0
Source/cmGlobalVisualStudio15Generator.cxx

@@ -158,6 +158,25 @@ bool cmGlobalVisualStudio15Generator::GetVSInstance(std::string& dir) const
   return vsSetupAPIHelper.GetVSInstanceInfo(dir);
 }
 
+std::string cmGlobalVisualStudio15Generator::GetAuxiliaryToolset() const
+{
+  const char* version = this->GetPlatformToolsetVersion();
+  if (version) {
+    std::string instancePath;
+    GetVSInstance(instancePath);
+    std::stringstream path;
+    path << instancePath;
+    path << "/VC/Auxiliary/Build/";
+    path << version;
+    path << "/Microsoft.VCToolsVersion." << version << ".props";
+
+    std::string toolsetPath = path.str();
+    cmSystemTools::ConvertToUnixSlashes(toolsetPath);
+    return toolsetPath;
+  }
+  return {};
+}
+
 bool cmGlobalVisualStudio15Generator::InitializeWindows(cmMakefile* mf)
 {
   // If the Win 8.1 SDK is installed then we can select a SDK matching

+ 2 - 0
Source/cmGlobalVisualStudio15Generator.h

@@ -32,6 +32,8 @@ public:
 
   bool GetVSInstance(std::string& dir) const;
 
+  std::string GetAuxiliaryToolset() const override;
+
 protected:
   bool InitializeWindows(cmMakefile* mf) override;
   bool SelectWindowsStoreToolset(std::string& toolset) const override;

+ 5 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -557,6 +557,11 @@ void cmVisualStudio10TargetGenerator::Generate()
 
     switch (this->ProjectType) {
       case vcxproj:
+        if (this->GlobalGenerator->GetPlatformToolsetVersion()) {
+          Elem(e0, "Import")
+            .Attribute("Project",
+                       this->GlobalGenerator->GetAuxiliaryToolset());
+        }
         Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS);
         break;
       case csproj:

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetVersion-result.txt

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

+ 10 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetVersion-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    .*
+
+  given toolset and version specification
+
+    Test Toolset,version=Bad Toolset Version
+
+  contains an invalid version specification.

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetVersion.cmake

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

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetVersionTwice-result.txt

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

+ 10 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetVersionTwice-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    .*
+
+  given toolset specification
+
+    Test Toolset,version=Test Toolset Version,version=Test Toolset Version
+
+  that contains duplicate field key 'version'\.$

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetVersionTwice.cmake

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

+ 12 - 0
Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake

@@ -25,6 +25,18 @@ if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[01245]")
     run_cmake(BadToolsetHostArch)
     set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64,host=x64")
     run_cmake(BadToolsetHostArchTwice)
+    if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 15")
+      set(RunCMake_GENERATOR_TOOLSET "Test Toolset,version=Test Toolset Version")
+      run_cmake(TestToolsetVersionBoth)
+      set(RunCMake_GENERATOR_TOOLSET ",version=Test Toolset Version")
+      run_cmake(TestToolsetVersionOnly)
+      set(RunCMake_GENERATOR_TOOLSET "version=Test Toolset Version")
+      run_cmake(TestToolsetVersionOnly)
+      set(RunCMake_GENERATOR_TOOLSET "Test Toolset,version=Bad Toolset Version")
+      run_cmake(BadToolsetVersion)
+      set(RunCMake_GENERATOR_TOOLSET "Test Toolset,version=Test Toolset Version,version=Test Toolset Version")
+      run_cmake(BadToolsetVersionTwice)
+    endif()
   else()
     set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
     run_cmake(BadToolsetHostArch)

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetVersionBoth-stdout.txt

@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='Test Toolset'
+-- CMAKE_VS_PLATFORM_TOOLSET_VERSION='Test Toolset Version'

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetVersionBoth.cmake

@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_VERSION='${CMAKE_VS_PLATFORM_TOOLSET_VERSION}'")

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetVersionOnly-stdout.txt

@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='v[0-9]+'
+-- CMAKE_VS_PLATFORM_TOOLSET_VERSION='Test Toolset Version'

+ 2 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetVersionOnly.cmake

@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_VERSION='${CMAKE_VS_PLATFORM_TOOLSET_VERSION}'")