29eeb5a9170f81dc5661882420bd5253aba0e534
[platform/upstream/cmake.git] / Source / cmGlobalVisualStudio10Generator.cxx
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"
4
5 #include <algorithm>
6 #include <cstring>
7 #include <map>
8 #include <sstream>
9 #include <utility>
10
11 #include <cm/memory>
12
13 #include <cm3p/json/reader.h>
14 #include <cm3p/json/value.h>
15
16 #include "cmsys/FStream.hxx"
17 #include "cmsys/Glob.hxx"
18 #include "cmsys/RegularExpression.hxx"
19
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"
39 #include "cmake.h"
40
41 static const char vs10generatorName[] = "Visual Studio 10 2010";
42 static std::map<std::string, std::vector<cmIDEFlagTable>> loadedFlagJsonFiles;
43
44 static void ConvertToWindowsSlashes(std::string& s)
45 {
46   // first convert all of the slashes
47   for (auto& ch : s) {
48     if (ch == '/') {
49       ch = '\\';
50     }
51   }
52 }
53
54 // Map generator name without year to name with year.
55 static const char* cmVS10GenName(const std::string& name, std::string& genName)
56 {
57   if (strncmp(name.c_str(), vs10generatorName,
58               sizeof(vs10generatorName) - 6) != 0) {
59     return 0;
60   }
61   const char* p = name.c_str() + sizeof(vs10generatorName) - 6;
62   if (cmHasLiteralPrefix(p, " 2010")) {
63     p += 5;
64   }
65   genName = std::string(vs10generatorName) + p;
66   return p;
67 }
68
69 class cmGlobalVisualStudio10Generator::Factory
70   : public cmGlobalGeneratorFactory
71 {
72 public:
73   std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
74     const std::string& name, bool allowArch, cmake* cm) const override
75   {
76     std::string genName;
77     const char* p = cmVS10GenName(name, genName);
78     if (!p) {
79       return std::unique_ptr<cmGlobalGenerator>();
80     }
81     if (!*p) {
82       return std::unique_ptr<cmGlobalGenerator>(
83         new cmGlobalVisualStudio10Generator(cm, genName, ""));
84     }
85     if (!allowArch || *p++ != ' ') {
86       return std::unique_ptr<cmGlobalGenerator>();
87     }
88     if (strcmp(p, "Win64") == 0) {
89       return std::unique_ptr<cmGlobalGenerator>(
90         new cmGlobalVisualStudio10Generator(cm, genName, "x64"));
91     }
92     if (strcmp(p, "IA64") == 0) {
93       return std::unique_ptr<cmGlobalGenerator>(
94         new cmGlobalVisualStudio10Generator(cm, genName, "Itanium"));
95     }
96     return std::unique_ptr<cmGlobalGenerator>();
97   }
98
99   void GetDocumentation(cmDocumentationEntry& entry) const override
100   {
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\".";
104   }
105
106   std::vector<std::string> GetGeneratorNames() const override
107   {
108     std::vector<std::string> names;
109     names.push_back(vs10generatorName);
110     return names;
111   }
112
113   std::vector<std::string> GetGeneratorNamesWithPlatform() const override
114   {
115     std::vector<std::string> names;
116     names.push_back(vs10generatorName + std::string(" IA64"));
117     names.push_back(vs10generatorName + std::string(" Win64"));
118     return names;
119   }
120
121   bool SupportsToolset() const override { return true; }
122   bool SupportsPlatform() const override { return true; }
123
124   std::vector<std::string> GetKnownPlatforms() const override
125   {
126     std::vector<std::string> platforms;
127     platforms.emplace_back("x64");
128     platforms.emplace_back("Win32");
129     platforms.emplace_back("Itanium");
130     return platforms;
131   }
132
133   std::string GetDefaultPlatformName() const override { return "Win32"; }
134 };
135
136 std::unique_ptr<cmGlobalGeneratorFactory>
137 cmGlobalVisualStudio10Generator::NewFactory()
138 {
139   return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
140 }
141
142 cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
143   cmake* cm, const std::string& name,
144   std::string const& platformInGeneratorName)
145   : cmGlobalVisualStudio8Generator(cm, name, platformInGeneratorName)
146 {
147   std::string vc10Express;
148   this->ExpressEdition = cmSystemTools::ReadRegistryValue(
149     "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0\\Setup\\VC;"
150     "ProductDir",
151     vc10Express, cmSystemTools::KeyWOW64_32);
152   this->CudaEnabled = false;
153   {
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";
159     } else {
160       this->DefaultPlatformToolset = "v100";
161     }
162   }
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";
172
173   this->Version = VSVersion::VS10;
174   this->PlatformToolsetNeedsDebugEnum = false;
175 }
176
177 bool cmGlobalVisualStudio10Generator::MatchesGeneratorName(
178   const std::string& name) const
179 {
180   std::string genName;
181   if (cmVS10GenName(name, genName)) {
182     return genName == this->GetName();
183   }
184   return false;
185 }
186
187 bool cmGlobalVisualStudio10Generator::SetSystemName(std::string const& s,
188                                                     cmMakefile* mf)
189 {
190   this->SystemName = s;
191   this->SystemVersion = mf->GetSafeDefinition("CMAKE_SYSTEM_VERSION");
192   if (!this->InitializeSystem(mf)) {
193     return false;
194   }
195   return this->cmGlobalVisualStudio8Generator::SetSystemName(s, mf);
196 }
197
198 bool cmGlobalVisualStudio10Generator::SetGeneratorPlatform(
199   std::string const& p, cmMakefile* mf)
200 {
201   if (!this->cmGlobalVisualStudio8Generator::SetGeneratorPlatform(p, mf)) {
202     return false;
203   }
204   if (this->GetPlatformName() == "Itanium" ||
205       this->GetPlatformName() == "x64") {
206     if (this->IsExpressEdition() && !this->Find64BitTools(mf)) {
207       return false;
208     }
209   }
210   return true;
211 }
212
213 static void cmCudaToolVersion(std::string& s)
214 {
215   // "CUDA x.y.props" => "x.y"
216   s = s.substr(5);
217   s = s.substr(0, s.size() - 6);
218 }
219
220 bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
221   std::string const& ts, bool build, cmMakefile* mf)
222 {
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());
229     return false;
230   }
231
232   if (!this->ParseGeneratorToolset(ts, mf)) {
233     return false;
234   }
235
236   if (build) {
237     return true;
238   }
239
240   if (this->CustomVCTargetsPath.empty() && !this->FindVCTargetsPath(mf)) {
241     return false;
242   }
243
244   if (!this->CustomFlagTableDir.empty() &&
245       !(cmSystemTools::FileIsFullPath(this->CustomFlagTableDir) &&
246         cmSystemTools::FileIsDirectory(this->CustomFlagTableDir))) {
247     std::ostringstream e;
248     /* clang-format off */
249     e <<
250       "Generator\n"
251       "  " << this->GetName() << "\n"
252       "given toolset\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();
258     return false;
259   }
260
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());
269     std::string line;
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;
274         break;
275       }
276     }
277   }
278
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"));
284
285   if (this->GeneratorToolsetCuda.empty()) {
286     // Find the highest available version of the CUDA tools.
287     std::vector<std::string> cudaTools;
288     std::string bcDir;
289     if (this->GeneratorToolsetCudaCustomDir.empty()) {
290       bcDir = this->VCTargetsPath + "/BuildCustomizations";
291     } else {
292       bcDir = this->GetPlatformToolsetCudaCustomDirString() +
293         this->GetPlatformToolsetCudaVSIntegrationSubdirString() +
294         "extras\\visual_studio_integration\\MSBuildExtensions";
295       cmSystemTools::ConvertToUnixSlashes(bcDir);
296     }
297     cmsys::Glob gl;
298     gl.SetRelative(bcDir.c_str());
299     if (gl.FindFiles(bcDir + "/CUDA *.props")) {
300       cudaTools = gl.GetFiles();
301     }
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 */
312       e <<
313         "Generator\n"
314         "  " << this->GetName() << "\n"
315         "given toolset\n"
316         "  cuda=" << this->GeneratorToolsetCudaCustomDir << "\n"
317         "cannot detect Visual Studio integration files in path\n"
318         "  " << bcDir;
319
320       /* clang-format on */
321       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
322
323       // Clear the configured tool-set
324       this->GeneratorToolsetCuda.clear();
325     }
326   }
327
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);
337     } else {
338       // Version not recognized. Clear it.
339       versionToolset.clear();
340     }
341
342     if (!cmHasPrefix(versionToolset, this->GetPlatformToolsetString())) {
343       std::ostringstream e;
344       /* clang-format off */
345       e <<
346         "Generator\n"
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."
352       ;
353       /* clang-format on */
354       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
355
356       // Clear the configured tool-set
357       this->GeneratorToolsetVersion.clear();
358     }
359
360     std::string auxProps;
361     switch (this->FindAuxToolset(this->GeneratorToolsetVersion, auxProps)) {
362       case AuxToolset::None:
363         this->GeneratorToolsetVersionProps = {};
364         break;
365       case AuxToolset::Default:
366         // The given version is the default toolset.  Remove the setting.
367         this->GeneratorToolsetVersion.clear();
368         this->GeneratorToolsetVersionProps = {};
369         break;
370       case AuxToolset::PropsExist:
371         this->GeneratorToolsetVersionProps = std::move(auxProps);
372         break;
373       case AuxToolset::PropsMissing: {
374         std::ostringstream e;
375         /* clang-format off */
376         e <<
377           "Generator\n"
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" <<
383           "  " << auxProps;
384         ;
385         /* clang-format on */
386         mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
387
388         // Clear the configured tool-set
389         this->GeneratorToolsetVersion.clear();
390         this->GeneratorToolsetVersionProps = {};
391       } break;
392     }
393   }
394
395   if (const char* toolset = this->GetPlatformToolset()) {
396     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET", toolset);
397   }
398   if (!this->GeneratorToolsetVersion.empty()) {
399     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VERSION",
400                       this->GeneratorToolsetVersion);
401   }
402   if (const char* hostArch = this->GetPlatformToolsetHostArchitecture()) {
403     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE", hostArch);
404   }
405   if (const char* cuda = this->GetPlatformToolsetCuda()) {
406     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA", cuda);
407   }
408   if (const char* cudaDir = this->GetPlatformToolsetCudaCustomDir()) {
409     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR", cudaDir);
410   }
411   if (const char* vcTargetsDir = this->GetCustomVCTargetsPath()) {
412     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR",
413                       vcTargetsDir);
414   }
415
416   return true;
417 }
418
419 bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
420   std::string const& ts, cmMakefile* mf)
421 {
422   std::vector<std::string> const fields = cmTokenize(ts, ",");
423   std::vector<std::string>::const_iterator fi = fields.begin();
424   if (fi == fields.end()) {
425     return true;
426   }
427
428   // The first field may be the VS platform toolset.
429   if (fi->find('=') == fi->npos) {
430     this->GeneratorToolset = *fi;
431     ++fi;
432   }
433
434   std::set<std::string> handled;
435
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 */
442       e <<
443         "Generator\n"
444         "  " << this->GetName() << "\n"
445         "given toolset specification\n"
446         "  " << ts << "\n"
447         "that contains a field after the first ',' with no '='."
448         ;
449       /* clang-format on */
450       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
451       return false;
452     }
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 */
458       e <<
459         "Generator\n"
460         "  " << this->GetName() << "\n"
461         "given toolset specification\n"
462         "  " << ts << "\n"
463         "that contains duplicate field key '" << key << "'."
464         ;
465       /* clang-format on */
466       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
467       return false;
468     }
469     if (!this->ProcessGeneratorToolsetField(key, value)) {
470       std::ostringstream e;
471       /* clang-format off */
472       e <<
473         "Generator\n"
474         "  " << this->GetName() << "\n"
475         "given toolset specification\n"
476         "  " << ts << "\n"
477         "that contains invalid field '" << *fi << "'."
478         ;
479       /* clang-format on */
480       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
481       return false;
482     }
483   }
484
485   return true;
486 }
487
488 bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
489   std::string const& key, std::string const& value)
490 {
491   if (key == "cuda") {
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('\\');
499       }
500       /* check for legacy toolkit folder structure */
501       if (cmsys::SystemTools::FileIsDirectory(
502             cmStrCat(this->GeneratorToolsetCudaCustomDir, "nvcc"))) {
503         this->GeneratorToolsetCudaNvccSubdir = "nvcc\\";
504       }
505       if (cmsys::SystemTools::FileIsDirectory(
506             cmStrCat(this->GeneratorToolsetCudaCustomDir,
507                      "CUDAVisualStudioIntegration"))) {
508         this->GeneratorToolsetCudaVSIntegrationSubdir =
509           "CUDAVisualStudioIntegration\\";
510       }
511     } else {
512       this->GeneratorToolsetCuda = value;
513     }
514     return true;
515   }
516   if (key == "customFlagTableDir") {
517     this->CustomFlagTableDir = value;
518     cmSystemTools::ConvertToUnixSlashes(this->CustomFlagTableDir);
519     return true;
520   }
521   if (key == "version") {
522     this->GeneratorToolsetVersion = value;
523     return true;
524   }
525   if (key == "VCTargetsPath") {
526     this->CustomVCTargetsPath = value;
527     ConvertToWindowsSlashes(this->CustomVCTargetsPath);
528     return true;
529   }
530   return false;
531 }
532
533 bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf)
534 {
535   if (this->SystemName == "Windows") {
536     if (!this->InitializeWindows(mf)) {
537       return false;
538     }
539   } else if (this->SystemName == "WindowsCE") {
540     this->SystemIsWindowsCE = true;
541     if (!this->InitializeWindowsCE(mf)) {
542       return false;
543     }
544   } else if (this->SystemName == "WindowsPhone") {
545     this->SystemIsWindowsPhone = true;
546     if (!this->InitializeWindowsPhone(mf)) {
547       return false;
548     }
549   } else if (this->SystemName == "WindowsStore") {
550     this->SystemIsWindowsStore = true;
551     if (!this->InitializeWindowsStore(mf)) {
552       return false;
553     }
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());
560       return false;
561     }
562     if (mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM") == "Tegra-Android") {
563       if (!this->InitializeTegraAndroid(mf)) {
564         return false;
565       }
566     } else {
567       this->SystemIsAndroid = true;
568       if (!this->InitializeAndroid(mf)) {
569         return false;
570       }
571     }
572   }
573
574   return true;
575 }
576
577 bool cmGlobalVisualStudio10Generator::InitializeWindows(cmMakefile*)
578 {
579   return true;
580 }
581
582 bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf)
583 {
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());
589     return false;
590   }
591
592   this->DefaultPlatformToolset = this->SelectWindowsCEToolset();
593
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";
599   }
600
601   return true;
602 }
603
604 bool cmGlobalVisualStudio10Generator::InitializeWindowsPhone(cmMakefile* mf)
605 {
606   std::ostringstream e;
607   e << this->GetName() << " does not support Windows Phone.";
608   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
609   return false;
610 }
611
612 bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
613 {
614   std::ostringstream e;
615   e << this->GetName() << " does not support Windows Store.";
616   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
617   return false;
618 }
619
620 bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf)
621 {
622   std::string v = this->GetInstalledNsightTegraVersion();
623   if (v.empty()) {
624     mf->IssueMessage(MessageType::FATAL_ERROR,
625                      "CMAKE_SYSTEM_NAME is 'Android' but "
626                      "'NVIDIA Nsight Tegra Visual Studio Edition' "
627                      "is not installed.");
628     return false;
629   }
630   this->DefaultPlatformName = "Tegra-Android";
631   this->DefaultPlatformToolset = "Default";
632   this->NsightTegraVersion = v;
633   mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v);
634   return true;
635 }
636
637 bool cmGlobalVisualStudio10Generator::InitializeAndroid(cmMakefile* mf)
638 {
639   std::ostringstream e;
640   e << this->GetName() << " does not support Android.";
641   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
642   return false;
643 }
644
645 bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
646   std::string& toolset) const
647 {
648   toolset.clear();
649   return false;
650 }
651
652 bool cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
653   std::string& toolset) const
654 {
655   toolset.clear();
656   return false;
657 }
658
659 std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
660 {
661   if (this->SystemVersion == "8.0") {
662     return "CE800";
663   }
664   return "";
665 }
666
667 //! Create a local generator appropriate to this Global Generator
668 std::unique_ptr<cmLocalGenerator>
669 cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmMakefile* mf)
670 {
671   return std::unique_ptr<cmLocalGenerator>(
672     cm::make_unique<cmLocalVisualStudio10Generator>(this, mf));
673 }
674
675 void cmGlobalVisualStudio10Generator::Generate()
676 {
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 */
683     e <<
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 "
688       "filenames:\n"
689       "  ";
690     /* clang-format on */
691     bool first = true;
692     for (auto const& name : this->AndroidExecutableWarnings) {
693       if (!first) {
694         e << ", ";
695       }
696       first = false;
697       e << name;
698     }
699     this->CMakeInstance->IssueMessage(MessageType::WARNING, e.str());
700   }
701   if (this->LongestSource.Length > 0) {
702     cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator();
703     std::ostringstream e;
704     /* clang-format off */
705     e <<
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 "
709       "Visual Studio 10.  "
710       "A more detailed explanation follows."
711       "\n"
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());
726   }
727   if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
728         "CMAKE_VS_NUGET_PACKAGE_RESTORE")) {
729     this->CMakeInstance->MarkCliAsUsed("CMAKE_VS_NUGET_PACKAGE_RESTORE");
730   }
731 }
732
733 void cmGlobalVisualStudio10Generator::EnableLanguage(
734   std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
735 {
736   for (std::string const& it : lang) {
737     if (it == "ASM_NASM") {
738       this->NasmEnabled = true;
739     }
740     if (it == "CUDA") {
741       this->CudaEnabled = true;
742     }
743   }
744   this->AddPlatformDefinitions(mf);
745   cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
746 }
747
748 const char* cmGlobalVisualStudio10Generator::GetCustomVCTargetsPath() const
749 {
750   if (this->CustomVCTargetsPath.empty()) {
751     return nullptr;
752   }
753   return this->CustomVCTargetsPath.c_str();
754 }
755
756 const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
757 {
758   std::string const& toolset = this->GetPlatformToolsetString();
759   if (toolset.empty()) {
760     return nullptr;
761   }
762   return toolset.c_str();
763 }
764
765 std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString()
766   const
767 {
768   if (!this->GeneratorToolset.empty()) {
769     return this->GeneratorToolset;
770   }
771   if (this->SystemIsAndroid) {
772     if (!this->DefaultAndroidToolset.empty()) {
773       return this->DefaultAndroidToolset;
774     }
775   } else {
776     if (!this->DefaultPlatformToolset.empty()) {
777       return this->DefaultPlatformToolset;
778     }
779   }
780   static std::string const empty;
781   return empty;
782 }
783
784 std::string const&
785 cmGlobalVisualStudio10Generator::GetPlatformToolsetVersionProps() const
786 {
787   return this->GeneratorToolsetVersionProps;
788 }
789
790 const char*
791 cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitecture() const
792 {
793   std::string const& hostArch =
794     this->GetPlatformToolsetHostArchitectureString();
795   if (hostArch.empty()) {
796     return nullptr;
797   }
798   return hostArch.c_str();
799 }
800
801 std::string const&
802 cmGlobalVisualStudio10Generator::GetPlatformToolsetHostArchitectureString()
803   const
804 {
805   if (!this->GeneratorToolsetHostArchitecture.empty()) {
806     return this->GeneratorToolsetHostArchitecture;
807   }
808   if (!this->DefaultPlatformToolsetHostArchitecture.empty()) {
809     return this->DefaultPlatformToolsetHostArchitecture;
810   }
811   static std::string const empty;
812   return empty;
813 }
814
815 const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCuda() const
816 {
817   if (!this->GeneratorToolsetCuda.empty()) {
818     return this->GeneratorToolsetCuda.c_str();
819   }
820   return nullptr;
821 }
822
823 std::string const&
824 cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaString() const
825 {
826   return this->GeneratorToolsetCuda;
827 }
828
829 const char* cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDir()
830   const
831 {
832   if (!this->GeneratorToolsetCudaCustomDir.empty()) {
833     return this->GeneratorToolsetCudaCustomDir.c_str();
834   }
835   return nullptr;
836 }
837
838 std::string const&
839 cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaCustomDirString() const
840 {
841   return this->GeneratorToolsetCudaCustomDir;
842 }
843
844 std::string const&
845 cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaNvccSubdirString() const
846 {
847   return this->GeneratorToolsetCudaNvccSubdir;
848 }
849
850 std::string const& cmGlobalVisualStudio10Generator::
851   GetPlatformToolsetCudaVSIntegrationSubdirString() const
852 {
853   return this->GeneratorToolsetCudaVSIntegrationSubdir;
854 }
855
856 cmGlobalVisualStudio10Generator::AuxToolset
857 cmGlobalVisualStudio10Generator::FindAuxToolset(std::string&,
858                                                 std::string&) const
859 {
860   return AuxToolset::None;
861 }
862
863 bool cmGlobalVisualStudio10Generator::FindMakeProgram(cmMakefile* mf)
864 {
865   if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
866     return false;
867   }
868   mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND", this->GetMSBuildCommand());
869   return true;
870 }
871
872 std::string const& cmGlobalVisualStudio10Generator::GetMSBuildCommand()
873 {
874   if (!this->MSBuildCommandInitialized) {
875     this->MSBuildCommandInitialized = true;
876     this->MSBuildCommand = this->FindMSBuildCommand();
877   }
878   return this->MSBuildCommand;
879 }
880
881 cm::optional<std::string>
882 cmGlobalVisualStudio10Generator::FindMSBuildCommandEarly(cmMakefile*)
883 {
884   return this->GetMSBuildCommand();
885 }
886
887 std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
888 {
889   std::string msbuild;
890   std::string mskey;
891
892   // Search in standard location.
893   mskey = cmStrCat(
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)) {
901       return msbuild;
902     }
903   }
904
905   msbuild = "MSBuild.exe";
906   return msbuild;
907 }
908
909 std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
910 {
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.
915     return "";
916   }
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();
920 }
921
922 bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
923 {
924   // Skip this in special cases within our own test suite.
925   if (this->GetPlatformName() == "Test Platform" ||
926       this->GetPlatformToolsetString() == "Test Toolset") {
927     return true;
928   }
929
930   std::string wd;
931   if (!this->ConfiguredFilesPath.empty()) {
932     // In a try-compile we are given the outer CMakeFiles directory.
933     wd = this->ConfiguredFilesPath;
934   } else {
935     wd = cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
936                   "/CMakeFiles");
937   }
938   wd += "/";
939   wd += cmVersion::GetCMakeVersion();
940
941   // We record the result persistently in a file.
942   std::string const txt = wd + "/VCTargetsPath.txt";
943
944   // If we have a recorded result, use it.
945   {
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);
950       return true;
951     }
952   }
953
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();
959     return false;
960   }
961
962   // Generate a project file for MSBuild to tell us the VCTargetsPath value.
963   std::string const vcxproj = "VCTargetsPath.vcxproj";
964   {
965     std::string const vcxprojAbs = wd + "/" + vcxproj;
966     cmsys::ofstream fout(vcxprojAbs.c_str());
967     cmXMLWriter xw(fout);
968
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");
979     }
980     {
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());
987     }
988     {
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"
995                    ? "Android"
996                    : "Win32Proj");
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());
1010       }
1011       if (!this->WindowsTargetPlatformVersion.empty()) {
1012         cmXMLElement(epg, "WindowsTargetPlatformVersion")
1013           .Content(this->WindowsTargetPlatformVersion);
1014       }
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");
1020         }
1021       }
1022     }
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);
1028     }
1029     {
1030       cmXMLElement epg(eprj, "PropertyGroup");
1031       epg.Attribute("Label", "Configuration");
1032       {
1033         cmXMLElement ect(epg, "ConfigurationType");
1034         if (this->IsNsightTegra()) {
1035           // Tegra-Android platform does not understand "Utility".
1036           ect.Content("StaticLibrary");
1037         } else {
1038           ect.Content("Utility");
1039         }
1040       }
1041       cmXMLElement(epg, "CharacterSet").Content("MultiByte");
1042       if (this->IsNsightTegra()) {
1043         cmXMLElement(epg, "NdkToolchainVersion")
1044           .Content(this->GetPlatformToolsetString());
1045       } else {
1046         cmXMLElement(epg, "PlatformToolset")
1047           .Content(this->GetPlatformToolsetString());
1048       }
1049     }
1050     cmXMLElement(eprj, "Import")
1051       .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
1052     {
1053       cmXMLElement eidg(eprj, "ItemDefinitionGroup");
1054       cmXMLElement epbe(eidg, "PostBuildEvent");
1055       cmXMLElement(epbe, "Command")
1056         .Content("echo VCTargetsPath=$(VCTargetsPath)");
1057     }
1058     cmXMLElement(eprj, "Import")
1059       .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
1060   }
1061
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());
1069   std::string out;
1070   int ret = 0;
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 */
1078     e <<
1079       "Failed to run MSBuild command:\n"
1080       "  " << cmd[0] << "\n"
1081       "to get the value of VCTargetsPath:\n"
1082       "  " << out << "\n"
1083       ;
1084     /* clang-format on */
1085     if (ret != 0) {
1086       e << "Exit code: " << ret << "\n";
1087     }
1088     mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
1089     cmSystemTools::SetFatalErrorOccurred();
1090     return false;
1091   }
1092   this->VCTargetsPath = regex.match(1);
1093   cmSystemTools::ConvertToUnixSlashes(this->VCTargetsPath);
1094
1095   {
1096     cmsys::ofstream fout(txt.c_str());
1097     fout << this->VCTargetsPath << "\n";
1098   }
1099   return true;
1100 }
1101
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)
1109 {
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());
1114
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);
1120
1121   // Workaround to convince VCExpress.exe to produce output.
1122   const bool requiresOutputForward =
1123     (makeProgramLower.find("vcexpress") != std::string::npos);
1124
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.
1127   cmSlnData slnData;
1128   {
1129     std::string slnFile;
1130     if (!projectDir.empty()) {
1131       slnFile = cmStrCat(projectDir, '/');
1132     }
1133     slnFile += projectName;
1134     slnFile += ".sln";
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) {
1140         if (useDevEnv) {
1141           break;
1142         }
1143         std::string proj = project.GetRelativePath();
1144         if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
1145           useDevEnv = true;
1146         }
1147       }
1148     }
1149   }
1150   if (useDevEnv) {
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);
1155   }
1156
1157   std::vector<std::string> realTargetNames = targetNames;
1158   if (targetNames.empty() ||
1159       ((targetNames.size() == 1) && targetNames.front().empty())) {
1160     realTargetNames = { "ALL_BUILD" };
1161   }
1162   for (const auto& tname : realTargetNames) {
1163     // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
1164     // /target:ALL_BUILD
1165     //                         /m
1166     if (tname.empty()) {
1167       continue;
1168     }
1169
1170     GeneratedMakeCommand makeCommand;
1171     makeCommand.RequiresOutputForward = requiresOutputForward;
1172     makeCommand.Add(makeProgramSelected);
1173     cm::optional<cmSlnProjectEntry> proj = cm::nullopt;
1174
1175     if (tname == "clean") {
1176       makeCommand.Add(cmStrCat(projectName, ".sln"));
1177       makeCommand.Add("/t:Clean");
1178     } else {
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
1183         if (proj) {
1184           targetProject = proj->GetRelativePath();
1185           cmSystemTools::ConvertToUnixSlashes(targetProject);
1186         }
1187       }
1188       makeCommand.Add(targetProject);
1189
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;
1194
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();
1201       } else {
1202         // There are no package references defined.
1203         requiresRestore = false;
1204       }
1205
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");
1211         } else {
1212           // Invoke restore target, unless it has been explicitly disabled.
1213           bool restorePackages = true;
1214
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();
1231           }
1232
1233           if (restorePackages) {
1234             if (this->IsMsBuildRestoreSupported()) {
1235               makeCommand.Add("/restore");
1236             } else {
1237               GeneratedMakeCommand restoreCommand;
1238               restoreCommand.Add(makeProgramSelected);
1239               restoreCommand.Add(targetProject);
1240               restoreCommand.Add("/t:Restore");
1241               makeCommands.emplace_back(restoreCommand);
1242             }
1243           }
1244         }
1245       }
1246     }
1247
1248     std::string plainConfig = config;
1249     if (config.empty()) {
1250       plainConfig = "Debug";
1251     }
1252
1253     std::string platform = GetPlatformName();
1254     if (proj) {
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
1260         platform =
1261           slnData.GetConfigurationTarget(tname, plainConfig, platform);
1262       }
1263     }
1264
1265     makeCommand.Add(cmStrCat("/p:Configuration=", plainConfig));
1266     makeCommand.Add(cmStrCat("/p:Platform=", platform));
1267     makeCommand.Add(
1268       cmStrCat("/p:VisualStudioVersion=", this->GetIDEVersion()));
1269
1270     if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
1271       if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
1272         makeCommand.Add("/m");
1273       } else {
1274         makeCommand.Add(cmStrCat("/m:", std::to_string(jobs)));
1275       }
1276       // Having msbuild.exe and cl.exe using multiple jobs is discouraged
1277       makeCommand.Add("/p:CL_MPCount=1");
1278     }
1279
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));
1285   }
1286   return makeCommands;
1287 }
1288
1289 bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
1290 {
1291   if (this->DefaultPlatformToolset == "v100") {
1292     // The v100 64-bit toolset does not exist in the express edition.
1293     this->DefaultPlatformToolset.clear();
1294   }
1295   if (this->GetPlatformToolset()) {
1296     return true;
1297   }
1298   // This edition does not come with 64-bit tools.  Look for them.
1299   //
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",
1308         winSDK_7_1)) {
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";
1313     return true;
1314   } else {
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();
1323     return false;
1324   }
1325 }
1326
1327 std::string cmGlobalVisualStudio10Generator::GenerateRuleFile(
1328   std::string const& output) const
1329 {
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");
1337   return ruleFile;
1338 }
1339
1340 void cmGlobalVisualStudio10Generator::PathTooLong(cmGeneratorTarget* target,
1341                                                   cmSourceFile const* sf,
1342                                                   std::string const& sfRel)
1343 {
1344   size_t len =
1345     (target->GetLocalGenerator()->GetCurrentBinaryDirectory().length() + 1 +
1346      sfRel.length());
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;
1352   }
1353 }
1354
1355 std::string cmGlobalVisualStudio10Generator::Encoding()
1356 {
1357   return "utf-8";
1358 }
1359
1360 const char* cmGlobalVisualStudio10Generator::GetToolsVersion() const
1361 {
1362   switch (this->Version) {
1363     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
1364     case cmGlobalVisualStudioGenerator::VSVersion::VS10:
1365     case cmGlobalVisualStudioGenerator::VSVersion::VS11:
1366       return "4.0";
1367
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
1370       // version number
1371     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
1372       return "12.0";
1373     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
1374       return "14.0";
1375     case cmGlobalVisualStudioGenerator::VSVersion::VS15:
1376       return "15.0";
1377     case cmGlobalVisualStudioGenerator::VSVersion::VS16:
1378       return "16.0";
1379     case cmGlobalVisualStudioGenerator::VSVersion::VS17:
1380       return "17.0";
1381   }
1382   return "";
1383 }
1384
1385 bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
1386 {
1387   return !this->NsightTegraVersion.empty();
1388 }
1389
1390 std::string cmGlobalVisualStudio10Generator::GetNsightTegraVersion() const
1391 {
1392   return this->NsightTegraVersion;
1393 }
1394
1395 std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
1396 {
1397   std::string version;
1398   cmSystemTools::ReadRegistryValue(
1399     "HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Nsight Tegra;"
1400     "Version",
1401     version, cmSystemTools::KeyWOW64_32);
1402   return version;
1403 }
1404
1405 std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const
1406 {
1407   if (this->GetSystemName() == "Android") {
1408     return this->GetAndroidApplicationTypeRevision();
1409   }
1410
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);
1416 }
1417
1418 static std::string cmLoadFlagTableString(Json::Value entry, const char* field)
1419 {
1420   if (entry.isMember(field)) {
1421     auto string = entry[field];
1422     if (string.isConvertibleTo(Json::ValueType::stringValue)) {
1423       return string.asString();
1424     }
1425   }
1426   return "";
1427 }
1428
1429 static unsigned int cmLoadFlagTableSpecial(Json::Value entry,
1430                                            const char* field)
1431 {
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;
1456         }
1457       }
1458     }
1459   }
1460   return value;
1461 }
1462
1463 namespace {
1464
1465 cmIDEFlagTable const* cmLoadFlagTableJson(std::string const& flagJsonPath,
1466                                           cm::optional<std::string> vsVer)
1467 {
1468   cmIDEFlagTable* ret = nullptr;
1469   auto savedFlagIterator = loadedFlagJsonFiles.find(flagJsonPath);
1470   if (savedFlagIterator != loadedFlagJsonFiles.end()) {
1471     ret = savedFlagIterator->second.data();
1472   } else {
1473     Json::Reader reader;
1474     cmsys::ifstream stream;
1475
1476     stream.open(flagJsonPath.c_str(), std::ios_base::in);
1477     if (stream) {
1478       Json::Value flags;
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()) {
1486               if (!vsVer ||
1487                   cmSystemTools::VersionCompareGreater(vsmin, *vsVer)) {
1488                 continue;
1489               }
1490             }
1491           }
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);
1499         }
1500         cmIDEFlagTable endFlag{ "", "", "", "", 0 };
1501         flagTable.push_back(endFlag);
1502
1503         loadedFlagJsonFiles[flagJsonPath] = flagTable;
1504         ret = loadedFlagJsonFiles[flagJsonPath].data();
1505       }
1506     }
1507   }
1508   return ret;
1509 }
1510 }
1511
1512 cm::optional<std::string> cmGlobalVisualStudio10Generator::FindFlagTable(
1513   cm::string_view toolsetName, cm::string_view table) const
1514 {
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;
1521     }
1522     customFlagTableFile =
1523       cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
1524                table, ".json");
1525     if (cmSystemTools::FileExists(customFlagTableFile)) {
1526       return customFlagTableFile;
1527     }
1528   }
1529   std::string fullPath =
1530     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Templates/MSBuild/FlagTables/",
1531              toolsetName, '_', table, ".json");
1532   if (cmSystemTools::FileExists(fullPath)) {
1533     return fullPath;
1534   }
1535   return {};
1536 }
1537
1538 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::LoadFlagTable(
1539   std::string const& toolSpecificName, std::string const& defaultName,
1540   std::string const& table) const
1541 {
1542   cmMakefile* mf = this->GetCurrentMakefile();
1543
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);
1549     } else {
1550       mf->IssueMessage(MessageType::FATAL_ERROR,
1551                        cmStrCat("JSON flag table for ", table,
1552                                 " not found for toolset ", toolSpecificName));
1553       return nullptr;
1554     }
1555   } else {
1556     std::string const& genericName =
1557       this->CanonicalToolsetName(this->GetPlatformToolsetString());
1558     cm::optional<std::string> found = this->FindFlagTable(genericName, table);
1559     if (!found) {
1560       found = this->FindFlagTable(defaultName, table);
1561     }
1562     if (found) {
1563       filename = std::move(*found);
1564     } else {
1565       mf->IssueMessage(MessageType::FATAL_ERROR,
1566                        cmStrCat("JSON flag table for ", table,
1567                                 " not found for toolset ", genericName, " ",
1568                                 defaultName));
1569       return nullptr;
1570     }
1571   }
1572
1573   cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
1574   if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename, vsVer)) {
1575     return ret;
1576   }
1577
1578   mf->IssueMessage(
1579     MessageType::FATAL_ERROR,
1580     cmStrCat("JSON flag table could not be loaded:\n  ", filename));
1581   return nullptr;
1582 }
1583
1584 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetClFlagTable() const
1585 {
1586   return LoadFlagTable(this->GetClFlagTableName(),
1587                        this->DefaultCLFlagTableName, "CL");
1588 }
1589
1590 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCSharpFlagTable()
1591   const
1592 {
1593   return LoadFlagTable(this->GetCSharpFlagTableName(),
1594                        this->DefaultCSharpFlagTableName, "CSharp");
1595 }
1596
1597 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetRcFlagTable() const
1598 {
1599   return LoadFlagTable(this->GetRcFlagTableName(),
1600                        this->DefaultRCFlagTableName, "RC");
1601 }
1602
1603 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLibFlagTable() const
1604 {
1605   return LoadFlagTable(this->GetLibFlagTableName(),
1606                        this->DefaultLibFlagTableName, "LIB");
1607 }
1608
1609 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
1610 {
1611   return LoadFlagTable(this->GetLinkFlagTableName(),
1612                        this->DefaultLinkFlagTableName, "Link");
1613 }
1614
1615 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaFlagTable() const
1616 {
1617   return LoadFlagTable(std::string(), this->DefaultCudaFlagTableName, "Cuda");
1618 }
1619
1620 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
1621   const
1622 {
1623   return LoadFlagTable(std::string(), this->DefaultCudaHostFlagTableName,
1624                        "CudaHost");
1625 }
1626
1627 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
1628 {
1629   return LoadFlagTable(this->GetMasmFlagTableName(),
1630                        this->DefaultMasmFlagTableName, "MASM");
1631 }
1632
1633 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
1634 {
1635   return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
1636 }
1637
1638 bool cmGlobalVisualStudio10Generator::IsMsBuildRestoreSupported() const
1639 {
1640   if (this->Version >= VSVersion::VS16) {
1641     return true;
1642   }
1643
1644   static std::string const vsVer15_7_5 = "15.7.27703.2042";
1645   cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
1646   return (vsVer &&
1647           cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_7_5));
1648 }
1649
1650 std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
1651 {
1652   std::string const& toolset = this->GetPlatformToolsetString();
1653   std::string const useToolset = this->CanonicalToolsetName(toolset);
1654
1655   if (toolset == "v142") {
1656     return "v142";
1657   } else if (toolset == "v141") {
1658     return "v141";
1659   } else if (useToolset == "v140") {
1660     return "v140";
1661   } else if (useToolset == "v120") {
1662     return "v12";
1663   } else if (useToolset == "v110") {
1664     return "v11";
1665   } else if (useToolset == "v100") {
1666     return "v10";
1667   } else {
1668     return "";
1669   }
1670 }
1671
1672 std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
1673 {
1674   std::string const& toolset = this->GetPlatformToolsetString();
1675   std::string const useToolset = this->CanonicalToolsetName(toolset);
1676
1677   if (useToolset == "v142") {
1678     return "v142";
1679   } else if (useToolset == "v141") {
1680     return "v141";
1681   } else if (useToolset == "v140") {
1682     return "v140";
1683   } else if (useToolset == "v120") {
1684     return "v12";
1685   } else if (useToolset == "v110") {
1686     return "v11";
1687   } else if (useToolset == "v100") {
1688     return "v10";
1689   } else {
1690     return "";
1691   }
1692 }
1693
1694 std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
1695 {
1696   std::string const& toolset = this->GetPlatformToolsetString();
1697   std::string const useToolset = this->CanonicalToolsetName(toolset);
1698
1699   if ((useToolset == "v140") || (useToolset == "v141") ||
1700       (useToolset == "v142")) {
1701     return "v14";
1702   } else if (useToolset == "v120") {
1703     return "v12";
1704   } else if (useToolset == "v110") {
1705     return "v11";
1706   } else if (useToolset == "v100") {
1707     return "v10";
1708   } else {
1709     return "";
1710   }
1711 }
1712
1713 std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
1714 {
1715   std::string const& toolset = this->GetPlatformToolsetString();
1716   std::string const useToolset = this->CanonicalToolsetName(toolset);
1717
1718   if ((useToolset == "v140") || (useToolset == "v141") ||
1719       (useToolset == "v142")) {
1720     return "v14";
1721   } else if (useToolset == "v120") {
1722     return "v12";
1723   } else if (useToolset == "v110") {
1724     return "v11";
1725   } else if (useToolset == "v100") {
1726     return "v10";
1727   } else {
1728     return "";
1729   }
1730 }
1731
1732 std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
1733 {
1734   std::string const& toolset = this->GetPlatformToolsetString();
1735   std::string const useToolset = this->CanonicalToolsetName(toolset);
1736
1737   if (useToolset == "v142") {
1738     return "v142";
1739   } else if (useToolset == "v141") {
1740     return "v141";
1741   } else if (useToolset == "v140") {
1742     return "v140";
1743   } else if (useToolset == "v120") {
1744     return "v12";
1745   } else if (useToolset == "v110") {
1746     return "v11";
1747   } else if (useToolset == "v100") {
1748     return "v10";
1749   } else {
1750     return "";
1751   }
1752 }
1753
1754 std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
1755 {
1756   std::string const& toolset = this->GetPlatformToolsetString();
1757   std::string const useToolset = this->CanonicalToolsetName(toolset);
1758
1759   if ((useToolset == "v140") || (useToolset == "v141") ||
1760       (useToolset == "v142")) {
1761     return "v14";
1762   } else if (useToolset == "v120") {
1763     return "v12";
1764   } else if (useToolset == "v110") {
1765     return "v11";
1766   } else if (useToolset == "v100") {
1767     return "v10";
1768   } else {
1769     return "";
1770   }
1771 }
1772
1773 std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName(
1774   std::string const& toolset) const
1775 {
1776   std::size_t length = toolset.length();
1777
1778   if (cmHasLiteralSuffix(toolset, "_xp")) {
1779     length -= 3;
1780   }
1781
1782   return toolset.substr(0, length);
1783 }