From 09f59da7f09ef864c592cb7e3ffd26373ae2f705 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 12 Mar 2021 06:33:51 -0500 Subject: cmGlobalVisualStudioVersionedGenerator: Clarify local variable name --- Source/cmGlobalVisualStudio10Generator.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 7794df3..7011333 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -302,16 +302,16 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( // 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; + std::string versionToolset = this->GeneratorToolsetVersion; cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9][0-9]"); - if (regex.find(version)) { - version = "v" + version.erase(2, 1); + if (regex.find(versionToolset)) { + versionToolset = "v" + versionToolset.erase(2, 1); } else { // Version not recognized. Clear it. - version.clear(); + versionToolset.clear(); } - if (!cmHasPrefix(version, this->GetPlatformToolsetString())) { + if (!cmHasPrefix(versionToolset, this->GetPlatformToolsetString())) { std::ostringstream e; /* clang-format off */ e << -- cgit v0.12 From 58a50a3a0aa814c0fb00720cb8fc9edb2cf72344 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 11 Mar 2021 16:59:20 -0500 Subject: VS: Fix '-T version=14.28' under VS 16.9 CMake accepts the toolset version that is default in the current VS version by matching the name later VS versions will use for the SxS props files. It predicts the future name based on the first two components of the current VS version's default toolset. However, this heuristic breaks naming the VS 16.8 toolset version 14.28 under VS 16.9 because the latter's default toolset version is 14.28.29910, which did not increment the second version component (unprecedented in VS). Fix this by always using the requested version's SxS props file when it exists, even if it matches the first two components of the current VS version's default toolset. Also add a special case for the name VS 16.10 will use for VS 16.9's default toolset, so that it can be used with VS 16.9 too. Fixes: #21922 --- .../variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst | 8 ++ Source/cmGlobalVisualStudio10Generator.cxx | 63 +++++++-------- Source/cmGlobalVisualStudio10Generator.h | 22 ++++-- Source/cmGlobalVisualStudioVersionedGenerator.cxx | 90 ++++++++++++---------- Source/cmGlobalVisualStudioVersionedGenerator.h | 4 +- Source/cmVisualStudio10TargetGenerator.cxx | 12 +-- 6 files changed, 108 insertions(+), 91 deletions(-) diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst index 64f2e39..b058278 100644 --- a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst +++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst @@ -11,3 +11,11 @@ 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. + +If the value is not empty, it is the version number that MSBuild uses in +its ``Microsoft.VCToolsVersion.*.props`` file names. + +.. versionadded:: 3.19.7 + + VS 16.9's toolset may also be specified as ``14.28.16.9`` because + VS 16.10 uses the file name ``Microsoft.VCToolsVersion.14.28.16.9.props``. diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 7011333..badce2e 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -3,6 +3,7 @@ #include "cmGlobalVisualStudio10Generator.h" #include +#include #include @@ -329,15 +330,20 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( this->GeneratorToolsetVersion.clear(); } - bool const isDefaultToolset = - this->IsDefaultToolset(this->GeneratorToolsetVersion); - if (isDefaultToolset) { - // If the given version is the default toolset, remove the setting - this->GeneratorToolsetVersion.clear(); - } else { - std::string const toolsetPath = this->GetAuxiliaryToolset(); - if (!toolsetPath.empty() && !cmSystemTools::FileExists(toolsetPath)) { - + std::string auxProps; + switch (this->FindAuxToolset(this->GeneratorToolsetVersion, auxProps)) { + case AuxToolset::None: + this->GeneratorToolsetVersionProps = {}; + break; + case AuxToolset::Default: + // The given version is the default toolset. Remove the setting. + this->GeneratorToolsetVersion.clear(); + this->GeneratorToolsetVersionProps = {}; + break; + case AuxToolset::PropsExist: + this->GeneratorToolsetVersionProps = std::move(auxProps); + break; + case AuxToolset::PropsMissing: { std::ostringstream e; /* clang-format off */ e << @@ -347,22 +353,24 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( " " << this->GetPlatformToolsetString() << ",version=" << this->GeneratorToolsetVersion << "\n" "does not seem to be installed at\n" << - " " << toolsetPath; + " " << auxProps; ; /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); // Clear the configured tool-set this->GeneratorToolsetVersion.clear(); - } + this->GeneratorToolsetVersionProps = {}; + } break; } } 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 (!this->GeneratorToolsetVersion.empty()) { + mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VERSION", + this->GeneratorToolsetVersion); } if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) { mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch); @@ -719,23 +727,10 @@ 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 +cmGlobalVisualStudio10Generator::GetPlatformToolsetVersionProps() const { - if (!this->GeneratorToolsetVersion.empty()) { - return this->GeneratorToolsetVersion; - } - static std::string const empty; - return empty; + return this->GeneratorToolsetVersionProps; } const char* @@ -792,15 +787,11 @@ cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDirString() const return this->GeneratorToolsetCudaCustomDir; } -bool cmGlobalVisualStudio10Generator::IsDefaultToolset( - const std::string&) const -{ - return true; -} - -std::string cmGlobalVisualStudio10Generator::GetAuxiliaryToolset() const +cmGlobalVisualStudio10Generator::AuxToolset +cmGlobalVisualStudio10Generator::FindAuxToolset(std::string&, + std::string&) const { - return {}; + return AuxToolset::None; } bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf) diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 65ea33f..8d30ef8 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -61,9 +61,8 @@ public: const char* GetPlatformToolset() const; std::string const& GetPlatformToolsetString() const; - /** The toolset version. */ - const char* GetPlatformToolsetVersion() const; - std::string const& GetPlatformToolsetVersionString() const; + /** The toolset version props file, if any. */ + std::string const& GetPlatformToolsetVersionProps() const; /** The toolset host architecture name (e.g. x64 for 64-bit host tools). */ const char* GetPlatformToolsetHostArchitecture() const; @@ -120,9 +119,6 @@ public: std::string Encoding() override; const char* GetToolsVersion() const; - virtual bool IsDefaultToolset(const std::string& version) const; - virtual std::string GetAuxiliaryToolset() const; - bool GetSupportsUnityBuilds() const { return this->SupportsUnityBuilds; } bool FindMakeProgram(cmMakefile* mf) override; @@ -168,6 +164,16 @@ protected: virtual bool SelectWindowsPhoneToolset(std::string& toolset) const; virtual bool SelectWindowsStoreToolset(std::string& toolset) const; + enum class AuxToolset + { + None, + Default, + PropsExist, + PropsMissing + }; + virtual AuxToolset FindAuxToolset(std::string& version, + std::string& props) const; + std::string const& GetMSBuildCommand(); cmIDEFlagTable const* LoadFlagTable(std::string const& optionsName, @@ -176,7 +182,7 @@ protected: std::string const& table) const; std::string GeneratorToolset; - std::string GeneratorToolsetVersion; + std::string GeneratorToolsetVersionProps; std::string GeneratorToolsetHostArchitecture; std::string GeneratorToolsetCustomVCTargetsDir; std::string GeneratorToolsetCuda; @@ -230,6 +236,8 @@ private: std::string FindDevEnvCommand() override; std::string GetVSMakeProgram() override { return this->GetMSBuildCommand(); } + std::string GeneratorToolsetVersion; + bool PlatformToolsetNeedsDebugEnum; bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf); diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index 84f870e..4e2464b 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudioVersionedGenerator.h" +#include + #include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmLocalVisualStudio10Generator.h" @@ -391,27 +393,6 @@ bool cmGlobalVisualStudioVersionedGenerator::GetVSInstanceVersion( return vsSetupAPIHelper.GetVSInstanceVersion(vsInstanceVersion); } -bool cmGlobalVisualStudioVersionedGenerator::IsDefaultToolset( - const std::string& version) const -{ - if (version.empty()) { - return true; - } - - std::string vcToolsetVersion; - if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion)) { - - cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9]+"); - if (regex.find(version) && regex.find(vcToolsetVersion)) { - const auto majorMinorEnd = vcToolsetVersion.find('.', 3); - const auto majorMinor = vcToolsetVersion.substr(0, majorMinorEnd); - return version == majorMinor; - } - } - - return false; -} - bool cmGlobalVisualStudioVersionedGenerator::IsStdOutEncodingSupported() const { // Supported from Visual Studio 16.7 Preview 3. @@ -446,29 +427,58 @@ cmGlobalVisualStudioVersionedGenerator::GetAndroidApplicationTypeRevision() return ""; } -std::string cmGlobalVisualStudioVersionedGenerator::GetAuxiliaryToolset() const +cmGlobalVisualStudioVersionedGenerator::AuxToolset +cmGlobalVisualStudioVersionedGenerator::FindAuxToolset( + std::string& version, std::string& props) const { - const char* version = this->GetPlatformToolsetVersion(); - if (version) { - std::string instancePath; - GetVSInstance(instancePath); - std::string toolsetDir = instancePath + "/VC/Auxiliary/Build"; - char sep = '/'; - if (cmSystemTools::VersionCompareGreaterEq(version, "14.20")) { - std::string toolsetDot = - cmStrCat(toolsetDir, '.', version, "/Microsoft.VCToolsVersion.", - version, ".props"); - if (cmSystemTools::PathExists(toolsetDot)) { - sep = '.'; + if (version.empty()) { + return AuxToolset::None; + } + + std::string instancePath; + this->GetVSInstance(instancePath); + cmSystemTools::ConvertToUnixSlashes(instancePath); + + if (cmSystemTools::VersionCompareGreaterEq(version, "14.20")) { + props = cmStrCat(instancePath, "/VC/Auxiliary/Build."_s, version, + "/Microsoft.VCToolsVersion."_s, version, ".props"_s); + if (cmSystemTools::PathExists(props)) { + return AuxToolset::PropsExist; + } + } + props = cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, version, + "/Microsoft.VCToolsVersion."_s, version, ".props"_s); + if (cmSystemTools::PathExists(props)) { + return AuxToolset::PropsExist; + } + + // Accept the toolset version that is default in the current VS version + // by matching the name later VS versions will use for the SxS props files. + std::string vcToolsetVersion; + if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion)) { + // Accept an exact-match (three-component version). + if (version == vcToolsetVersion) { + return AuxToolset::Default; + } + + // Accept known SxS props file names using four version components + // in VS versions later than the current. + if (version == "14.28.16.9" && vcToolsetVersion == "14.28.29910") { + return AuxToolset::Default; + } + + // The first two components of the default toolset version typically + // match the name used by later VS versions for the SxS props files. + cmsys::RegularExpression twoComponent("^([0-9]+\\.[0-9]+)"); + if (twoComponent.find(version)) { + std::string const versionPrefix = cmStrCat(twoComponent.match(1), '.'); + if (cmHasPrefix(vcToolsetVersion, versionPrefix)) { + return AuxToolset::Default; } } - std::string toolsetPath = - cmStrCat(toolsetDir, sep, version, "/Microsoft.VCToolsVersion.", version, - ".props"); - cmSystemTools::ConvertToUnixSlashes(toolsetPath); - return toolsetPath; } - return {}; + + return AuxToolset::PropsMissing; } bool cmGlobalVisualStudioVersionedGenerator::InitializeWindows(cmMakefile* mf) diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 46a5f40..cee129e 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -30,8 +30,8 @@ public: bool GetVSInstanceVersion(unsigned long long& vsInstanceVersion) const; - bool IsDefaultToolset(const std::string& version) const override; - std::string GetAuxiliaryToolset() const override; + AuxToolset FindAuxToolset(std::string& version, + std::string& props) const override; bool IsStdOutEncodingSupported() const override; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4eb3b7f..489e42d 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -623,14 +623,14 @@ void cmVisualStudio10TargetGenerator::Generate() } switch (this->ProjectType) { - case vcxproj: - if (this->GlobalGenerator->GetPlatformToolsetVersion()) { - Elem(e0, "Import") - .Attribute("Project", - this->GlobalGenerator->GetAuxiliaryToolset()); + case vcxproj: { + std::string const& props = + this->GlobalGenerator->GetPlatformToolsetVersionProps(); + if (!props.empty()) { + Elem(e0, "Import").Attribute("Project", props); } Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS); - break; + } break; case csproj: Elem(e0, "Import") .Attribute("Project", VS10_CSharp_DEFAULT_PROPS) -- cgit v0.12 From 30c835428fffbf91191ebb1150d7fec00803523c Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 12 Mar 2021 08:01:54 -0500 Subject: VS: Accept and translate '-T version=' values with three components The VS 16.8 and VS 16.9 toolset versions differ only in their third component. The `vcvarsall` option `-vcvars_ver=` accepts a three component version, so accept this format for VS toolset selection too. Issue: #21922 --- Help/release/3.19.rst | 8 +++++ .../variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst | 12 +++++++ Source/cmGlobalVisualStudioVersionedGenerator.cxx | 37 ++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/Help/release/3.19.rst b/Help/release/3.19.rst index 1d55f1e..49c6793 100644 --- a/Help/release/3.19.rst +++ b/Help/release/3.19.rst @@ -432,3 +432,11 @@ Changes made since CMake 3.19.0 include the following. ``CMakePresets.json`` or ``CMakeUserPresets.json`` files. This was mistakenly allowed by the implementation in CMake 3.19.0 through CMake 3.19.5, and was not documented. + +3.19.7 +------ + +* With :ref:`Visual Studio Generators` for VS 2017 and higher, the + :variable:`CMAKE_GENERATOR_TOOLSET` field ``version=`` now accepts + three-component MSVC toolset versions such as ``14.28.29910``. + See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_VERSION` variable. diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst index b058278..c4369ee 100644 --- a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst +++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.rst @@ -19,3 +19,15 @@ its ``Microsoft.VCToolsVersion.*.props`` file names. VS 16.9's toolset may also be specified as ``14.28.16.9`` because VS 16.10 uses the file name ``Microsoft.VCToolsVersion.14.28.16.9.props``. + +Three-Component MSVC Toolset Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.19.7 + +The ``version=`` field may be given a three-component toolset version +such as ``14.28.29910``, and CMake will convert it to the name used by +MSBuild ``Microsoft.VCToolsVersion.*.props`` files. This is useful +to distinguish between VS 16.8's ``14.28.29333`` toolset and VS 16.9's +``14.28.29910`` toolset. It also matches ``vcvarsall``'s ``-vcvars_ver=`` +behavior. diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index 4e2464b..fb518a2 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -4,6 +4,9 @@ #include +#include "cmsys/FStream.hxx" +#include "cmsys/Glob.hxx" + #include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmLocalVisualStudio10Generator.h" @@ -439,6 +442,40 @@ cmGlobalVisualStudioVersionedGenerator::FindAuxToolset( this->GetVSInstance(instancePath); cmSystemTools::ConvertToUnixSlashes(instancePath); + // Translate three-component format accepted by "vcvarsall -vcvars_ver=". + cmsys::RegularExpression threeComponent( + "^([0-9]+\\.[0-9]+)\\.[0-9][0-9][0-9][0-9][0-9]$"); + if (threeComponent.find(version)) { + // Load "VC/Auxiliary/Build/*/Microsoft.VCToolsVersion.*.txt" files + // with two matching components to check their three-component version. + std::string const& twoComponent = threeComponent.match(1); + std::string pattern = + cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, twoComponent, + "*/Microsoft.VCToolsVersion."_s, twoComponent, "*.txt"_s); + cmsys::Glob glob; + glob.SetRecurseThroughSymlinks(false); + if (glob.FindFiles(pattern)) { + for (std::string const& txt : glob.GetFiles()) { + std::string ver; + cmsys::ifstream fin(txt.c_str()); + if (fin && std::getline(fin, ver)) { + // Strip trailing whitespace. + ver = ver.substr(0, ver.find_first_not_of("0123456789.")); + // If the three-component version matches, translate it to + // that used by the "Microsoft.VCToolsVersion.*.txt" file name. + if (ver == version) { + cmsys::RegularExpression extractVersion( + "VCToolsVersion\\.([0-9.]+)\\.txt$"); + if (extractVersion.find(txt)) { + version = extractVersion.match(1); + break; + } + } + } + } + } + } + if (cmSystemTools::VersionCompareGreaterEq(version, "14.20")) { props = cmStrCat(instancePath, "/VC/Auxiliary/Build."_s, version, "/Microsoft.VCToolsVersion."_s, version, ".props"_s); -- cgit v0.12