1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmGlobalVisualStudio10Generator.h"
13 #include <cm3p/json/reader.h>
14 #include <cm3p/json/value.h>
16 #include "cmsys/FStream.hxx"
17 #include "cmsys/Glob.hxx"
18 #include "cmsys/RegularExpression.hxx"
20 #include "cmDocumentationEntry.h"
21 #include "cmGeneratorTarget.h"
22 #include "cmGlobalGenerator.h"
23 #include "cmGlobalGeneratorFactory.h"
24 #include "cmGlobalVisualStudio71Generator.h"
25 #include "cmGlobalVisualStudio7Generator.h"
26 #include "cmGlobalVisualStudioGenerator.h"
27 #include "cmIDEFlagTable.h"
28 #include "cmLocalGenerator.h"
29 #include "cmLocalVisualStudio10Generator.h"
30 #include "cmMakefile.h"
31 #include "cmMessageType.h"
32 #include "cmSourceFile.h"
33 #include "cmStringAlgorithms.h"
34 #include "cmSystemTools.h"
35 #include "cmVersion.h"
36 #include "cmVisualStudioSlnData.h"
37 #include "cmVisualStudioSlnParser.h"
38 #include "cmXMLWriter.h"
41 static const char vs10generatorName[] = "Visual Studio 10 2010";
42 static std::map<std::string, std::vector<cmIDEFlagTable>> loadedFlagJsonFiles;
44 static void ConvertToWindowsSlashes(std::string& s)
46 // first convert all of the slashes
54 // Map generator name without year to name with year.
55 static const char* cmVS10GenName(const std::string& name, std::string& genName)
57 if (strncmp(name.c_str(), vs10generatorName,
58 sizeof(vs10generatorName) - 6) != 0) {
61 const char* p = name.c_str() + sizeof(vs10generatorName) - 6;
62 if (cmHasLiteralPrefix(p, " 2010")) {
65 genName = std::string(vs10generatorName) + p;
69 class cmGlobalVisualStudio10Generator::Factory
70 : public cmGlobalGeneratorFactory
73 std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
74 const std::string& name, bool allowArch, cmake* cm) const override
77 const char* p = cmVS10GenName(name, genName);
79 return std::unique_ptr<cmGlobalGenerator>();
82 return std::unique_ptr<cmGlobalGenerator>(
83 new cmGlobalVisualStudio10Generator(cm, genName, ""));
85 if (!allowArch || *p++ != ' ') {
86 return std::unique_ptr<cmGlobalGenerator>();
88 if (strcmp(p, "Win64") == 0) {
89 return std::unique_ptr<cmGlobalGenerator>(
90 new cmGlobalVisualStudio10Generator(cm, genName, "x64"));
92 if (strcmp(p, "IA64") == 0) {
93 return std::unique_ptr<cmGlobalGenerator>(
94 new cmGlobalVisualStudio10Generator(cm, genName, "Itanium"));
96 return std::unique_ptr<cmGlobalGenerator>();
99 void GetDocumentation(cmDocumentationEntry& entry) const override
101 entry.Name = std::string(vs10generatorName) + " [arch]";
102 entry.Brief = "Deprecated. Generates Visual Studio 2010 project files. "
103 "Optional [arch] can be \"Win64\" or \"IA64\".";
106 std::vector<std::string> GetGeneratorNames() const override
108 std::vector<std::string> names;
109 names.push_back(vs10generatorName);
113 std::vector<std::string> GetGeneratorNamesWithPlatform() const override
115 std::vector<std::string> names;
116 names.push_back(vs10generatorName + std::string(" IA64"));
117 names.push_back(vs10generatorName + std::string(" Win64"));
121 bool SupportsToolset() const override { return true; }
122 bool SupportsPlatform() const override { return true; }
124 std::vector<std::string> GetKnownPlatforms() const override
126 std::vector<std::string> platforms;
127 platforms.emplace_back("x64");
128 platforms.emplace_back("Win32");
129 platforms.emplace_back("Itanium");
133 std::string GetDefaultPlatformName() const override { return "Win32"; }
136 std::unique_ptr<cmGlobalGeneratorFactory>
137 cmGlobalVisualStudio10Generator::NewFactory()
139 return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
142 cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
143 cmake* cm, const std::string& name,
144 std::string const& platformInGeneratorName)
145 : cmGlobalVisualStudio8Generator(cm, name, platformInGeneratorName)
147 std::string vc10Express;
148 this->ExpressEdition = cmSystemTools::ReadRegistryValue(
149 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
151 vc10Express, cmSystemTools::KeyWOW64_32);
152 this->CudaEnabled = false;
154 std::string envPlatformToolset;
155 if (cmSystemTools::GetEnv("PlatformToolset", envPlatformToolset) &&
156 envPlatformToolset == "Windows7.1SDK") {
157 // We are running from a Windows7.1SDK command prompt.
158 this->DefaultPlatformToolset = "Windows7.1SDK";
160 this->DefaultPlatformToolset = "v100";
163 this->DefaultCLFlagTableName = "v10";
164 this->DefaultCSharpFlagTableName = "v10";
165 this->DefaultLibFlagTableName = "v10";
166 this->DefaultLinkFlagTableName = "v10";
167 this->DefaultCudaFlagTableName = "v10";
168 this->DefaultCudaHostFlagTableName = "v10";
169 this->DefaultMasmFlagTableName = "v10";
170 this->DefaultNasmFlagTableName = "v10";
171 this->DefaultRCFlagTableName = "v10";
173 this->Version = VSVersion::VS10;
174 this->PlatformToolsetNeedsDebugEnum = false;
177 bool cmGlobalVisualStudio10Generator::MatchesGeneratorName(
178 const std::string& name) const
181 if (cmVS10GenName(name, genName)) {
182 return genName == this->GetName();
187 bool cmGlobalVisualStudio10Generator::SetSystemName(std::string const& s,
190 this->SystemName = s;
191 this->SystemVersion = mf->GetSafeDefinition("CMAKE_SYSTEM_VERSION");
192 if (!this->InitializeSystem(mf)) {
195 return this->cmGlobalVisualStudio8Generator::SetSystemName(s, mf);
198 bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
199 std::string const& p, cmMakefile* mf)
201 if (!this->cmGlobalVisualStudio8Generator::SetGeneratorPlatform(p, mf)) {
204 if (this->GetPlatformName() == "Itanium" ||
205 this->GetPlatformName() == "x64") {
206 if (this->IsExpressEdition() && !this->Find64BitTools(mf)) {
213 static void cmCudaToolVersion(std::string& s)
215 // "CUDA x.y.props" => "x.y"
217 s = s.substr(0, s.size() - 6);
220 bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
221 std::string const& ts, bool build, cmMakefile* mf)
223 if (this->SystemIsWindowsCE && ts.empty() &&
224 this->DefaultPlatformToolset.empty()) {
225 std::ostringstream e;
226 e << this->GetName() << " Windows CE version '" << this->SystemVersion
227 << "' requires CMAKE_GENERATOR_TOOLSET to be set.";
228 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
232 if (!this->ParseGeneratorToolset(ts, mf)) {
240 if (this->CustomVCTargetsPath.empty() && !this->FindVCTargetsPath(mf)) {
244 if (!this->CustomFlagTableDir.empty() &&
245 !(cmSystemTools::FileIsFullPath(this->CustomFlagTableDir) &&
246 cmSystemTools::FileIsDirectory(this->CustomFlagTableDir))) {
247 std::ostringstream e;
248 /* clang-format off */
251 " " << this->GetName() << "\n"
253 " customFlagTableDir=" << this->CustomFlagTableDir << "\n"
254 "that is not an absolute path to an existing directory.";
255 /* clang-format on */
256 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
257 cmSystemTools::SetFatalErrorOccurred();
261 if (cmHasLiteralPrefix(this->GetPlatformToolsetString(), "v140")) {
262 // The GenerateDebugInformation link setting for the v140 toolset
263 // in VS 2015 was originally an enum with "No" and "Debug" values,
264 // differing from the "false" and "true" values used in older toolsets.
265 // A VS 2015 update changed it back. Parse the "link.xml" file to
266 // discover which one we need.
267 std::string const link_xml = this->VCTargetsPath + "/1033/link.xml";
268 cmsys::ifstream fin(link_xml.c_str());
270 while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
271 if (line.find(" Switch=\"DEBUG\" ") != std::string::npos) {
272 this->PlatformToolsetNeedsDebugEnum =
273 line.find(" Name=\"Debug\" ") != std::string::npos;
279 this->SupportsUnityBuilds =
280 this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 ||
281 (this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS15 &&
282 cmSystemTools::PathExists(this->VCTargetsPath +
283 "/Microsoft.Cpp.Unity.targets"));
285 if (this->GeneratorToolsetCuda.empty()) {
286 // Find the highest available version of the CUDA tools.
287 std::vector<std::string> cudaTools;
289 if (this->GeneratorToolsetCudaCustomDir.empty()) {
290 bcDir = this->VCTargetsPath + "/BuildCustomizations";
292 bcDir = this->GetPlatformToolsetCudaCustomDirString() +
293 this->GetPlatformToolsetCudaVSIntegrationSubdirString() +
294 "extras\\visual_studio_integration\\MSBuildExtensions";
295 cmSystemTools::ConvertToUnixSlashes(bcDir);
298 gl.SetRelative(bcDir.c_str());
299 if (gl.FindFiles(bcDir + "/CUDA *.props")) {
300 cudaTools = gl.GetFiles();
302 if (!cudaTools.empty()) {
303 std::for_each(cudaTools.begin(), cudaTools.end(), cmCudaToolVersion);
304 std::sort(cudaTools.begin(), cudaTools.end(),
305 cmSystemTools::VersionCompareGreater);
306 this->GeneratorToolsetCuda = cudaTools.at(0);
307 } else if (!this->GeneratorToolsetCudaCustomDir.empty()) {
308 // Generate an error if Visual Studio integration files are not found
309 // inside of custom cuda toolset.
310 std::ostringstream e;
311 /* clang-format off */
314 " " << this->GetName() << "\n"
316 " cuda=" << this->GeneratorToolsetCudaCustomDir << "\n"
317 "cannot detect Visual Studio integration files in path\n"
320 /* clang-format on */
321 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
323 // Clear the configured tool-set
324 this->GeneratorToolsetCuda.clear();
328 if (!this->GeneratorToolsetVersion.empty() &&
329 this->GeneratorToolsetVersion != "Test Toolset Version") {
330 // If a specific minor version of the toolset was requested, verify that it
331 // is compatible to the major version and that is exists on disk.
332 // If not clear the value.
333 std::string versionToolset = this->GeneratorToolsetVersion;
334 cmsys::RegularExpression regex("[0-9][0-9]\\.[0-9][0-9]");
335 if (regex.find(versionToolset)) {
336 versionToolset = "v" + versionToolset.erase(2, 1);
338 // Version not recognized. Clear it.
339 versionToolset.clear();
342 if (!cmHasPrefix(versionToolset, this->GetPlatformToolsetString())) {
343 std::ostringstream e;
344 /* clang-format off */
347 " " << this->GetName() << "\n"
348 "given toolset and version specification\n"
349 " " << this->GetPlatformToolsetString() << ",version=" <<
350 this->GeneratorToolsetVersion << "\n"
351 "contains an invalid version specification."
353 /* clang-format on */
354 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
356 // Clear the configured tool-set
357 this->GeneratorToolsetVersion.clear();
360 std::string auxProps;
361 switch (this->FindAuxToolset(this->GeneratorToolsetVersion, auxProps)) {
362 case AuxToolset::None:
363 this->GeneratorToolsetVersionProps = {};
365 case AuxToolset::Default:
366 // The given version is the default toolset. Remove the setting.
367 this->GeneratorToolsetVersion.clear();
368 this->GeneratorToolsetVersionProps = {};
370 case AuxToolset::PropsExist:
371 this->GeneratorToolsetVersionProps = std::move(auxProps);
373 case AuxToolset::PropsMissing: {
374 std::ostringstream e;
375 /* clang-format off */
378 " " << this->GetName() << "\n"
379 "given toolset and version specification\n"
380 " " << this->GetPlatformToolsetString() << ",version=" <<
381 this->GeneratorToolsetVersion << "\n"
382 "does not seem to be installed at\n" <<
385 /* clang-format on */
386 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
388 // Clear the configured tool-set
389 this->GeneratorToolsetVersion.clear();
390 this->GeneratorToolsetVersionProps = {};
395 if (const char* toolset = this->GetPlatformToolset()) {
396 mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
398 if (!this->GeneratorToolsetVersion.empty()) {
399 mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VERSION",
400 this->GeneratorToolsetVersion);
402 if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
403 mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch);
405 if (const char* cuda = this->GetPlatformToolsetCuda()) {
406 mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA", cuda);
408 if (const char* cudaDir = this->GetPlatformToolsetCudaCustomDir()) {
409 mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR", cudaDir);
411 if (const char* vcTargetsDir = this->GetCustomVCTargetsPath()) {
412 mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR",
419 bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
420 std::string const& ts, cmMakefile* mf)
422 std::vector<std::string> const fields = cmTokenize(ts, ",");
423 std::vector<std::string>::const_iterator fi = fields.begin();
424 if (fi == fields.end()) {
428 // The first field may be the VS platform toolset.
429 if (fi->find('=') == fi->npos) {
430 this->GeneratorToolset = *fi;
434 std::set<std::string> handled;
436 // The rest of the fields must be key=value pairs.
437 for (; fi != fields.end(); ++fi) {
438 std::string::size_type pos = fi->find('=');
439 if (pos == fi->npos) {
440 std::ostringstream e;
441 /* clang-format off */
444 " " << this->GetName() << "\n"
445 "given toolset specification\n"
447 "that contains a field after the first ',' with no '='."
449 /* clang-format on */
450 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
453 std::string const key = fi->substr(0, pos);
454 std::string const value = fi->substr(pos + 1);
455 if (!handled.insert(key).second) {
456 std::ostringstream e;
457 /* clang-format off */
460 " " << this->GetName() << "\n"
461 "given toolset specification\n"
463 "that contains duplicate field key '" << key << "'."
465 /* clang-format on */
466 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
469 if (!this->ProcessGeneratorToolsetField(key, value)) {
470 std::ostringstream e;
471 /* clang-format off */
474 " " << this->GetName() << "\n"
475 "given toolset specification\n"
477 "that contains invalid field '" << *fi << "'."
479 /* clang-format on */
480 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
488 bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
489 std::string const& key, std::string const& value)
492 /* test if cuda toolset is path to custom dir or cuda version */
493 auto pos = value.find_first_not_of("0123456789.");
494 if (pos != std::string::npos) {
495 this->GeneratorToolsetCudaCustomDir = value;
496 /* ensure trailing backslash for easy path joining */
497 if (this->GeneratorToolsetCudaCustomDir.back() != '\\') {
498 this->GeneratorToolsetCudaCustomDir.push_back('\\');
500 /* check for legacy toolkit folder structure */
501 if (cmsys::SystemTools::FileIsDirectory(
502 cmStrCat(this->GeneratorToolsetCudaCustomDir, "nvcc"))) {
503 this->GeneratorToolsetCudaNvccSubdir = "nvcc\\";
505 if (cmsys::SystemTools::FileIsDirectory(
506 cmStrCat(this->GeneratorToolsetCudaCustomDir,
507 "CUDAVisualStudioIntegration"))) {
508 this->GeneratorToolsetCudaVSIntegrationSubdir =
509 "CUDAVisualStudioIntegration\\";
512 this->GeneratorToolsetCuda = value;
516 if (key == "customFlagTableDir") {
517 this->CustomFlagTableDir = value;
518 cmSystemTools::ConvertToUnixSlashes(this->CustomFlagTableDir);
521 if (key == "version") {
522 this->GeneratorToolsetVersion = value;
525 if (key == "VCTargetsPath") {
526 this->CustomVCTargetsPath = value;
527 ConvertToWindowsSlashes(this->CustomVCTargetsPath);
533 bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
535 if (this->SystemName == "Windows") {
536 if (!this->InitializeWindows(mf)) {
539 } else if (this->SystemName == "WindowsCE") {
540 this->SystemIsWindowsCE = true;
541 if (!this->InitializeWindowsCE(mf)) {
544 } else if (this->SystemName == "WindowsPhone") {
545 this->SystemIsWindowsPhone = true;
546 if (!this->InitializeWindowsPhone(mf)) {
549 } else if (this->SystemName == "WindowsStore") {
550 this->SystemIsWindowsStore = true;
551 if (!this->InitializeWindowsStore(mf)) {
554 } else if (this->SystemName == "Android") {
555 if (this->PlatformInGeneratorName) {
556 std::ostringstream e;
557 e << "CMAKE_SYSTEM_NAME is 'Android' but CMAKE_GENERATOR "
558 << "specifies a platform too: '" << this->GetName() << "'";
559 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
562 if (mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM") == "Tegra-Android") {
563 if (!this->InitializeTegraAndroid(mf)) {
567 this->SystemIsAndroid = true;
568 if (!this->InitializeAndroid(mf)) {
577 bool cmGlobalVisualStudio10Generator::InitializeWindows(cmMakefile*)
582 bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
584 if (this->PlatformInGeneratorName) {
585 std::ostringstream e;
586 e << "CMAKE_SYSTEM_NAME is 'WindowsCE' but CMAKE_GENERATOR "
587 << "specifies a platform too: '" << this->GetName() << "'";
588 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
592 this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
594 if (this->GetVersion() == cmGlobalVisualStudioGenerator::VSVersion::VS12) {
595 // VS 12 .NET CF defaults to .NET framework 3.9 for Windows CE.
596 this->DefaultTargetFrameworkVersion = "v3.9";
597 this->DefaultTargetFrameworkIdentifier = "WindowsEmbeddedCompact";
598 this->DefaultTargetFrameworkTargetsVersion = "v8.0";
604 bool cmGlobalVisualStudio10Generator::InitializeWindowsPhone(cmMakefile* mf)
606 std::ostringstream e;
607 e << this->GetName() << " does not support Windows Phone.";
608 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
612 bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
614 std::ostringstream e;
615 e << this->GetName() << " does not support Windows Store.";
616 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
620 bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf)
622 std::string v = this->GetInstalledNsightTegraVersion();
624 mf->IssueMessage(MessageType::FATAL_ERROR,
625 "CMAKE_SYSTEM_NAME is 'Android' but "
626 "'NVIDIA Nsight Tegra Visual Studio Edition' "
627 "is not installed.");
630 this->DefaultPlatformName = "Tegra-Android";
631 this->DefaultPlatformToolset = "Default";
632 this->NsightTegraVersion = v;
633 mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v);
637 bool cmGlobalVisualStudio10Generator::InitializeAndroid(cmMakefile* mf)
639 std::ostringstream e;
640 e << this->GetName() << " does not support Android.";
641 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
645 bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
646 std::string& toolset) const
652 bool cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
653 std::string& toolset) const
659 std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
661 if (this->SystemVersion == "8.0") {
667 //! Create a local generator appropriate to this Global Generator
668 std::unique_ptr<cmLocalGenerator>
669 cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmMakefile* mf)
671 return std::unique_ptr<cmLocalGenerator>(
672 cm::make_unique<cmLocalVisualStudio10Generator>(this, mf));
675 void cmGlobalVisualStudio10Generator::Generate()
677 this->LongestSource = LongestSourcePath();
678 this->cmGlobalVisualStudio8Generator::Generate();
679 if (!this->AndroidExecutableWarnings.empty() &&
680 !this->CMakeInstance->GetIsInTryCompile()) {
681 std::ostringstream e;
682 /* clang-format off */
684 "You are using Visual Studio tools for Android, which does not support "
685 "standalone executables. However, the following executable targets do "
686 "not have the ANDROID_GUI property set, and thus will not be built as "
687 "expected. They will be built as shared libraries with executable "
690 /* clang-format on */
692 for (auto const& name : this->AndroidExecutableWarnings) {
699 this->CMakeInstance->IssueMessage(MessageType::WARNING, e.str());
701 if (this->LongestSource.Length > 0) {
702 cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator();
703 std::ostringstream e;
704 /* clang-format off */
706 "The binary and/or source directory paths may be too long to generate "
707 "Visual Studio 10 files for this project. "
708 "Consider choosing shorter directory names to build this project with "
710 "A more detailed explanation follows."
712 "There is a bug in the VS 10 IDE that renders property dialog fields "
713 "blank for files referenced by full path in the project file. "
714 "However, CMake must reference at least one file by full path:\n"
715 " " << this->LongestSource.SourceFile->GetFullPath() << "\n"
716 "This is because some Visual Studio tools would append the relative "
717 "path to the end of the referencing directory path, as in:\n"
718 " " << lg->GetCurrentBinaryDirectory() << "/"
719 << this->LongestSource.SourceRel << "\n"
720 "and then incorrectly complain that the file does not exist because "
721 "the path length is too long for some internal buffer or API. "
722 "To avoid this problem CMake must use a full path for this file "
723 "which then triggers the VS 10 property dialog bug.";
724 /* clang-format on */
725 lg->IssueMessage(MessageType::WARNING, e.str());
727 if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
728 "CMAKE_VS_NUGET_PACKAGE_RESTORE")) {
729 this->CMakeInstance->MarkCliAsUsed("CMAKE_VS_NUGET_PACKAGE_RESTORE");
733 void cmGlobalVisualStudio10Generator::EnableLanguage(
734 std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
736 for (std::string const& it : lang) {
737 if (it == "ASM_NASM") {
738 this->NasmEnabled = true;
741 this->CudaEnabled = true;
744 this->AddPlatformDefinitions(mf);
745 cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
748 const char* cmGlobalVisualStudio10Generator::GetCustomVCTargetsPath() const
750 if (this->CustomVCTargetsPath.empty()) {
753 return this->CustomVCTargetsPath.c_str();
756 const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
758 std::string const& toolset = this->GetPlatformToolsetString();
759 if (toolset.empty()) {
762 return toolset.c_str();
765 std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString()
768 if (!this->GeneratorToolset.empty()) {
769 return this->GeneratorToolset;
771 if (this->SystemIsAndroid) {
772 if (!this->DefaultAndroidToolset.empty()) {
773 return this->DefaultAndroidToolset;
776 if (!this->DefaultPlatformToolset.empty()) {
777 return this->DefaultPlatformToolset;
780 static std::string const empty;
785 cmGlobalVisualStudio10Generator::GetPlatformToolsetVersionProps() const
787 return this->GeneratorToolsetVersionProps;
791 cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
793 std::string const& hostArch =
794 this->GetPlatformToolsetHostArchitectureString();
795 if (hostArch.empty()) {
798 return hostArch.c_str();
802 cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitectureString()
805 if (!this->GeneratorToolsetHostArchitecture.empty()) {
806 return this->GeneratorToolsetHostArchitecture;
808 if (!this->DefaultPlatformToolsetHostArchitecture.empty()) {
809 return this->DefaultPlatformToolsetHostArchitecture;
811 static std::string const empty;
815 const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCuda() const
817 if (!this->GeneratorToolsetCuda.empty()) {
818 return this->GeneratorToolsetCuda.c_str();
824 cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
826 return this->GeneratorToolsetCuda;
829 const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDir()
832 if (!this->GeneratorToolsetCudaCustomDir.empty()) {
833 return this->GeneratorToolsetCudaCustomDir.c_str();
839 cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDirString() const
841 return this->GeneratorToolsetCudaCustomDir;
845 cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaNvccSubdirString() const
847 return this->GeneratorToolsetCudaNvccSubdir;
850 std::string const& cmGlobalVisualStudio10Generator::
851 GetPlatformToolsetCudaVSIntegrationSubdirString() const
853 return this->GeneratorToolsetCudaVSIntegrationSubdir;
856 cmGlobalVisualStudio10Generator::AuxToolset
857 cmGlobalVisualStudio10Generator::FindAuxToolset(std::string&,
860 return AuxToolset::None;
863 bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
865 if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
868 mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND", this->GetMSBuildCommand());
872 std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
874 if (!this->MSBuildCommandInitialized) {
875 this->MSBuildCommandInitialized = true;
876 this->MSBuildCommand = this->FindMSBuildCommand();
878 return this->MSBuildCommand;
881 cm::optional<std::string>
882 cmGlobalVisualStudio10Generator::FindMSBuildCommandEarly(cmMakefile*)
884 return this->GetMSBuildCommand();
887 std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
892 // Search in standard location.
894 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\",
895 this->GetToolsVersion(), ";MSBuildToolsPath");
896 if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild,
897 cmSystemTools::KeyWOW64_32)) {
898 cmSystemTools::ConvertToUnixSlashes(msbuild);
899 msbuild += "/MSBuild.exe";
900 if (cmSystemTools::FileExists(msbuild, true)) {
905 msbuild = "MSBuild.exe";
909 std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
911 if (this->ExpressEdition) {
912 // Visual Studio Express >= 10 do not have "devenv.com" or
913 // "VCExpress.exe" that we can use to build reliably.
914 // Tell the caller it needs to use MSBuild instead.
917 // Skip over the cmGlobalVisualStudio8Generator implementation because
918 // we expect a real devenv and do not want to look for VCExpress.
919 return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
922 bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
924 // Skip this in special cases within our own test suite.
925 if (this->GetPlatformName() == "Test Platform" ||
926 this->GetPlatformToolsetString() == "Test Toolset") {
931 if (!this->ConfiguredFilesPath.empty()) {
932 // In a try-compile we are given the outer CMakeFiles directory.
933 wd = this->ConfiguredFilesPath;
935 wd = cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
939 wd += cmVersion::GetCMakeVersion();
941 // We record the result persistently in a file.
942 std::string const txt = wd + "/VCTargetsPath.txt";
944 // If we have a recorded result, use it.
946 cmsys::ifstream fin(txt.c_str());
947 if (fin && cmSystemTools::GetLineFromStream(fin, this->VCTargetsPath) &&
948 cmSystemTools::FileIsDirectory(this->VCTargetsPath)) {
949 cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
954 // Prepare the work directory.
955 if (!cmSystemTools::MakeDirectory(wd)) {
956 std::string e = "Failed to make directory:\n " + wd;
957 mf->IssueMessage(MessageType::FATAL_ERROR, e);
958 cmSystemTools::SetFatalErrorOccurred();
962 // Generate a project file for MSBuild to tell us the VCTargetsPath value.
963 std::string const vcxproj = "VCTargetsPath.vcxproj";
965 std::string const vcxprojAbs = wd + "/" + vcxproj;
966 cmsys::ofstream fout(vcxprojAbs.c_str());
967 cmXMLWriter xw(fout);
969 cmXMLDocument doc(xw);
970 cmXMLElement eprj(doc, "Project");
971 eprj.Attribute("DefaultTargets", "Build");
972 eprj.Attribute("ToolsVersion", "4.0");
973 eprj.Attribute("xmlns",
974 "http://schemas.microsoft.com/developer/msbuild/2003");
975 if (this->IsNsightTegra()) {
976 cmXMLElement epg(eprj, "PropertyGroup");
977 epg.Attribute("Label", "NsightTegraProject");
978 cmXMLElement(epg, "NsightTegraProjectRevisionNumber").Content("6");
981 cmXMLElement eig(eprj, "ItemGroup");
982 eig.Attribute("Label", "ProjectConfigurations");
983 cmXMLElement epc(eig, "ProjectConfiguration");
984 epc.Attribute("Include", "Debug|" + this->GetPlatformName());
985 cmXMLElement(epc, "Configuration").Content("Debug");
986 cmXMLElement(epc, "Platform").Content(this->GetPlatformName());
989 cmXMLElement epg(eprj, "PropertyGroup");
990 epg.Attribute("Label", "Globals");
991 cmXMLElement(epg, "ProjectGuid")
992 .Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}");
993 cmXMLElement(epg, "Keyword")
994 .Content(mf->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android"
997 cmXMLElement(epg, "Platform").Content(this->GetPlatformName());
998 if (this->GetSystemName() == "WindowsPhone") {
999 cmXMLElement(epg, "ApplicationType").Content("Windows Phone");
1000 cmXMLElement(epg, "ApplicationTypeRevision")
1001 .Content(this->GetApplicationTypeRevision());
1002 } else if (this->GetSystemName() == "WindowsStore") {
1003 cmXMLElement(epg, "ApplicationType").Content("Windows Store");
1004 cmXMLElement(epg, "ApplicationTypeRevision")
1005 .Content(this->GetApplicationTypeRevision());
1006 } else if (this->GetSystemName() == "Android") {
1007 cmXMLElement(epg, "ApplicationType").Content("Android");
1008 cmXMLElement(epg, "ApplicationTypeRevision")
1009 .Content(this->GetApplicationTypeRevision());
1011 if (!this->WindowsTargetPlatformVersion.empty()) {
1012 cmXMLElement(epg, "WindowsTargetPlatformVersion")
1013 .Content(this->WindowsTargetPlatformVersion);
1015 if (this->GetSystemName() != "Android") {
1016 if (this->GetPlatformName() == "ARM64") {
1017 cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true");
1018 } else if (this->GetPlatformName() == "ARM") {
1019 cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true");
1023 cmXMLElement(eprj, "Import")
1024 .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
1025 if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
1026 cmXMLElement epg(eprj, "PropertyGroup");
1027 cmXMLElement(epg, "PreferredToolArchitecture").Content(hostArch);
1030 cmXMLElement epg(eprj, "PropertyGroup");
1031 epg.Attribute("Label", "Configuration");
1033 cmXMLElement ect(epg, "ConfigurationType");
1034 if (this->IsNsightTegra()) {
1035 // Tegra-Android platform does not understand "Utility".
1036 ect.Content("StaticLibrary");
1038 ect.Content("Utility");
1041 cmXMLElement(epg, "CharacterSet").Content("MultiByte");
1042 if (this->IsNsightTegra()) {
1043 cmXMLElement(epg, "NdkToolchainVersion")
1044 .Content(this->GetPlatformToolsetString());
1046 cmXMLElement(epg, "PlatformToolset")
1047 .Content(this->GetPlatformToolsetString());
1050 cmXMLElement(eprj, "Import")
1051 .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
1053 cmXMLElement eidg(eprj, "ItemDefinitionGroup");
1054 cmXMLElement epbe(eidg, "PostBuildEvent");
1055 cmXMLElement(epbe, "Command")
1056 .Content("echo VCTargetsPath=$(VCTargetsPath)");
1058 cmXMLElement(eprj, "Import")
1059 .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
1062 std::vector<std::string> cmd;
1063 cmd.push_back(this->GetMSBuildCommand());
1064 cmd.push_back(vcxproj);
1065 cmd.push_back("/p:Configuration=Debug");
1066 cmd.push_back(cmStrCat("/p:Platform=", this->GetPlatformName()));
1067 cmd.push_back(std::string("/p:VisualStudioVersion=") +
1068 this->GetIDEVersion());
1071 cmsys::RegularExpression regex("\n *VCTargetsPath=([^%\r\n]+)[\r\n]");
1072 if (!cmSystemTools::RunSingleCommand(cmd, &out, &out, &ret, wd.c_str(),
1073 cmSystemTools::OUTPUT_NONE) ||
1074 ret != 0 || !regex.find(out)) {
1075 cmSystemTools::ReplaceString(out, "\n", "\n ");
1076 std::ostringstream e;
1077 /* clang-format off */
1079 "Failed to run MSBuild command:\n"
1080 " " << cmd[0] << "\n"
1081 "to get the value of VCTargetsPath:\n"
1084 /* clang-format on */
1086 e << "Exit code: " << ret << "\n";
1088 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
1089 cmSystemTools::SetFatalErrorOccurred();
1092 this->VCTargetsPath = regex.match(1);
1093 cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
1096 cmsys::ofstream fout(txt.c_str());
1097 fout << this->VCTargetsPath << "\n";
1102 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
1103 cmGlobalVisualStudio10Generator::GenerateBuildCommand(
1104 const std::string& makeProgram, const std::string& projectName,
1105 const std::string& projectDir, std::vector<std::string> const& targetNames,
1106 const std::string& config, int jobs, bool verbose,
1107 const cmBuildOptions& buildOptions,
1108 std::vector<std::string> const& makeOptions)
1110 std::vector<GeneratedMakeCommand> makeCommands;
1111 // Select the caller- or user-preferred make program, else MSBuild.
1112 std::string makeProgramSelected =
1113 this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
1115 // Check if the caller explicitly requested a devenv tool.
1116 std::string makeProgramLower = makeProgramSelected;
1117 cmSystemTools::LowerCase(makeProgramLower);
1118 bool useDevEnv = (makeProgramLower.find("devenv") != std::string::npos ||
1119 makeProgramLower.find("vcexpress") != std::string::npos);
1121 // Workaround to convince VCExpress.exe to produce output.
1122 const bool requiresOutputForward =
1123 (makeProgramLower.find("vcexpress") != std::string::npos);
1125 // MSBuild is preferred (and required for VS Express), but if the .sln has
1126 // an Intel Fortran .vfproj then we have to use devenv. Parse it to find out.
1129 std::string slnFile;
1130 if (!projectDir.empty()) {
1131 slnFile = cmStrCat(projectDir, '/');
1133 slnFile += projectName;
1135 cmVisualStudioSlnParser parser;
1136 if (parser.ParseFile(slnFile, slnData,
1137 cmVisualStudioSlnParser::DataGroupAll)) {
1138 std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
1139 for (cmSlnProjectEntry const& project : slnProjects) {
1143 std::string proj = project.GetRelativePath();
1144 if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
1151 // Use devenv to build solutions containing Intel Fortran projects.
1152 return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
1153 makeProgram, projectName, projectDir, targetNames, config, jobs, verbose,
1154 buildOptions, makeOptions);
1157 std::vector<std::string> realTargetNames = targetNames;
1158 if (targetNames.empty() ||
1159 ((targetNames.size() == 1) && targetNames.front().empty())) {
1160 realTargetNames = { "ALL_BUILD" };
1162 for (const auto& tname : realTargetNames) {
1163 // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
1164 // /target:ALL_BUILD
1166 if (tname.empty()) {
1170 GeneratedMakeCommand makeCommand;
1171 makeCommand.RequiresOutputForward = requiresOutputForward;
1172 makeCommand.Add(makeProgramSelected);
1173 cm::optional<cmSlnProjectEntry> proj = cm::nullopt;
1175 if (tname == "clean") {
1176 makeCommand.Add(cmStrCat(projectName, ".sln"));
1177 makeCommand.Add("/t:Clean");
1179 std::string targetProject = cmStrCat(tname, ".vcxproj");
1180 proj = slnData.GetProjectByName(tname);
1181 if (targetProject.find('/') == std::string::npos) {
1182 // it might be in a subdir
1184 targetProject = proj->GetRelativePath();
1185 cmSystemTools::ConvertToUnixSlashes(targetProject);
1188 makeCommand.Add(targetProject);
1190 // Check if we do need a restore at all (i.e. if there are package
1191 // references and restore has not been disabled by a command line option.
1192 PackageResolveMode restoreMode = buildOptions.ResolveMode;
1193 bool requiresRestore = true;
1195 if (restoreMode == PackageResolveMode::Disable) {
1196 requiresRestore = false;
1197 } else if (cmValue cached =
1198 this->CMakeInstance->GetState()->GetCacheEntryValue(
1199 tname + "_REQUIRES_VS_PACKAGE_RESTORE")) {
1200 requiresRestore = cached.IsOn();
1202 // There are no package references defined.
1203 requiresRestore = false;
1206 // If a restore is required, evaluate the restore mode.
1207 if (requiresRestore) {
1208 if (restoreMode == PackageResolveMode::OnlyResolve) {
1209 // Only invoke the restore target on the project.
1210 makeCommand.Add("/t:Restore");
1212 // Invoke restore target, unless it has been explicitly disabled.
1213 bool restorePackages = true;
1215 if (this->Version < VSVersion::VS15) {
1216 // Package restore is only supported starting from Visual Studio
1217 // 2017. Package restore must be executed manually using NuGet
1218 // shell for older versions.
1219 this->CMakeInstance->IssueMessage(
1220 MessageType::WARNING,
1221 "Restoring package references is only supported for Visual "
1222 "Studio 2017 and later. You have to manually restore the "
1223 "packages using NuGet before building the project.");
1224 restorePackages = false;
1225 } else if (restoreMode == PackageResolveMode::Default) {
1226 // Decide if a restore is performed, based on a cache variable.
1227 if (cmValue cached =
1228 this->CMakeInstance->GetState()->GetCacheEntryValue(
1229 "CMAKE_VS_NUGET_PACKAGE_RESTORE"))
1230 restorePackages = cached.IsOn();
1233 if (restorePackages) {
1234 if (this->IsMsBuildRestoreSupported()) {
1235 makeCommand.Add("/restore");
1237 GeneratedMakeCommand restoreCommand;
1238 restoreCommand.Add(makeProgramSelected);
1239 restoreCommand.Add(targetProject);
1240 restoreCommand.Add("/t:Restore");
1241 makeCommands.emplace_back(restoreCommand);
1248 std::string plainConfig = config;
1249 if (config.empty()) {
1250 plainConfig = "Debug";
1253 std::string platform = GetPlatformName();
1255 std::string extension =
1256 cmSystemTools::GetFilenameLastExtension(proj->GetRelativePath());
1257 extension = cmSystemTools::LowerCase(extension);
1258 if (extension.compare(".csproj") == 0) {
1259 // Use correct platform name
1261 slnData.GetConfigurationTarget(tname, plainConfig, platform);
1265 makeCommand.Add(cmStrCat("/p:Configuration=", plainConfig));
1266 makeCommand.Add(cmStrCat("/p:Platform=", platform));
1268 cmStrCat("/p:VisualStudioVersion=", this->GetIDEVersion()));
1270 if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
1271 if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
1272 makeCommand.Add("/m");
1274 makeCommand.Add(cmStrCat("/m:", std::to_string(jobs)));
1276 // Having msbuild.exe and cl.exe using multiple jobs is discouraged
1277 makeCommand.Add("/p:CL_MPCount=1");
1280 // Respect the verbosity: 'n' normal will show build commands
1281 // 'm' minimal only the build step's title
1282 makeCommand.Add(cmStrCat("/v:", ((verbose) ? "n" : "m")));
1283 makeCommand.Add(makeOptions.begin(), makeOptions.end());
1284 makeCommands.emplace_back(std::move(makeCommand));
1286 return makeCommands;
1289 bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
1291 if (this->DefaultPlatformToolset == "v100") {
1292 // The v100 64-bit toolset does not exist in the express edition.
1293 this->DefaultPlatformToolset.clear();
1295 if (this->GetPlatformToolset()) {
1298 // This edition does not come with 64-bit tools. Look for them.
1300 // TODO: Detect available tools? x64\v100 exists but does not work?
1301 // HKLM\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\4.0;VCTargetsPath
1302 // c:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/Platforms/
1303 // {Itanium,Win32,x64}/PlatformToolsets/{v100,v90,Windows7.1SDK}
1304 std::string winSDK_7_1;
1305 if (cmSystemTools::ReadRegistryValue(
1306 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\"
1307 "Windows\\v7.1;InstallationFolder",
1309 std::ostringstream m;
1310 m << "Found Windows SDK v7.1: " << winSDK_7_1;
1311 mf->DisplayStatus(m.str(), -1);
1312 this->DefaultPlatformToolset = "Windows7.1SDK";
1315 std::ostringstream e;
1316 /* clang-format off */
1317 e << "Cannot enable 64-bit tools with Visual Studio 2010 Express.\n"
1318 << "Install the Microsoft Windows SDK v7.1 to get 64-bit tools:\n"
1319 << " http://msdn.microsoft.com/en-us/windows/bb980924.aspx";
1320 /* clang-format on */
1321 mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str());
1322 cmSystemTools::SetFatalErrorOccurred();
1327 std::string cmGlobalVisualStudio10Generator::GenerateRuleFile(
1328 std::string const& output) const
1330 // The VS 10 generator needs to create the .rule files on disk.
1331 // Hide them away under the CMakeFiles directory.
1332 std::string ruleDir = cmStrCat(
1333 this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeFiles/",
1334 cmSystemTools::ComputeStringMD5(cmSystemTools::GetFilenamePath(output)));
1335 std::string ruleFile =
1336 cmStrCat(ruleDir, '/', cmSystemTools::GetFilenameName(output), ".rule");
1340 void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target,
1341 cmSourceFile const* sf,
1342 std::string const& sfRel)
1345 (target->GetLocalGenerator()->GetCurrentBinaryDirectory().length() + 1 +
1347 if (len > this->LongestSource.Length) {
1348 this->LongestSource.Length = len;
1349 this->LongestSource.Target = target;
1350 this->LongestSource.SourceFile = sf;
1351 this->LongestSource.SourceRel = sfRel;
1355 std::string cmGlobalVisualStudio10Generator::Encoding()
1360 const char* cmGlobalVisualStudio10Generator::GetToolsVersion() const
1362 switch (this->Version) {
1363 case cmGlobalVisualStudioGenerator::VSVersion::VS9:
1364 case cmGlobalVisualStudioGenerator::VSVersion::VS10:
1365 case cmGlobalVisualStudioGenerator::VSVersion::VS11:
1368 // in Visual Studio 2013 they detached the MSBuild tools version
1369 // from the .Net Framework version and instead made it have it's own
1371 case cmGlobalVisualStudioGenerator::VSVersion::VS12:
1373 case cmGlobalVisualStudioGenerator::VSVersion::VS14:
1375 case cmGlobalVisualStudioGenerator::VSVersion::VS15:
1377 case cmGlobalVisualStudioGenerator::VSVersion::VS16:
1379 case cmGlobalVisualStudioGenerator::VSVersion::VS17:
1385 bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
1387 return !this->NsightTegraVersion.empty();
1390 std::string cmGlobalVisualStudio10Generator::GetNsightTegraVersion() const
1392 return this->NsightTegraVersion;
1395 std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
1397 std::string version;
1398 cmSystemTools::ReadRegistryValue(
1399 "HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;"
1401 version, cmSystemTools::KeyWOW64_32);
1405 std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const
1407 if (this->GetSystemName() == "Android") {
1408 return this->GetAndroidApplicationTypeRevision();
1411 // Return the first two '.'-separated components of the Windows version.
1412 std::string::size_type end1 = this->SystemVersion.find('.');
1413 std::string::size_type end2 =
1414 end1 == std::string::npos ? end1 : this->SystemVersion.find('.', end1 + 1);
1415 return this->SystemVersion.substr(0, end2);
1418 static std::string cmLoadFlagTableString(Json::Value entry, const char* field)
1420 if (entry.isMember(field)) {
1421 auto string = entry[field];
1422 if (string.isConvertibleTo(Json::ValueType::stringValue)) {
1423 return string.asString();
1429 static unsigned int cmLoadFlagTableSpecial(Json::Value entry,
1432 unsigned int value = 0;
1433 if (entry.isMember(field)) {
1434 auto specials = entry[field];
1435 if (specials.isArray()) {
1436 for (auto const& special : specials) {
1437 std::string s = special.asString();
1438 if (s == "UserValue") {
1439 value |= cmIDEFlagTable::UserValue;
1440 } else if (s == "UserIgnored") {
1441 value |= cmIDEFlagTable::UserIgnored;
1442 } else if (s == "UserRequired") {
1443 value |= cmIDEFlagTable::UserRequired;
1444 } else if (s == "Continue") {
1445 value |= cmIDEFlagTable::Continue;
1446 } else if (s == "SemicolonAppendable") {
1447 value |= cmIDEFlagTable::SemicolonAppendable;
1448 } else if (s == "UserFollowing") {
1449 value |= cmIDEFlagTable::UserFollowing;
1450 } else if (s == "CaseInsensitive") {
1451 value |= cmIDEFlagTable::CaseInsensitive;
1452 } else if (s == "SpaceAppendable") {
1453 value |= cmIDEFlagTable::SpaceAppendable;
1454 } else if (s == "CommaAppendable") {
1455 value |= cmIDEFlagTable::CommaAppendable;
1465 cmIDEFlagTable const* cmLoadFlagTableJson(std::string const& flagJsonPath,
1466 cm::optional<std::string> vsVer)
1468 cmIDEFlagTable* ret = nullptr;
1469 auto savedFlagIterator = loadedFlagJsonFiles.find(flagJsonPath);
1470 if (savedFlagIterator != loadedFlagJsonFiles.end()) {
1471 ret = savedFlagIterator->second.data();
1473 Json::Reader reader;
1474 cmsys::ifstream stream;
1476 stream.open(flagJsonPath.c_str(), std::ios_base::in);
1479 if (reader.parse(stream, flags, false) && flags.isArray()) {
1480 std::vector<cmIDEFlagTable> flagTable;
1481 for (auto const& flag : flags) {
1482 Json::Value const& vsminJson = flag["vsmin"];
1483 if (vsminJson.isString()) {
1484 std::string const& vsmin = vsminJson.asString();
1485 if (!vsmin.empty()) {
1487 cmSystemTools::VersionCompareGreater(vsmin, *vsVer)) {
1492 cmIDEFlagTable flagEntry;
1493 flagEntry.IDEName = cmLoadFlagTableString(flag, "name");
1494 flagEntry.commandFlag = cmLoadFlagTableString(flag, "switch");
1495 flagEntry.comment = cmLoadFlagTableString(flag, "comment");
1496 flagEntry.value = cmLoadFlagTableString(flag, "value");
1497 flagEntry.special = cmLoadFlagTableSpecial(flag, "flags");
1498 flagTable.push_back(flagEntry);
1500 cmIDEFlagTable endFlag{ "", "", "", "", 0 };
1501 flagTable.push_back(endFlag);
1503 loadedFlagJsonFiles[flagJsonPath] = flagTable;
1504 ret = loadedFlagJsonFiles[flagJsonPath].data();
1512 cm::optional<std::string> cmGlobalVisualStudio10Generator::FindFlagTable(
1513 cm::string_view toolsetName, cm::string_view table) const
1515 if (!this->CustomFlagTableDir.empty()) {
1516 std::string customFlagTableFile =
1517 cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
1518 toolsetName, '_', table, ".json");
1519 if (cmSystemTools::FileExists(customFlagTableFile)) {
1520 return customFlagTableFile;
1522 customFlagTableFile =
1523 cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
1525 if (cmSystemTools::FileExists(customFlagTableFile)) {
1526 return customFlagTableFile;
1529 std::string fullPath =
1530 cmStrCat(cmSystemTools::GetCMakeRoot(), "/Templates/MSBuild/FlagTables/",
1531 toolsetName, '_', table, ".json");
1532 if (cmSystemTools::FileExists(fullPath)) {
1538 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::LoadFlagTable(
1539 std::string const& toolSpecificName, std::string const& defaultName,
1540 std::string const& table) const
1542 cmMakefile* mf = this->GetCurrentMakefile();
1544 std::string filename;
1545 if (!toolSpecificName.empty()) {
1546 if (cm::optional<std::string> found =
1547 this->FindFlagTable(toolSpecificName, table)) {
1548 filename = std::move(*found);
1550 mf->IssueMessage(MessageType::FATAL_ERROR,
1551 cmStrCat("JSON flag table for ", table,
1552 " not found for toolset ", toolSpecificName));
1556 std::string const& genericName =
1557 this->CanonicalToolsetName(this->GetPlatformToolsetString());
1558 cm::optional<std::string> found = this->FindFlagTable(genericName, table);
1560 found = this->FindFlagTable(defaultName, table);
1563 filename = std::move(*found);
1565 mf->IssueMessage(MessageType::FATAL_ERROR,
1566 cmStrCat("JSON flag table for ", table,
1567 " not found for toolset ", genericName, " ",
1573 cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
1574 if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename, vsVer)) {
1579 MessageType::FATAL_ERROR,
1580 cmStrCat("JSON flag table could not be loaded:\n ", filename));
1584 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetClFlagTable() const
1586 return LoadFlagTable(this->GetClFlagTableName(),
1587 this->DefaultCLFlagTableName, "CL");
1590 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCSharpFlagTable()
1593 return LoadFlagTable(this->GetCSharpFlagTableName(),
1594 this->DefaultCSharpFlagTableName, "CSharp");
1597 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetRcFlagTable() const
1599 return LoadFlagTable(this->GetRcFlagTableName(),
1600 this->DefaultRCFlagTableName, "RC");
1603 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLibFlagTable() const
1605 return LoadFlagTable(this->GetLibFlagTableName(),
1606 this->DefaultLibFlagTableName, "LIB");
1609 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
1611 return LoadFlagTable(this->GetLinkFlagTableName(),
1612 this->DefaultLinkFlagTableName, "Link");
1615 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaFlagTable() const
1617 return LoadFlagTable(std::string(), this->DefaultCudaFlagTableName, "Cuda");
1620 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
1623 return LoadFlagTable(std::string(), this->DefaultCudaHostFlagTableName,
1627 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
1629 return LoadFlagTable(this->GetMasmFlagTableName(),
1630 this->DefaultMasmFlagTableName, "MASM");
1633 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
1635 return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
1638 bool cmGlobalVisualStudio10Generator::IsMsBuildRestoreSupported() const
1640 if (this->Version >= VSVersion::VS16) {
1644 static std::string const vsVer15_7_5 = "15.7.27703.2042";
1645 cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
1647 cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_7_5));
1650 std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
1652 std::string const& toolset = this->GetPlatformToolsetString();
1653 std::string const useToolset = this->CanonicalToolsetName(toolset);
1655 if (toolset == "v142") {
1657 } else if (toolset == "v141") {
1659 } else if (useToolset == "v140") {
1661 } else if (useToolset == "v120") {
1663 } else if (useToolset == "v110") {
1665 } else if (useToolset == "v100") {
1672 std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
1674 std::string const& toolset = this->GetPlatformToolsetString();
1675 std::string const useToolset = this->CanonicalToolsetName(toolset);
1677 if (useToolset == "v142") {
1679 } else if (useToolset == "v141") {
1681 } else if (useToolset == "v140") {
1683 } else if (useToolset == "v120") {
1685 } else if (useToolset == "v110") {
1687 } else if (useToolset == "v100") {
1694 std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
1696 std::string const& toolset = this->GetPlatformToolsetString();
1697 std::string const useToolset = this->CanonicalToolsetName(toolset);
1699 if ((useToolset == "v140") || (useToolset == "v141") ||
1700 (useToolset == "v142")) {
1702 } else if (useToolset == "v120") {
1704 } else if (useToolset == "v110") {
1706 } else if (useToolset == "v100") {
1713 std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
1715 std::string const& toolset = this->GetPlatformToolsetString();
1716 std::string const useToolset = this->CanonicalToolsetName(toolset);
1718 if ((useToolset == "v140") || (useToolset == "v141") ||
1719 (useToolset == "v142")) {
1721 } else if (useToolset == "v120") {
1723 } else if (useToolset == "v110") {
1725 } else if (useToolset == "v100") {
1732 std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
1734 std::string const& toolset = this->GetPlatformToolsetString();
1735 std::string const useToolset = this->CanonicalToolsetName(toolset);
1737 if (useToolset == "v142") {
1739 } else if (useToolset == "v141") {
1741 } else if (useToolset == "v140") {
1743 } else if (useToolset == "v120") {
1745 } else if (useToolset == "v110") {
1747 } else if (useToolset == "v100") {
1754 std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
1756 std::string const& toolset = this->GetPlatformToolsetString();
1757 std::string const useToolset = this->CanonicalToolsetName(toolset);
1759 if ((useToolset == "v140") || (useToolset == "v141") ||
1760 (useToolset == "v142")) {
1762 } else if (useToolset == "v120") {
1764 } else if (useToolset == "v110") {
1766 } else if (useToolset == "v100") {
1773 std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName(
1774 std::string const& toolset) const
1776 std::size_t length = toolset.length();
1778 if (cmHasLiteralSuffix(toolset, "_xp")) {
1782 return toolset.substr(0, length);