1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-06-10 07:58:03 +08:00
CMake/Source/cmGlobalVisualStudio10Generator.cxx
Brad King 4313c5acbc VS: Revert "Write ZERO_CHECK.proj for VS19 and above"
Revert commit 925da7d428 (VS: Write ZERO_CHECK.proj for VS19 and above,
2021-12-24).  Although its commit message was mistakenly not updated, it
implemented the change for VS 2017 and below too.  Since it was merged,
I've discovered several subtle failures in nightly testing with VS 2017.
Revert the change pending further investigation.
2022-02-17 11:23:02 -05:00

1784 lines
58 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalVisualStudio10Generator.h"
#include <algorithm>
#include <cstring>
#include <map>
#include <sstream>
#include <utility>
#include <cm/memory>
#include <cm3p/json/reader.h>
#include <cm3p/json/value.h>
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmDocumentationEntry.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalVisualStudio71Generator.h"
#include "cmGlobalVisualStudio7Generator.h"
#include "cmGlobalVisualStudioGenerator.h"
#include "cmIDEFlagTable.h"
#include "cmLocalGenerator.h"
#include "cmLocalVisualStudio10Generator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmSourceFile.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
#include "cmVisualStudioSlnData.h"
#include "cmVisualStudioSlnParser.h"
#include "cmXMLWriter.h"
#include "cmake.h"
static const char vs10generatorName[] = "Visual Studio 10 2010";
static std::map<std::string, std::vector<cmIDEFlagTable>> loadedFlagJsonFiles;
static void ConvertToWindowsSlashes(std::string& s)
{
// first convert all of the slashes
for (auto& ch : s) {
if (ch == '/') {
ch = '\\';
}
}
}
// Map generator name without year to name with year.
static const char* cmVS10GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs10generatorName,
sizeof(vs10generatorName) - 6) != 0) {
return 0;
}
const char* p = name.c_str() + sizeof(vs10generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2010")) {
p += 5;
}
genName = std::string(vs10generatorName) + p;
return p;
}
class cmGlobalVisualStudio10Generator::Factory
: public cmGlobalGeneratorFactory
{
public:
std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
const std::string& name, bool allowArch, cmake* cm) const override
{
std::string genName;
const char* p = cmVS10GenName(name, genName);
if (!p) {
return std::unique_ptr<cmGlobalGenerator>();
}
if (!*p) {
return std::unique_ptr<cmGlobalGenerator>(
new cmGlobalVisualStudio10Generator(cm, genName, ""));
}
if (!allowArch || *p++ != ' ') {
return std::unique_ptr<cmGlobalGenerator>();
}
if (strcmp(p, "Win64") == 0) {
return std::unique_ptr<cmGlobalGenerator>(
new cmGlobalVisualStudio10Generator(cm, genName, "x64"));
}
if (strcmp(p, "IA64") == 0) {
return std::unique_ptr<cmGlobalGenerator>(
new cmGlobalVisualStudio10Generator(cm, genName, "Itanium"));
}
return std::unique_ptr<cmGlobalGenerator>();
}
void GetDocumentation(cmDocumentationEntry& entry) const override
{
entry.Name = std::string(vs10generatorName) + " [arch]";
entry.Brief = "Deprecated. Generates Visual Studio 2010 project files. "
"Optional [arch] can be \"Win64\" or \"IA64\".";
}
std::vector<std::string> GetGeneratorNames() const override
{
std::vector<std::string> names;
names.push_back(vs10generatorName);
return names;
}
std::vector<std::string> GetGeneratorNamesWithPlatform() const override
{
std::vector<std::string> names;
names.push_back(vs10generatorName + std::string(" IA64"));
names.push_back(vs10generatorName + std::string(" Win64"));
return names;
}
bool SupportsToolset() const override { return true; }
bool SupportsPlatform() const override { return true; }
std::vector<std::string> GetKnownPlatforms() const override
{
std::vector<std::string> platforms;
platforms.emplace_back("x64");
platforms.emplace_back("Win32");
platforms.emplace_back("Itanium");
return platforms;
}
std::string GetDefaultPlatformName() const override { return "Win32"; }
};
std::unique_ptr<cmGlobalGeneratorFactory>
cmGlobalVisualStudio10Generator::NewFactory()
{
return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
}
cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
cmake* cm, const std::string& name,
std::string const& platformInGeneratorName)
: cmGlobalVisualStudio8Generator(cm, name, platformInGeneratorName)
{
std::string vc10Express;
this->ExpressEdition = cmSystemTools::ReadRegistryValue(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
"ProductDir",
vc10Express, cmSystemTools::KeyWOW64_32);
this->CudaEnabled = false;
{
std::string envPlatformToolset;
if (cmSystemTools::GetEnv("PlatformToolset", envPlatformToolset) &&
envPlatformToolset == "Windows7.1SDK") {
// We are running from a Windows7.1SDK command prompt.
this->DefaultPlatformToolset = "Windows7.1SDK";
} else {
this->DefaultPlatformToolset = "v100";
}
}
this->DefaultCLFlagTableName = "v10";
this->DefaultCSharpFlagTableName = "v10";
this->DefaultLibFlagTableName = "v10";
this->DefaultLinkFlagTableName = "v10";
this->DefaultCudaFlagTableName = "v10";
this->DefaultCudaHostFlagTableName = "v10";
this->DefaultMasmFlagTableName = "v10";
this->DefaultNasmFlagTableName = "v10";
this->DefaultRCFlagTableName = "v10";
this->Version = VSVersion::VS10;
this->PlatformToolsetNeedsDebugEnum = false;
}
bool cmGlobalVisualStudio10Generator::MatchesGeneratorName(
const std::string& name) const
{
std::string genName;
if (cmVS10GenName(name, genName)) {
return genName == this->GetName();
}
return false;
}
bool cmGlobalVisualStudio10Generator::SetSystemName(std::string const& s,
cmMakefile* mf)
{
this->SystemName = s;
this->SystemVersion = mf->GetSafeDefinition("CMAKE_SYSTEM_VERSION");
if (!this->InitializeSystem(mf)) {
return false;
}
return this->cmGlobalVisualStudio8Generator::SetSystemName(s, mf);
}
bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
std::string const& p, cmMakefile* mf)
{
if (!this->cmGlobalVisualStudio8Generator::SetGeneratorPlatform(p, mf)) {
return false;
}
if (this->GetPlatformName() == "Itanium" ||
this->GetPlatformName() == "x64") {
if (this->IsExpressEdition() && !this->Find64BitTools(mf)) {
return false;
}
}
return true;
}
static void cmCudaToolVersion(std::string& s)
{
// "CUDA x.y.props" => "x.y"
s = s.substr(5);
s = s.substr(0, s.size() - 6);
}
bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
std::string const& ts, bool build, cmMakefile* mf)
{
if (this->SystemIsWindowsCE && ts.empty() &&
this->DefaultPlatformToolset.empty()) {
std::ostringstream e;
e << this->GetName() << " Windows CE version '" << this->SystemVersion
<< "' requires CMAKE_GENERATOR_TOOLSET to be set.";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
if (!this->ParseGeneratorToolset(ts, mf)) {
return false;
}
if (build) {
return true;
}
if (this->CustomVCTargetsPath.empty() && !this->FindVCTargetsPath(mf)) {
return false;
}
if (!this->CustomFlagTableDir.empty() &&
!(cmSystemTools::FileIsFullPath(this->CustomFlagTableDir) &&
cmSystemTools::FileIsDirectory(this->CustomFlagTableDir))) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"given toolset\n"
" customFlagTableDir=" << this->CustomFlagTableDir << "\n"
"that is not an absolute path to an existing directory.";
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
if (cmHasLiteralPrefix(this->GetPlatformToolsetString(), "v140")) {
// The GenerateDebugInformation link setting for the v140 toolset
// in VS 2015 was originally an enum with "No" and "Debug" values,
// differing from the "false" and "true" values used in older toolsets.
// A VS 2015 update changed it back. Parse the "link.xml" file to
// discover which one we need.
std::string const link_xml = this->VCTargetsPath + "/1033/link.xml";
cmsys::ifstream fin(link_xml.c_str());
std::string line;
while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
if (line.find(" Switch=\"DEBUG\" ") != std::string::npos) {
this->PlatformToolsetNeedsDebugEnum =
line.find(" Name=\"Debug\" ") != std::string::npos;
break;
}
}
}
this->SupportsUnityBuilds =
this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 ||
(this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS15 &&
cmSystemTools::PathExists(this->VCTargetsPath +
"/Microsoft.Cpp.Unity.targets"));
if (this->GeneratorToolsetCuda.empty()) {
// Find the highest available version of the CUDA tools.
std::vector<std::string> cudaTools;
std::string bcDir;
if (this->GeneratorToolsetCudaCustomDir.empty()) {
bcDir = this->VCTargetsPath + "/BuildCustomizations";
} else {
bcDir = this->GetPlatformToolsetCudaCustomDirString() +
this->GetPlatformToolsetCudaVSIntegrationSubdirString() +
"extras\\visual_studio_integration\\MSBuildExtensions";
cmSystemTools::ConvertToUnixSlashes(bcDir);
}
cmsys::Glob gl;
gl.SetRelative(bcDir.c_str());
if (gl.FindFiles(bcDir + "/CUDA *.props")) {
cudaTools = gl.GetFiles();
}
if (!cudaTools.empty()) {
std::for_each(cudaTools.begin(), cudaTools.end(), cmCudaToolVersion);
std::sort(cudaTools.begin(), cudaTools.end(),
cmSystemTools::VersionCompareGreater);
this->GeneratorToolsetCuda = cudaTools.at(0);
} else if (!this->GeneratorToolsetCudaCustomDir.empty()) {
// Generate an error if Visual Studio integration files are not found
// inside of custom cuda toolset.
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"given toolset\n"
" cuda=" << this->GeneratorToolsetCudaCustomDir << "\n"
"cannot detect Visual Studio integration files in path\n"
" " << bcDir;
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
// Clear the configured tool-set
this->GeneratorToolsetCuda.clear();
}
}
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 versionToolset = this->GeneratorToolsetVersion;
cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9][0-9]");
if (regex.find(versionToolset)) {
versionToolset = "v" + versionToolset.erase(2, 1);
} else {
// Version not recognized. Clear it.
versionToolset.clear();
}
if (!cmHasPrefix(versionToolset, this->GetPlatformToolsetString())) {
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(MessageType::FATAL_ERROR, e.str());
// Clear the configured tool-set
this->GeneratorToolsetVersion.clear();
}
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 <<
"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" <<
" " << 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 (!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);
}
if (const char* cuda = this->GetPlatformToolsetCuda()) {
mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA", cuda);
}
if (const char* cudaDir = this->GetPlatformToolsetCudaCustomDir()) {
mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR", cudaDir);
}
if (const char* vcTargetsDir = this->GetCustomVCTargetsPath()) {
mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR",
vcTargetsDir);
}
return true;
}
bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
std::string const& ts, cmMakefile* mf)
{
std::vector<std::string> const fields = cmTokenize(ts, ",");
std::vector<std::string>::const_iterator fi = fields.begin();
if (fi == fields.end()) {
return true;
}
// The first field may be the VS platform toolset.
if (fi->find('=') == fi->npos) {
this->GeneratorToolset = *fi;
++fi;
}
std::set<std::string> handled;
// The rest of the fields must be key=value pairs.
for (; fi != fields.end(); ++fi) {
std::string::size_type pos = fi->find('=');
if (pos == fi->npos) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"given toolset specification\n"
" " << ts << "\n"
"that contains a field after the first ',' with no '='."
;
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
std::string const key = fi->substr(0, pos);
std::string const value = fi->substr(pos + 1);
if (!handled.insert(key).second) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"given toolset specification\n"
" " << ts << "\n"
"that contains duplicate field key '" << key << "'."
;
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
if (!this->ProcessGeneratorToolsetField(key, value)) {
std::ostringstream e;
/* clang-format off */
e <<
"Generator\n"
" " << this->GetName() << "\n"
"given toolset specification\n"
" " << ts << "\n"
"that contains invalid field '" << *fi << "'."
;
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
}
return true;
}
bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
std::string const& key, std::string const& value)
{
if (key == "cuda") {
/* test if cuda toolset is path to custom dir or cuda version */
auto pos = value.find_first_not_of("0123456789.");
if (pos != std::string::npos) {
this->GeneratorToolsetCudaCustomDir = value;
/* ensure trailing backslash for easy path joining */
if (this->GeneratorToolsetCudaCustomDir.back() != '\\') {
this->GeneratorToolsetCudaCustomDir.push_back('\\');
}
/* check for legacy toolkit folder structure */
if (cmsys::SystemTools::FileIsDirectory(
cmStrCat(this->GeneratorToolsetCudaCustomDir, "nvcc"))) {
this->GeneratorToolsetCudaNvccSubdir = "nvcc\\";
}
if (cmsys::SystemTools::FileIsDirectory(
cmStrCat(this->GeneratorToolsetCudaCustomDir,
"CUDAVisualStudioIntegration"))) {
this->GeneratorToolsetCudaVSIntegrationSubdir =
"CUDAVisualStudioIntegration\\";
}
} else {
this->GeneratorToolsetCuda = value;
}
return true;
}
if (key == "customFlagTableDir") {
this->CustomFlagTableDir = value;
cmSystemTools::ConvertToUnixSlashes(this->CustomFlagTableDir);
return true;
}
if (key == "version") {
this->GeneratorToolsetVersion = value;
return true;
}
if (key == "VCTargetsPath") {
this->CustomVCTargetsPath = value;
ConvertToWindowsSlashes(this->CustomVCTargetsPath);
return true;
}
return false;
}
bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
{
if (this->SystemName == "Windows") {
if (!this->InitializeWindows(mf)) {
return false;
}
} else if (this->SystemName == "WindowsCE") {
this->SystemIsWindowsCE = true;
if (!this->InitializeWindowsCE(mf)) {
return false;
}
} else if (this->SystemName == "WindowsPhone") {
this->SystemIsWindowsPhone = true;
if (!this->InitializeWindowsPhone(mf)) {
return false;
}
} else if (this->SystemName == "WindowsStore") {
this->SystemIsWindowsStore = true;
if (!this->InitializeWindowsStore(mf)) {
return false;
}
} else if (this->SystemName == "Android") {
if (this->PlatformInGeneratorName) {
std::ostringstream e;
e << "CMAKE_SYSTEM_NAME is 'Android' but CMAKE_GENERATOR "
<< "specifies a platform too: '" << this->GetName() << "'";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
if (mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM") == "Tegra-Android") {
if (!this->InitializeTegraAndroid(mf)) {
return false;
}
} else {
this->SystemIsAndroid = true;
if (!this->InitializeAndroid(mf)) {
return false;
}
}
}
return true;
}
bool cmGlobalVisualStudio10Generator::InitializeWindows(cmMakefile*)
{
return true;
}
bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
{
if (this->PlatformInGeneratorName) {
std::ostringstream e;
e << "CMAKE_SYSTEM_NAME is 'WindowsCE' but CMAKE_GENERATOR "
<< "specifies a platform too: '" << this->GetName() << "'";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
if (this->GetVersion() == cmGlobalVisualStudioGenerator::VSVersion::VS12) {
// VS 12 .NET CF defaults to .NET framework 3.9 for Windows CE.
this->DefaultTargetFrameworkVersion = "v3.9";
this->DefaultTargetFrameworkIdentifier = "WindowsEmbeddedCompact";
this->DefaultTargetFrameworkTargetsVersion = "v8.0";
}
return true;
}
bool cmGlobalVisualStudio10Generator::InitializeWindowsPhone(cmMakefile* mf)
{
std::ostringstream e;
e << this->GetName() << " does not support Windows Phone.";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
{
std::ostringstream e;
e << this->GetName() << " does not support Windows Store.";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf)
{
std::string v = this->GetInstalledNsightTegraVersion();
if (v.empty()) {
mf->IssueMessage(MessageType::FATAL_ERROR,
"CMAKE_SYSTEM_NAME is 'Android' but "
"'NVIDIA Nsight Tegra Visual Studio Edition' "
"is not installed.");
return false;
}
this->DefaultPlatformName = "Tegra-Android";
this->DefaultPlatformToolset = "Default";
this->NsightTegraVersion = v;
mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v);
return true;
}
bool cmGlobalVisualStudio10Generator::InitializeAndroid(cmMakefile* mf)
{
std::ostringstream e;
e << this->GetName() << " does not support Android.";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
std::string& toolset) const
{
toolset.clear();
return false;
}
bool cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
std::string& toolset) const
{
toolset.clear();
return false;
}
std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
{
if (this->SystemVersion == "8.0") {
return "CE800";
}
return "";
}
//! Create a local generator appropriate to this Global Generator
std::unique_ptr<cmLocalGenerator>
cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmMakefile* mf)
{
return std::unique_ptr<cmLocalGenerator>(
cm::make_unique<cmLocalVisualStudio10Generator>(this, mf));
}
void cmGlobalVisualStudio10Generator::Generate()
{
this->LongestSource = LongestSourcePath();
this->cmGlobalVisualStudio8Generator::Generate();
if (!this->AndroidExecutableWarnings.empty() &&
!this->CMakeInstance->GetIsInTryCompile()) {
std::ostringstream e;
/* clang-format off */
e <<
"You are using Visual Studio tools for Android, which does not support "
"standalone executables. However, the following executable targets do "
"not have the ANDROID_GUI property set, and thus will not be built as "
"expected. They will be built as shared libraries with executable "
"filenames:\n"
" ";
/* clang-format on */
bool first = true;
for (auto const& name : this->AndroidExecutableWarnings) {
if (!first) {
e << ", ";
}
first = false;
e << name;
}
this->CMakeInstance->IssueMessage(MessageType::WARNING, e.str());
}
if (this->LongestSource.Length > 0) {
cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator();
std::ostringstream e;
/* clang-format off */
e <<
"The binary and/or source directory paths may be too long to generate "
"Visual Studio 10 files for this project. "
"Consider choosing shorter directory names to build this project with "
"Visual Studio 10. "
"A more detailed explanation follows."
"\n"
"There is a bug in the VS 10 IDE that renders property dialog fields "
"blank for files referenced by full path in the project file. "
"However, CMake must reference at least one file by full path:\n"
" " << this->LongestSource.SourceFile->GetFullPath() << "\n"
"This is because some Visual Studio tools would append the relative "
"path to the end of the referencing directory path, as in:\n"
" " << lg->GetCurrentBinaryDirectory() << "/"
<< this->LongestSource.SourceRel << "\n"
"and then incorrectly complain that the file does not exist because "
"the path length is too long for some internal buffer or API. "
"To avoid this problem CMake must use a full path for this file "
"which then triggers the VS 10 property dialog bug.";
/* clang-format on */
lg->IssueMessage(MessageType::WARNING, e.str());
}
if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
"CMAKE_VS_NUGET_PACKAGE_RESTORE")) {
this->CMakeInstance->MarkCliAsUsed("CMAKE_VS_NUGET_PACKAGE_RESTORE");
}
}
void cmGlobalVisualStudio10Generator::EnableLanguage(
std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
{
for (std::string const& it : lang) {
if (it == "ASM_NASM") {
this->NasmEnabled = true;
}
if (it == "CUDA") {
this->CudaEnabled = true;
}
}
this->AddPlatformDefinitions(mf);
cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
}
const char* cmGlobalVisualStudio10Generator::GetCustomVCTargetsPath() const
{
if (this->CustomVCTargetsPath.empty()) {
return nullptr;
}
return this->CustomVCTargetsPath.c_str();
}
const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
{
std::string const& toolset = this->GetPlatformToolsetString();
if (toolset.empty()) {
return nullptr;
}
return toolset.c_str();
}
std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString()
const
{
if (!this->GeneratorToolset.empty()) {
return this->GeneratorToolset;
}
if (this->SystemIsAndroid) {
if (!this->DefaultAndroidToolset.empty()) {
return this->DefaultAndroidToolset;
}
} else {
if (!this->DefaultPlatformToolset.empty()) {
return this->DefaultPlatformToolset;
}
}
static std::string const empty;
return empty;
}
std::string const&
cmGlobalVisualStudio10Generator::GetPlatformToolsetVersionProps() const
{
return this->GeneratorToolsetVersionProps;
}
const char*
cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
{
std::string const& hostArch =
this->GetPlatformToolsetHostArchitectureString();
if (hostArch.empty()) {
return nullptr;
}
return hostArch.c_str();
}
std::string const&
cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitectureString()
const
{
if (!this->GeneratorToolsetHostArchitecture.empty()) {
return this->GeneratorToolsetHostArchitecture;
}
if (!this->DefaultPlatformToolsetHostArchitecture.empty()) {
return this->DefaultPlatformToolsetHostArchitecture;
}
static std::string const empty;
return empty;
}
const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCuda() const
{
if (!this->GeneratorToolsetCuda.empty()) {
return this->GeneratorToolsetCuda.c_str();
}
return nullptr;
}
std::string const&
cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
{
return this->GeneratorToolsetCuda;
}
const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDir()
const
{
if (!this->GeneratorToolsetCudaCustomDir.empty()) {
return this->GeneratorToolsetCudaCustomDir.c_str();
}
return nullptr;
}
std::string const&
cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDirString() const
{
return this->GeneratorToolsetCudaCustomDir;
}
std::string const&
cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaNvccSubdirString() const
{
return this->GeneratorToolsetCudaNvccSubdir;
}
std::string const& cmGlobalVisualStudio10Generator::
GetPlatformToolsetCudaVSIntegrationSubdirString() const
{
return this->GeneratorToolsetCudaVSIntegrationSubdir;
}
cmGlobalVisualStudio10Generator::AuxToolset
cmGlobalVisualStudio10Generator::FindAuxToolset(std::string&,
std::string&) const
{
return AuxToolset::None;
}
bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
{
if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
return false;
}
mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND", this->GetMSBuildCommand());
return true;
}
std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
{
if (!this->MSBuildCommandInitialized) {
this->MSBuildCommandInitialized = true;
this->MSBuildCommand = this->FindMSBuildCommand();
}
return this->MSBuildCommand;
}
cm::optional<std::string>
cmGlobalVisualStudio10Generator::FindMSBuildCommandEarly(cmMakefile*)
{
return this->GetMSBuildCommand();
}
std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
{
std::string msbuild;
std::string mskey;
// Search in standard location.
mskey = cmStrCat(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\",
this->GetToolsVersion(), ";MSBuildToolsPath");
if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild,
cmSystemTools::KeyWOW64_32)) {
cmSystemTools::ConvertToUnixSlashes(msbuild);
msbuild += "/MSBuild.exe";
if (cmSystemTools::FileExists(msbuild, true)) {
return msbuild;
}
}
msbuild = "MSBuild.exe";
return msbuild;
}
std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
{
if (this->ExpressEdition) {
// Visual Studio Express >= 10 do not have "devenv.com" or
// "VCExpress.exe" that we can use to build reliably.
// Tell the caller it needs to use MSBuild instead.
return "";
}
// Skip over the cmGlobalVisualStudio8Generator implementation because
// we expect a real devenv and do not want to look for VCExpress.
return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
}
bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
{
// Skip this in special cases within our own test suite.
if (this->GetPlatformName() == "Test Platform" ||
this->GetPlatformToolsetString() == "Test Toolset") {
return true;
}
std::string wd;
if (!this->ConfiguredFilesPath.empty()) {
// In a try-compile we are given the outer CMakeFiles directory.
wd = this->ConfiguredFilesPath;
} else {
wd = cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
"/CMakeFiles");
}
wd += "/";
wd += cmVersion::GetCMakeVersion();
// We record the result persistently in a file.
std::string const txt = wd + "/VCTargetsPath.txt";
// If we have a recorded result, use it.
{
cmsys::ifstream fin(txt.c_str());
if (fin && cmSystemTools::GetLineFromStream(fin, this->VCTargetsPath) &&
cmSystemTools::FileIsDirectory(this->VCTargetsPath)) {
cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
return true;
}
}
// Prepare the work directory.
if (!cmSystemTools::MakeDirectory(wd)) {
std::string e = "Failed to make directory:\n " + wd;
mf->IssueMessage(MessageType::FATAL_ERROR, e);
cmSystemTools::SetFatalErrorOccured();
return false;
}
// Generate a project file for MSBuild to tell us the VCTargetsPath value.
std::string const vcxproj = "VCTargetsPath.vcxproj";
{
std::string const vcxprojAbs = wd + "/" + vcxproj;
cmsys::ofstream fout(vcxprojAbs.c_str());
cmXMLWriter xw(fout);
cmXMLDocument doc(xw);
cmXMLElement eprj(doc, "Project");
eprj.Attribute("DefaultTargets", "Build");
eprj.Attribute("ToolsVersion", "4.0");
eprj.Attribute("xmlns",
"http://schemas.microsoft.com/developer/msbuild/2003");
if (this->IsNsightTegra()) {
cmXMLElement epg(eprj, "PropertyGroup");
epg.Attribute("Label", "NsightTegraProject");
cmXMLElement(epg, "NsightTegraProjectRevisionNumber").Content("6");
}
{
cmXMLElement eig(eprj, "ItemGroup");
eig.Attribute("Label", "ProjectConfigurations");
cmXMLElement epc(eig, "ProjectConfiguration");
epc.Attribute("Include", "Debug|" + this->GetPlatformName());
cmXMLElement(epc, "Configuration").Content("Debug");
cmXMLElement(epc, "Platform").Content(this->GetPlatformName());
}
{
cmXMLElement epg(eprj, "PropertyGroup");
epg.Attribute("Label", "Globals");
cmXMLElement(epg, "ProjectGuid")
.Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}");
cmXMLElement(epg, "Keyword")
.Content(mf->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android"
? "Android"
: "Win32Proj");
cmXMLElement(epg, "Platform").Content(this->GetPlatformName());
if (this->GetSystemName() == "WindowsPhone") {
cmXMLElement(epg, "ApplicationType").Content("Windows Phone");
cmXMLElement(epg, "ApplicationTypeRevision")
.Content(this->GetApplicationTypeRevision());
} else if (this->GetSystemName() == "WindowsStore") {
cmXMLElement(epg, "ApplicationType").Content("Windows Store");
cmXMLElement(epg, "ApplicationTypeRevision")
.Content(this->GetApplicationTypeRevision());
} else if (this->GetSystemName() == "Android") {
cmXMLElement(epg, "ApplicationType").Content("Android");
cmXMLElement(epg, "ApplicationTypeRevision")
.Content(this->GetApplicationTypeRevision());
}
if (!this->WindowsTargetPlatformVersion.empty()) {
cmXMLElement(epg, "WindowsTargetPlatformVersion")
.Content(this->WindowsTargetPlatformVersion);
}
if (this->GetSystemName() != "Android") {
if (this->GetPlatformName() == "ARM64") {
cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true");
} else if (this->GetPlatformName() == "ARM") {
cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true");
}
}
}
cmXMLElement(eprj, "Import")
.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
cmXMLElement epg(eprj, "PropertyGroup");
cmXMLElement(epg, "PreferredToolArchitecture").Content(hostArch);
}
{
cmXMLElement epg(eprj, "PropertyGroup");
epg.Attribute("Label", "Configuration");
{
cmXMLElement ect(epg, "ConfigurationType");
if (this->IsNsightTegra()) {
// Tegra-Android platform does not understand "Utility".
ect.Content("StaticLibrary");
} else {
ect.Content("Utility");
}
}
cmXMLElement(epg, "CharacterSet").Content("MultiByte");
if (this->IsNsightTegra()) {
cmXMLElement(epg, "NdkToolchainVersion")
.Content(this->GetPlatformToolsetString());
} else {
cmXMLElement(epg, "PlatformToolset")
.Content(this->GetPlatformToolsetString());
}
}
cmXMLElement(eprj, "Import")
.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
{
cmXMLElement eidg(eprj, "ItemDefinitionGroup");
cmXMLElement epbe(eidg, "PostBuildEvent");
cmXMLElement(epbe, "Command")
.Content("echo VCTargetsPath=$(VCTargetsPath)");
}
cmXMLElement(eprj, "Import")
.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
}
std::vector<std::string> cmd;
cmd.push_back(this->GetMSBuildCommand());
cmd.push_back(vcxproj);
cmd.push_back("/p:Configuration=Debug");
cmd.push_back(cmStrCat("/p:Platform=", this->GetPlatformName()));
cmd.push_back(std::string("/p:VisualStudioVersion=") +
this->GetIDEVersion());
std::string out;
int ret = 0;
cmsys::RegularExpression regex("\n *VCTargetsPath=([^%\r\n]+)[\r\n]");
if (!cmSystemTools::RunSingleCommand(cmd, &out, &out, &ret, wd.c_str(),
cmSystemTools::OUTPUT_NONE) ||
ret != 0 || !regex.find(out)) {
cmSystemTools::ReplaceString(out, "\n", "\n ");
std::ostringstream e;
/* clang-format off */
e <<
"Failed to run MSBuild command:\n"
" " << cmd[0] << "\n"
"to get the value of VCTargetsPath:\n"
" " << out << "\n"
;
/* clang-format on */
if (ret != 0) {
e << "Exit code: " << ret << "\n";
}
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
this->VCTargetsPath = regex.match(1);
cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
{
cmsys::ofstream fout(txt.c_str());
fout << this->VCTargetsPath << "\n";
}
return true;
}
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalVisualStudio10Generator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
const std::string& projectDir, std::vector<std::string> const& targetNames,
const std::string& config, int jobs, bool verbose,
const cmBuildOptions& buildOptions,
std::vector<std::string> const& makeOptions)
{
std::vector<GeneratedMakeCommand> makeCommands;
// Select the caller- or user-preferred make program, else MSBuild.
std::string makeProgramSelected =
this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
// Check if the caller explicitly requested a devenv tool.
std::string makeProgramLower = makeProgramSelected;
cmSystemTools::LowerCase(makeProgramLower);
bool useDevEnv = (makeProgramLower.find("devenv") != std::string::npos ||
makeProgramLower.find("vcexpress") != std::string::npos);
// Workaround to convince VCExpress.exe to produce output.
const bool requiresOutputForward =
(makeProgramLower.find("vcexpress") != std::string::npos);
// MSBuild is preferred (and required for VS Express), but if the .sln has
// an Intel Fortran .vfproj then we have to use devenv. Parse it to find out.
cmSlnData slnData;
{
std::string slnFile;
if (!projectDir.empty()) {
slnFile = cmStrCat(projectDir, '/');
}
slnFile += projectName;
slnFile += ".sln";
cmVisualStudioSlnParser parser;
if (parser.ParseFile(slnFile, slnData,
cmVisualStudioSlnParser::DataGroupAll)) {
std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
for (cmSlnProjectEntry const& project : slnProjects) {
if (useDevEnv) {
break;
}
std::string proj = project.GetRelativePath();
if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
useDevEnv = true;
}
}
}
}
if (useDevEnv) {
// Use devenv to build solutions containing Intel Fortran projects.
return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
makeProgram, projectName, projectDir, targetNames, config, jobs, verbose,
buildOptions, makeOptions);
}
std::vector<std::string> realTargetNames = targetNames;
if (targetNames.empty() ||
((targetNames.size() == 1) && targetNames.front().empty())) {
realTargetNames = { "ALL_BUILD" };
}
for (const auto& tname : realTargetNames) {
// msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
// /target:ALL_BUILD
// /m
if (tname.empty()) {
continue;
}
GeneratedMakeCommand makeCommand;
makeCommand.RequiresOutputForward = requiresOutputForward;
makeCommand.Add(makeProgramSelected);
cm::optional<cmSlnProjectEntry> proj = cm::nullopt;
if (tname == "clean") {
makeCommand.Add(cmStrCat(projectName, ".sln"));
makeCommand.Add("/t:Clean");
} else {
std::string targetProject = cmStrCat(tname, ".vcxproj");
proj = slnData.GetProjectByName(tname);
if (targetProject.find('/') == std::string::npos) {
// it might be in a subdir
if (proj) {
targetProject = proj->GetRelativePath();
cmSystemTools::ConvertToUnixSlashes(targetProject);
}
}
makeCommand.Add(targetProject);
// Check if we do need a restore at all (i.e. if there are package
// references and restore has not been disabled by a command line option.
PackageResolveMode restoreMode = buildOptions.ResolveMode;
bool requiresRestore = true;
if (restoreMode == PackageResolveMode::Disable) {
requiresRestore = false;
} else if (cmValue cached =
this->CMakeInstance->GetState()->GetCacheEntryValue(
tname + "_REQUIRES_VS_PACKAGE_RESTORE")) {
requiresRestore = cached.IsOn();
} else {
// There are no package references defined.
requiresRestore = false;
}
// If a restore is required, evaluate the restore mode.
if (requiresRestore) {
if (restoreMode == PackageResolveMode::OnlyResolve) {
// Only invoke the restore target on the project.
makeCommand.Add("/t:Restore");
} else {
// Invoke restore target, unless it has been explicitly disabled.
bool restorePackages = true;
if (this->Version < VSVersion::VS15) {
// Package restore is only supported starting from Visual Studio
// 2017. Package restore must be executed manually using NuGet
// shell for older versions.
this->CMakeInstance->IssueMessage(
MessageType::WARNING,
"Restoring package references is only supported for Visual "
"Studio 2017 and later. You have to manually restore the "
"packages using NuGet before building the project.");
restorePackages = false;
} else if (restoreMode == PackageResolveMode::Default) {
// Decide if a restore is performed, based on a cache variable.
if (cmValue cached =
this->CMakeInstance->GetState()->GetCacheEntryValue(
"CMAKE_VS_NUGET_PACKAGE_RESTORE"))
restorePackages = cached.IsOn();
}
if (restorePackages) {
if (this->IsMsBuildRestoreSupported()) {
makeCommand.Add("/restore");
} else {
GeneratedMakeCommand restoreCommand;
restoreCommand.Add(makeProgramSelected);
restoreCommand.Add(targetProject);
restoreCommand.Add("/t:Restore");
makeCommands.emplace_back(restoreCommand);
}
}
}
}
}
std::string plainConfig = config;
if (config.empty()) {
plainConfig = "Debug";
}
std::string platform = GetPlatformName();
if (proj) {
std::string extension =
cmSystemTools::GetFilenameLastExtension(proj->GetRelativePath());
extension = cmSystemTools::LowerCase(extension);
if (extension.compare(".csproj") == 0) {
// Use correct platform name
platform =
slnData.GetConfigurationTarget(tname, plainConfig, platform);
}
}
makeCommand.Add(cmStrCat("/p:Configuration=", plainConfig));
makeCommand.Add(cmStrCat("/p:Platform=", platform));
makeCommand.Add(
cmStrCat("/p:VisualStudioVersion=", this->GetIDEVersion()));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
makeCommand.Add("/m");
} else {
makeCommand.Add(cmStrCat("/m:", std::to_string(jobs)));
}
// Having msbuild.exe and cl.exe using multiple jobs is discouraged
makeCommand.Add("/p:CL_MPCount=1");
}
// Respect the verbosity: 'n' normal will show build commands
// 'm' minimal only the build step's title
makeCommand.Add(cmStrCat("/v:", ((verbose) ? "n" : "m")));
makeCommand.Add(makeOptions.begin(), makeOptions.end());
makeCommands.emplace_back(std::move(makeCommand));
}
return makeCommands;
}
bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
{
if (this->DefaultPlatformToolset == "v100") {
// The v100 64-bit toolset does not exist in the express edition.
this->DefaultPlatformToolset.clear();
}
if (this->GetPlatformToolset()) {
return true;
}
// This edition does not come with 64-bit tools. Look for them.
//
// TODO: Detect available tools? x64\v100 exists but does not work?
// HKLM\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\4.0;VCTargetsPath
// c:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/Platforms/
// {Itanium,Win32,x64}/PlatformToolsets/{v100,v90,Windows7.1SDK}
std::string winSDK_7_1;
if (cmSystemTools::ReadRegistryValue(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\"
"Windows\\v7.1;InstallationFolder",
winSDK_7_1)) {
std::ostringstream m;
m << "Found Windows SDK v7.1: " << winSDK_7_1;
mf->DisplayStatus(m.str(), -1);
this->DefaultPlatformToolset = "Windows7.1SDK";
return true;
} else {
std::ostringstream e;
/* clang-format off */
e << "Cannot enable 64-bit tools with Visual Studio 2010 Express.\n"
<< "Install the Microsoft Windows SDK v7.1 to get 64-bit tools:\n"
<< " http://msdn.microsoft.com/en-us/windows/bb980924.aspx";
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
}
std::string cmGlobalVisualStudio10Generator::GenerateRuleFile(
std::string const& output) const
{
// The VS 10 generator needs to create the .rule files on disk.
// Hide them away under the CMakeFiles directory.
std::string ruleDir = cmStrCat(
this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeFiles/",
cmSystemTools::ComputeStringMD5(cmSystemTools::GetFilenamePath(output)));
std::string ruleFile =
cmStrCat(ruleDir, '/', cmSystemTools::GetFilenameName(output), ".rule");
return ruleFile;
}
void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target,
cmSourceFile const* sf,
std::string const& sfRel)
{
size_t len =
(target->GetLocalGenerator()->GetCurrentBinaryDirectory().length() + 1 +
sfRel.length());
if (len > this->LongestSource.Length) {
this->LongestSource.Length = len;
this->LongestSource.Target = target;
this->LongestSource.SourceFile = sf;
this->LongestSource.SourceRel = sfRel;
}
}
std::string cmGlobalVisualStudio10Generator::Encoding()
{
return "utf-8";
}
const char* cmGlobalVisualStudio10Generator::GetToolsVersion() const
{
switch (this->Version) {
case cmGlobalVisualStudioGenerator::VSVersion::VS9:
case cmGlobalVisualStudioGenerator::VSVersion::VS10:
case cmGlobalVisualStudioGenerator::VSVersion::VS11:
return "4.0";
// in Visual Studio 2013 they detached the MSBuild tools version
// from the .Net Framework version and instead made it have it's own
// version number
case cmGlobalVisualStudioGenerator::VSVersion::VS12:
return "12.0";
case cmGlobalVisualStudioGenerator::VSVersion::VS14:
return "14.0";
case cmGlobalVisualStudioGenerator::VSVersion::VS15:
return "15.0";
case cmGlobalVisualStudioGenerator::VSVersion::VS16:
return "16.0";
case cmGlobalVisualStudioGenerator::VSVersion::VS17:
return "17.0";
}
return "";
}
bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
{
return !this->NsightTegraVersion.empty();
}
std::string cmGlobalVisualStudio10Generator::GetNsightTegraVersion() const
{
return this->NsightTegraVersion;
}
std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
{
std::string version;
cmSystemTools::ReadRegistryValue(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;"
"Version",
version, cmSystemTools::KeyWOW64_32);
return version;
}
std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const
{
if (this->GetSystemName() == "Android") {
return this->GetAndroidApplicationTypeRevision();
}
// Return the first two '.'-separated components of the Windows version.
std::string::size_type end1 = this->SystemVersion.find('.');
std::string::size_type end2 =
end1 == std::string::npos ? end1 : this->SystemVersion.find('.', end1 + 1);
return this->SystemVersion.substr(0, end2);
}
static std::string cmLoadFlagTableString(Json::Value entry, const char* field)
{
if (entry.isMember(field)) {
auto string = entry[field];
if (string.isConvertibleTo(Json::ValueType::stringValue)) {
return string.asString();
}
}
return "";
}
static unsigned int cmLoadFlagTableSpecial(Json::Value entry,
const char* field)
{
unsigned int value = 0;
if (entry.isMember(field)) {
auto specials = entry[field];
if (specials.isArray()) {
for (auto const& special : specials) {
std::string s = special.asString();
if (s == "UserValue") {
value |= cmIDEFlagTable::UserValue;
} else if (s == "UserIgnored") {
value |= cmIDEFlagTable::UserIgnored;
} else if (s == "UserRequired") {
value |= cmIDEFlagTable::UserRequired;
} else if (s == "Continue") {
value |= cmIDEFlagTable::Continue;
} else if (s == "SemicolonAppendable") {
value |= cmIDEFlagTable::SemicolonAppendable;
} else if (s == "UserFollowing") {
value |= cmIDEFlagTable::UserFollowing;
} else if (s == "CaseInsensitive") {
value |= cmIDEFlagTable::CaseInsensitive;
} else if (s == "SpaceAppendable") {
value |= cmIDEFlagTable::SpaceAppendable;
} else if (s == "CommaAppendable") {
value |= cmIDEFlagTable::CommaAppendable;
}
}
}
}
return value;
}
namespace {
cmIDEFlagTable const* cmLoadFlagTableJson(std::string const& flagJsonPath,
cm::optional<std::string> vsVer)
{
cmIDEFlagTable* ret = nullptr;
auto savedFlagIterator = loadedFlagJsonFiles.find(flagJsonPath);
if (savedFlagIterator != loadedFlagJsonFiles.end()) {
ret = savedFlagIterator->second.data();
} else {
Json::Reader reader;
cmsys::ifstream stream;
stream.open(flagJsonPath.c_str(), std::ios_base::in);
if (stream) {
Json::Value flags;
if (reader.parse(stream, flags, false) && flags.isArray()) {
std::vector<cmIDEFlagTable> flagTable;
for (auto const& flag : flags) {
Json::Value const& vsminJson = flag["vsmin"];
if (vsminJson.isString()) {
std::string const& vsmin = vsminJson.asString();
if (!vsmin.empty()) {
if (!vsVer ||
cmSystemTools::VersionCompareGreater(vsmin, *vsVer)) {
continue;
}
}
}
cmIDEFlagTable flagEntry;
flagEntry.IDEName = cmLoadFlagTableString(flag, "name");
flagEntry.commandFlag = cmLoadFlagTableString(flag, "switch");
flagEntry.comment = cmLoadFlagTableString(flag, "comment");
flagEntry.value = cmLoadFlagTableString(flag, "value");
flagEntry.special = cmLoadFlagTableSpecial(flag, "flags");
flagTable.push_back(flagEntry);
}
cmIDEFlagTable endFlag{ "", "", "", "", 0 };
flagTable.push_back(endFlag);
loadedFlagJsonFiles[flagJsonPath] = flagTable;
ret = loadedFlagJsonFiles[flagJsonPath].data();
}
}
}
return ret;
}
}
cm::optional<std::string> cmGlobalVisualStudio10Generator::FindFlagTable(
cm::string_view toolsetName, cm::string_view table) const
{
if (!this->CustomFlagTableDir.empty()) {
std::string customFlagTableFile =
cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
toolsetName, '_', table, ".json");
if (cmSystemTools::FileExists(customFlagTableFile)) {
return customFlagTableFile;
}
customFlagTableFile =
cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
table, ".json");
if (cmSystemTools::FileExists(customFlagTableFile)) {
return customFlagTableFile;
}
}
std::string fullPath =
cmStrCat(cmSystemTools::GetCMakeRoot(), "/Templates/MSBuild/FlagTables/",
toolsetName, '_', table, ".json");
if (cmSystemTools::FileExists(fullPath)) {
return fullPath;
}
return {};
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::LoadFlagTable(
std::string const& toolSpecificName, std::string const& defaultName,
std::string const& table) const
{
cmMakefile* mf = this->GetCurrentMakefile();
std::string filename;
if (!toolSpecificName.empty()) {
if (cm::optional<std::string> found =
this->FindFlagTable(toolSpecificName, table)) {
filename = std::move(*found);
} else {
mf->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("JSON flag table for ", table,
" not found for toolset ", toolSpecificName));
return nullptr;
}
} else {
std::string const& genericName =
this->CanonicalToolsetName(this->GetPlatformToolsetString());
cm::optional<std::string> found = this->FindFlagTable(genericName, table);
if (!found) {
found = this->FindFlagTable(defaultName, table);
}
if (found) {
filename = std::move(*found);
} else {
mf->IssueMessage(MessageType::FATAL_ERROR,
cmStrCat("JSON flag table for ", table,
" not found for toolset ", genericName, " ",
defaultName));
return nullptr;
}
}
cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename, vsVer)) {
return ret;
}
mf->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("JSON flag table could not be loaded:\n ", filename));
return nullptr;
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetClFlagTable() const
{
return LoadFlagTable(this->GetClFlagTableName(),
this->DefaultCLFlagTableName, "CL");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCSharpFlagTable()
const
{
return LoadFlagTable(this->GetCSharpFlagTableName(),
this->DefaultCSharpFlagTableName, "CSharp");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetRcFlagTable() const
{
return LoadFlagTable(this->GetRcFlagTableName(),
this->DefaultRCFlagTableName, "RC");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLibFlagTable() const
{
return LoadFlagTable(this->GetLibFlagTableName(),
this->DefaultLibFlagTableName, "LIB");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
{
return LoadFlagTable(this->GetLinkFlagTableName(),
this->DefaultLinkFlagTableName, "Link");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaFlagTable() const
{
return LoadFlagTable(std::string(), this->DefaultCudaFlagTableName, "Cuda");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
const
{
return LoadFlagTable(std::string(), this->DefaultCudaHostFlagTableName,
"CudaHost");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
{
return LoadFlagTable(this->GetMasmFlagTableName(),
this->DefaultMasmFlagTableName, "MASM");
}
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
{
return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
}
bool cmGlobalVisualStudio10Generator::IsMsBuildRestoreSupported() const
{
if (this->Version >= VSVersion::VS16) {
return true;
}
static std::string const vsVer15_7_5 = "15.7.27703.2042";
cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
return (vsVer &&
cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_7_5));
}
std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
std::string const useToolset = this->CanonicalToolsetName(toolset);
if (toolset == "v142") {
return "v142";
} else if (toolset == "v141") {
return "v141";
} else if (useToolset == "v140") {
return "v140";
} else if (useToolset == "v120") {
return "v12";
} else if (useToolset == "v110") {
return "v11";
} else if (useToolset == "v100") {
return "v10";
} else {
return "";
}
}
std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
std::string const useToolset = this->CanonicalToolsetName(toolset);
if (useToolset == "v142") {
return "v142";
} else if (useToolset == "v141") {
return "v141";
} else if (useToolset == "v140") {
return "v140";
} else if (useToolset == "v120") {
return "v12";
} else if (useToolset == "v110") {
return "v11";
} else if (useToolset == "v100") {
return "v10";
} else {
return "";
}
}
std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
std::string const useToolset = this->CanonicalToolsetName(toolset);
if ((useToolset == "v140") || (useToolset == "v141") ||
(useToolset == "v142")) {
return "v14";
} else if (useToolset == "v120") {
return "v12";
} else if (useToolset == "v110") {
return "v11";
} else if (useToolset == "v100") {
return "v10";
} else {
return "";
}
}
std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
std::string const useToolset = this->CanonicalToolsetName(toolset);
if ((useToolset == "v140") || (useToolset == "v141") ||
(useToolset == "v142")) {
return "v14";
} else if (useToolset == "v120") {
return "v12";
} else if (useToolset == "v110") {
return "v11";
} else if (useToolset == "v100") {
return "v10";
} else {
return "";
}
}
std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
std::string const useToolset = this->CanonicalToolsetName(toolset);
if (useToolset == "v142") {
return "v142";
} else if (useToolset == "v141") {
return "v141";
} else if (useToolset == "v140") {
return "v140";
} else if (useToolset == "v120") {
return "v12";
} else if (useToolset == "v110") {
return "v11";
} else if (useToolset == "v100") {
return "v10";
} else {
return "";
}
}
std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
std::string const useToolset = this->CanonicalToolsetName(toolset);
if ((useToolset == "v140") || (useToolset == "v141") ||
(useToolset == "v142")) {
return "v14";
} else if (useToolset == "v120") {
return "v12";
} else if (useToolset == "v110") {
return "v11";
} else if (useToolset == "v100") {
return "v10";
} else {
return "";
}
}
std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName(
std::string const& toolset) const
{
std::size_t length = toolset.length();
if (cmHasLiteralSuffix(toolset, "_xp")) {
length -= 3;
}
return toolset.substr(0, length);
}