Commit a48cd5dc authored by Egor Pugin's avatar Egor Pugin
Browse files

Add initial VS2019 generator.

Add missing files.

More VS2019 tweaks in help and tests. Update for json flag tables.

Set LF line endings.
parent 50454c96
Pipeline #126247 failed with stage
Visual Studio 16 2019
---------------------
Generates Visual Studio 16 (VS 2019) project files.
Project Types
^^^^^^^^^^^^^
Only Visual C++ and C# projects may be generated. Other types of
projects (JavaScript, Powershell, Python, etc.) are not supported.
Instance Selection
^^^^^^^^^^^^^^^^^^
VS 2019 supports multiple installations on the same machine.
The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
cache entry containing the absolute path to a Visual Studio instance.
If the value is not specified explicitly by the user or a toolchain file,
CMake queries the Visual Studio Installer to locate VS instances, chooses
one, and sets the variable as a cache entry to hold the value persistently.
When CMake first chooses an instance, if the ``VS160COMNTOOLS`` environment
variable is set and points to the ``Common7/Tools`` directory within
one of the instances, that instance will be used. Otherwise, if more
than one instance is installed we do not define which one is chosen
by default.
Platform Selection
^^^^^^^^^^^^^^^^^^
The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
name (architecture). For example:
* ``cmake -G "Visual Studio 16 2019" -A Win32``
* ``cmake -G "Visual Studio 16 2019" -A x64``
* ``cmake -G "Visual Studio 16 2019" -A ARM``
* ``cmake -G "Visual Studio 16 2019" -A ARM64``
For compatibility with CMake versions prior to 3.1, one may specify
a target platform name optionally at the end of the generator name.
This is supported only for:
``Visual Studio 16 2019 Win64``
Specify target platform ``x64``.
``Visual Studio 16 2019 ARM``
Specify target platform ``ARM``.
Toolset Selection
^^^^^^^^^^^^^^^^^
The ``v141`` toolset that comes with Visual Studio 16 2019 is selected by
default. The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
.. include:: VS_TOOLSET_HOST_ARCH.txt
......@@ -87,6 +87,7 @@ Visual Studio Generators
/generator/Visual Studio 12 2013
/generator/Visual Studio 14 2015
/generator/Visual Studio 15 2017
/generator/Visual Studio 16 2019
Other Generators
^^^^^^^^^^^^^^^^
......
vs-16-generator
---------------
* The :generator:`Visual Studio 16` generator was added.
......@@ -18,6 +18,7 @@ Known version numbers are::
1800 = VS 12.0 (v120 toolset)
1900 = VS 14.0 (v140 toolset)
1910-1919 = VS 15.0 (v141 toolset)
1920-1929 = VS 16.0 (v141 toolset)
See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` and
:variable:`MSVC_TOOLSET_VERSION` variable.
......@@ -698,6 +698,8 @@ if (WIN32)
cmGlobalVisualStudio14Generator.cxx
cmGlobalVisualStudio15Generator.h
cmGlobalVisualStudio15Generator.cxx
cmGlobalVisualStudio16Generator.h
cmGlobalVisualStudio16Generator.cxx
cmGlobalVisualStudioGenerator.cxx
cmGlobalVisualStudioGenerator.h
cmIDEFlagTable.h
......
......@@ -142,7 +142,7 @@ bool cmCMakeHostSystemInformationCommand::GetValue(
// Otherwise, find a VS 15 instance ourselves.
cmVSSetupAPIHelper vsSetupAPIHelper;
if (vsSetupAPIHelper.GetVSInstanceInfo(value)) {
if (vsSetupAPIHelper.GetVSInstanceInfo(value, 15)) {
cmSystemTools::ConvertToUnixSlashes(value);
}
#endif
......
......@@ -112,7 +112,7 @@ bool cmGlobalVisualStudio15Generator::SetGeneratorInstance(
std::string const& i, cmMakefile* mf)
{
if (!i.empty()) {
if (!this->vsSetupAPIHelper.SetVSInstance(i)) {
if (!this->vsSetupAPIHelper.SetVSInstance(i, 15)) {
std::ostringstream e;
/* clang-format off */
e <<
......@@ -127,7 +127,7 @@ bool cmGlobalVisualStudio15Generator::SetGeneratorInstance(
}
std::string vsInstance;
if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) {
if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance, 15)) {
std::ostringstream e;
/* clang-format off */
e <<
......@@ -152,7 +152,7 @@ bool cmGlobalVisualStudio15Generator::SetGeneratorInstance(
bool cmGlobalVisualStudio15Generator::GetVSInstance(std::string& dir) const
{
return vsSetupAPIHelper.GetVSInstanceInfo(dir);
return vsSetupAPIHelper.GetVSInstanceInfo(dir, 15);
}
bool cmGlobalVisualStudio15Generator::IsDefaultToolset(
......@@ -163,7 +163,7 @@ bool cmGlobalVisualStudio15Generator::IsDefaultToolset(
}
std::string vcToolsetVersion;
if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion)) {
if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion, 15)) {
cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9]+");
if (regex.find(version) && regex.find(vcToolsetVersion)) {
......@@ -230,13 +230,13 @@ bool cmGlobalVisualStudio15Generator::IsWindowsDesktopToolsetInstalled() const
bool cmGlobalVisualStudio15Generator::IsWindowsStoreToolsetInstalled() const
{
return vsSetupAPIHelper.IsWin10SDKInstalled();
return vsSetupAPIHelper.IsWin10SDKInstalled(15);
}
bool cmGlobalVisualStudio15Generator::IsWin81SDKInstalled() const
{
// Does the VS installer tool know about one?
if (vsSetupAPIHelper.IsWin81SDKInstalled()) {
if (vsSetupAPIHelper.IsWin81SDKInstalled(15)) {
return true;
}
......@@ -266,7 +266,7 @@ std::string cmGlobalVisualStudio15Generator::FindMSBuildCommand()
// Ask Visual Studio Installer tool.
std::string vs;
if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
if (vsSetupAPIHelper.GetVSInstanceInfo(vs, 15)) {
msbuild = vs + "/MSBuild/15.0/Bin/MSBuild.exe";
if (cmSystemTools::FileExists(msbuild)) {
return msbuild;
......@@ -283,7 +283,7 @@ std::string cmGlobalVisualStudio15Generator::FindDevEnvCommand()
// Ask Visual Studio Installer tool.
std::string vs;
if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
if (vsSetupAPIHelper.GetVSInstanceInfo(vs, 15)) {
devenv = vs + "/Common7/IDE/devenv.com";
if (cmSystemTools::FileExists(devenv)) {
return devenv;
......
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalVisualStudio16Generator.h"
#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include "cmLocalVisualStudio10Generator.h"
#include "cmMakefile.h"
#include "cmVSSetupHelper.h"
static const char vs16generatorName[] = "Visual Studio 16 2019";
// Map generator name without year to name with year.
static const char* cmVS16GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs16generatorName,
sizeof(vs16generatorName) - 6) != 0) {
return 0;
}
const char* p = name.c_str() + sizeof(vs16generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2019")) {
p += 5;
}
genName = std::string(vs16generatorName) + p;
return p;
}
class cmGlobalVisualStudio16Generator::Factory
: public cmGlobalGeneratorFactory
{
public:
virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
cmake* cm) const
{
std::string genName;
const char* p = cmVS16GenName(name, genName);
if (!p) {
return 0;
}
if (!*p) {
return new cmGlobalVisualStudio16Generator(cm, genName, "");
}
if (*p++ != ' ') {
return 0;
}
if (strcmp(p, "Win64") == 0) {
return new cmGlobalVisualStudio16Generator(cm, genName, "x64");
}
if (strcmp(p, "ARM") == 0) {
return new cmGlobalVisualStudio16Generator(cm, genName, "ARM");
}
return 0;
}
virtual void GetDocumentation(cmDocumentationEntry& entry) const
{
entry.Name = std::string(vs16generatorName) + " [arch]";
entry.Brief = "Generates Visual Studio 2019 project files. "
"Optional [arch] can be \"Win64\" or \"ARM\".";
}
virtual void GetGenerators(std::vector<std::string>& names) const
{
names.push_back(vs16generatorName);
names.push_back(vs16generatorName + std::string(" ARM"));
names.push_back(vs16generatorName + std::string(" Win64"));
}
bool SupportsToolset() const override { return true; }
bool SupportsPlatform() const override { return true; }
};
cmGlobalGeneratorFactory* cmGlobalVisualStudio16Generator::NewFactory()
{
return new Factory;
}
cmGlobalVisualStudio16Generator::cmGlobalVisualStudio16Generator(
cmake* cm, const std::string& name, const std::string& platformName)
: cmGlobalVisualStudio14Generator(cm, name, platformName)
{
this->ExpressEdition = false;
this->DefaultPlatformToolset = "v141";
this->DefaultCLFlagTableName = "v141";
this->DefaultCSharpFlagTableName = "v141";
this->DefaultLinkFlagTableName = "v141";
this->Version = VS16;
}
bool cmGlobalVisualStudio16Generator::MatchesGeneratorName(
const std::string& name) const
{
std::string genName;
if (cmVS16GenName(name, genName)) {
return genName == this->GetName();
}
return false;
}
void cmGlobalVisualStudio16Generator::WriteSLNHeader(std::ostream& fout)
{
// Visual Studio 16 writes .sln format 12.00
fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
if (this->ExpressEdition) {
fout << "# Visual Studio Express 16 for Windows Desktop\n";
} else {
fout << "# Visual Studio 16\n";
}
}
bool cmGlobalVisualStudio16Generator::SetGeneratorInstance(
std::string const& i, cmMakefile* mf)
{
if (!i.empty()) {
if (!this->vsSetupAPIHelper.SetVSInstance(i, 16)) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"could not find specified instance of Visual Studio:\n"
" " << i;
/* clang-format on */
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
return false;
}
}
std::string vsInstance;
if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance, 16)) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"could not find any instance of Visual Studio.\n";
/* clang-format on */
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
return false;
}
// Save the selected instance persistently.
std::string genInstance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
if (vsInstance != genInstance) {
this->CMakeInstance->AddCacheEntry(
"CMAKE_GENERATOR_INSTANCE", vsInstance.c_str(),
"Generator instance identifier.", cmStateEnums::INTERNAL);
}
return true;
}
bool cmGlobalVisualStudio16Generator::GetVSInstance(std::string& dir) const
{
return vsSetupAPIHelper.GetVSInstanceInfo(dir, 16);
}
bool cmGlobalVisualStudio16Generator::IsDefaultToolset(
const std::string& version) const
{
if (version.empty()) {
return true;
}
std::string vcToolsetVersion;
if (this->vsSetupAPIHelper.GetVCToolsetVersion(vcToolsetVersion, 16)) {
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;
}
std::string cmGlobalVisualStudio16Generator::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 cmGlobalVisualStudio16Generator::InitializeWindows(cmMakefile* mf)
{
// If the Win 8.1 SDK is installed then we can select a SDK matching
// the target Windows version.
if (this->IsWin81SDKInstalled()) {
return cmGlobalVisualStudio14Generator::InitializeWindows(mf);
}
// Otherwise we must choose a Win 10 SDK even if we are not targeting
// Windows 10.
return this->SelectWindows10SDK(mf, false);
}
bool cmGlobalVisualStudio16Generator::SelectWindowsStoreToolset(
std::string& toolset) const
{
if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
if (this->IsWindowsStoreToolsetInstalled() &&
this->IsWindowsDesktopToolsetInstalled()) {
toolset = "v141"; // VS 16 uses v141 toolset
return true;
} else {
return false;
}
}
return this->cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
toolset);
}
bool cmGlobalVisualStudio16Generator::IsWindowsDesktopToolsetInstalled() const
{
return vsSetupAPIHelper.IsVSInstalled(16);
}
bool cmGlobalVisualStudio16Generator::IsWindowsStoreToolsetInstalled() const
{
return vsSetupAPIHelper.IsWin10SDKInstalled(16);
}
bool cmGlobalVisualStudio16Generator::IsWin81SDKInstalled() const
{
// Does the VS installer tool know about one?
if (vsSetupAPIHelper.IsWin81SDKInstalled(16)) {
return true;
}
// Does the registry know about one (e.g. from VS 2016)?
std::string win81Root;
if (cmSystemTools::ReadRegistryValue(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
"Windows Kits\\Installed Roots;KitsRoot81",
win81Root, cmSystemTools::KeyWOW64_32) ||
cmSystemTools::ReadRegistryValue(
"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
"Windows Kits\\Installed Roots;KitsRoot81",
win81Root, cmSystemTools::KeyWOW64_32)) {
return cmSystemTools::FileExists(win81Root + "/um/windows.h", true);
}
return false;
}
std::string cmGlobalVisualStudio16Generator::GetWindows10SDKMaxVersion() const
{
return std::string();
}
std::string cmGlobalVisualStudio16Generator::FindMSBuildCommand()
{
std::string msbuild;
// Ask Visual Studio Installer tool.
std::string vs;
if (vsSetupAPIHelper.GetVSInstanceInfo(vs, 16)) {
msbuild = vs + "/MSBuild/Current/Bin/MSBuild.exe";
if (cmSystemTools::FileExists(msbuild)) {
return msbuild;
}
}
msbuild = "MSBuild.exe";
return msbuild;
}
std::string cmGlobalVisualStudio16Generator::FindDevEnvCommand()
{
std::string devenv;
// Ask Visual Studio Installer tool.
std::string vs;
if (vsSetupAPIHelper.GetVSInstanceInfo(vs, 16)) {
devenv = vs + "/Common7/IDE/devenv.com";
if (cmSystemTools::FileExists(devenv)) {
return devenv;
}
}
devenv = "devenv.com";
return devenv;
}
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmGlobalVisualStudio16Generator_h
#define cmGlobalVisualStudio16Generator_h
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
#include <string>
#include "cmGlobalVisualStudio14Generator.h"
#include "cmVSSetupHelper.h"
class cmGlobalGeneratorFactory;
class cmake;
/** \class cmGlobalVisualStudio16Generator */
class cmGlobalVisualStudio16Generator : public cmGlobalVisualStudio14Generator
{
public:
cmGlobalVisualStudio16Generator(cmake* cm, const std::string& name,
const std::string& platformName);
static cmGlobalGeneratorFactory* NewFactory();
bool MatchesGeneratorName(const std::string& name) const override;
void WriteSLNHeader(std::ostream& fout) override;
const char* GetToolsVersion() override { return "16.0"; }
bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override;
bool GetVSInstance(std::string& dir) const;
bool IsDefaultToolset(const std::string& version) const override;
std::string GetAuxiliaryToolset() const override;
protected:
bool InitializeWindows(cmMakefile* mf) override;
bool SelectWindowsStoreToolset(std::string& toolset) const override;
const char* GetIDEVersion() override { return "16.0"; }
// Used to verify that the Desktop toolset for the current generator is
// installed on the machine.
bool IsWindowsDesktopToolsetInstalled() const override;
// These aren't virtual because we need to check if the selected version
// of the toolset is installed
bool IsWindowsStoreToolsetInstalled() const;
// Check for a Win 8 SDK known to the registry or VS installer tool.
bool IsWin81SDKInstalled() const;
std::string GetWindows10SDKMaxVersion() const override;
std::string FindMSBuildCommand() override;
std::string FindDevEnvCommand() override;
private:
class Factory;
mutable cmVSSetupAPIHelper vsSetupAPIHelper;
};
#endif
......@@ -38,7 +38,8 @@ public:
VS12 = 120,
/* VS13 = 130 was skipped */
VS14 = 140,
VS15 = 150
VS15 = 150,
VS16 = 160
};
cmGlobalVisualStudioGenerator(cmake* cm);
......
......@@ -80,28 +80,34 @@ cmVSSetupAPIHelper::~cmVSSetupAPIHelper()
CoUninitialize();
}
bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation)
bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation,
int version)
{
this->SpecifiedVSInstallLocation = vsInstallLocation;
cmSystemTools::ConvertToUnixSlashes(this->SpecifiedVSInstallLocation);
chosenInstanceInfo = VSInstanceInfo();
return this->EnumerateAndChooseVSInstance();
return this->EnumerateAndChooseVSInstance(version);
}
bool cmVSSetupAPIHelper::IsVSInstalled(int version)
{
return this->EnumerateAndChooseVSInstance(version);
}
bool cmVSSetupAPIHelper::IsVS2017Installed()
{
return this->EnumerateAndChooseVSInstance();
return IsVSInstalled(15);
}
bool cmVSSetupAPIHelper::IsWin10SDKInstalled()
bool cmVSSetupAPIHelper::IsWin10SDKInstalled(int version)
{
return (this->EnumerateAndChooseVSInstance() &&
return (this->EnumerateAndChooseVSInstance(version) &&
chosenInstanceInfo.IsWin10SDKInstalled);
}
bool cmVSSetupAPIHelper::IsWin81SDKInstalled()
bool cmVSSetupAPIHelper::IsWin81SDKInstalled(int version)
{
return (this->EnumerateAndChooseVSInstance() &&
return (this->EnumerateAndChooseVSInstance(version) &&
chosenInstanceInfo.IsWin81SDKInstalled);
}
......@@ -243,10 +249,11 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
return true;
}
bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation)
bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation,
int version)
{
vsInstallLocation.clear();
bool isInstalled = this->EnumerateAndChooseVSInstance();
bool isInstalled = this->EnumerateAndChooseVSInstance(version);
if (isInstalled) {
vsInstallLocation = chosenInstanceInfo.GetInstallLocation();
......@@ -255,10 +262,11 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation)
return isInstalled;
}
bool cmVSSetupAPIHelper::GetVCToolsetVersion(std::string& vsToolsetVersion)
bool cmVSSetupAPIHelper::GetVCToolsetVersion(std::string& vsToolsetVersion,
int version)
{
vsToolsetVersion.clear();
bool isInstalled = this->EnumerateAndChooseVSInstance();
bool isInstalled = this->EnumerateAndChooseVSInstance(version);