cmVisualStudio10TargetGenerator.cxx 165 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3
#include "cmVisualStudio10TargetGenerator.h"
Brad King's avatar
Brad King committed
4

5
#include "cmAlgorithms.h"
6
#include "cmComputeLinkInformation.h"
7
#include "cmCustomCommandGenerator.h"
8
#include "cmGeneratedFileStream.h"
9
#include "cmGeneratorExpression.h"
10
11
#include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio10Generator.h"
12
#include "cmLocalVisualStudio10Generator.h"
13
14
#include "cmMakefile.h"
#include "cmSourceFile.h"
15
#include "cmSystemTools.h"
16
17
#include "cmVisualStudioGeneratorOptions.h"
#include "windows.h"
18

19
#include <iterator>
20
#include <memory> // IWYU pragma: keep
21

22
23
24
25
26
27
28
29
30
31
static void ConvertToWindowsSlash(std::string& s);

static std::string cmVS10EscapeXML(std::string arg)
{
  cmSystemTools::ReplaceString(arg, "&", "&amp;");
  cmSystemTools::ReplaceString(arg, "<", "&lt;");
  cmSystemTools::ReplaceString(arg, ">", "&gt;");
  return arg;
}

32
33
34
35
36
37
38
39
40
static std::string cmVS10EscapeAttr(std::string arg)
{
  cmSystemTools::ReplaceString(arg, "&", "&amp;");
  cmSystemTools::ReplaceString(arg, "<", "&lt;");
  cmSystemTools::ReplaceString(arg, ">", "&gt;");
  cmSystemTools::ReplaceString(arg, "\"", "&quot;");
  return arg;
}

41
42
struct cmVisualStudio10TargetGenerator::Elem
{
43
  std::ostream& S;
44
  const int Indent;
45
  bool HasElements = false;
46
  bool HasContent = false;
47
  std::string Tag;
48

49
  Elem(std::ostream& s, const char* tag)
50
    : S(s)
51
    , Indent(0)
52
    , Tag(tag)
53
  {
54
    this->StartElement();
55
  }
56
  Elem(const Elem&) = delete;
57
58
59
  Elem(Elem& par, const char* tag)
    : S(par.S)
    , Indent(par.Indent + 1)
60
    , Tag(tag)
61
62
  {
    par.SetHasElements();
63
    this->StartElement();
64
  }
65
66
67
  void SetHasElements()
  {
    if (!HasElements) {
68
      this->S << ">\n";
69
70
71
      HasElements = true;
    }
  }
72
  std::ostream& WriteString(const char* line);
73
  void StartElement() { this->WriteString("<") << this->Tag; }
74
75
  void Element(const char* tag, const std::string& val)
  {
76
    Elem(*this, tag).Content(val);
77
  }
78
79
  Elem& Attribute(const char* an, const std::string& av)
  {
80
    this->S << " " << an << "=\"" << cmVS10EscapeAttr(av) << "\"";
81
82
    return *this;
  }
83
84
  void Content(const std::string& val)
  {
85
86
87
88
89
    if (!this->HasContent) {
      this->S << ">";
      this->HasContent = true;
    }
    this->S << cmVS10EscapeXML(val);
90
  }
91
  ~Elem()
92
  {
93
94
95
96
97
    // Do not emit element which has not been started
    if (Tag.empty()) {
      return;
    }

98
    if (HasElements) {
99
100
101
102
103
104
      this->WriteString("</") << this->Tag << ">";
      if (this->Indent > 0) {
        this->S << '\n';
      } else {
        // special case: don't print EOL at EOF
      }
105
106
    } else if (HasContent) {
      this->S << "</" << this->Tag << ">\n";
107
    } else {
108
      this->S << " />\n";
109
110
    }
  }
111
112
113

  void WritePlatformConfigTag(const char* tag, const std::string& cond,
                              const std::string& content);
114
115
};

116
117
118
class cmVS10GeneratorOptions : public cmVisualStudioGeneratorOptions
{
public:
119
  typedef cmVisualStudio10TargetGenerator::Elem Elem;
120
121
122
123
124
125
126
127
  cmVS10GeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool,
                         cmVS7FlagTable const* table,
                         cmVisualStudio10TargetGenerator* g = nullptr)
    : cmVisualStudioGeneratorOptions(lg, tool, table)
    , TargetGenerator(g)
  {
  }

128
  void OutputFlag(std::ostream& /*fout*/, int /*indent*/, const char* tag,
129
130
131
132
133
                  const std::string& content) override
  {
    if (!this->GetConfiguration().empty()) {
      // if there are configuration specific flags, then
      // use the configuration specific tag for PreprocessorDefinitions
134
135
136
      const std::string cond =
        this->TargetGenerator->CalcCondition(this->GetConfiguration());
      this->Parent->WritePlatformConfigTag(tag, cond, content);
137
    } else {
138
      this->Parent->Element(tag, content);
139
140
141
142
    }
  }

private:
143
144
145
  cmVisualStudio10TargetGenerator* const TargetGenerator;
  Elem* Parent = nullptr;
  friend cmVisualStudio10TargetGenerator::OptionsHelper;
146
147
};

148
struct cmVisualStudio10TargetGenerator::OptionsHelper
149
{
150
151
152
153
154
155
156
  cmVS10GeneratorOptions& O;
  OptionsHelper(cmVS10GeneratorOptions& o, Elem& e)
    : O(o)
  {
    O.Parent = &e;
  }
  ~OptionsHelper() { O.Parent = nullptr; }
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  void OutputPreprocessorDefinitions(const std::string& lang)
  {
    O.OutputPreprocessorDefinitions(O.Parent->S, O.Parent->Indent + 1, lang);
  }
  void OutputAdditionalIncludeDirectories(const std::string& lang)
  {
    O.OutputAdditionalIncludeDirectories(O.Parent->S, O.Parent->Indent + 1,
                                         lang);
  }
  void OutputFlagMap() { O.OutputFlagMap(O.Parent->S, O.Parent->Indent + 1); }
  void PrependInheritedString(std::string const& key)
  {
    O.PrependInheritedString(key);
  }
};
173

174
175
176
177
178
179
static std::string cmVS10EscapeComment(std::string comment)
{
  // MSBuild takes the CDATA of a <Message></Message> element and just
  // does "echo $CDATA" with no escapes.  We must encode the string.
  // http://technet.microsoft.com/en-us/library/cc772462%28WS.10%29.aspx
  std::string echoable;
180
181
  for (char c : comment) {
    switch (c) {
182
183
184
185
186
      case '\r':
        break;
      case '\n':
        echoable += '\t';
        break;
187
188
189
190
191
      case '"': /* no break */
      case '|': /* no break */
      case '&': /* no break */
      case '<': /* no break */
      case '>': /* no break */
192
193
      case '^':
        echoable += '^'; /* no break */
194
        CM_FALLTHROUGH;
195
      default:
196
        echoable += c;
197
        break;
198
    }
199
  }
200
201
202
  return echoable;
}

203
204
205
206
207
208
static bool cmVS10IsTargetsFile(std::string const& path)
{
  std::string const ext = cmSystemTools::GetFilenameLastExtension(path);
  return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
}

209
static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
210
211
212
{
  std::string res;
  res = ".vcxproj";
213
  if (t->IsCSharpOnly()) {
214
215
216
217
218
    res = ".csproj";
  }
  return res;
}

219
220
cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
  cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
221
222
223
224
225
226
  : GeneratorTarget(target)
  , Makefile(target->Target->GetMakefile())
  , Platform(gg->GetPlatformName())
  , Name(target->GetName())
  , GUID(gg->GetGUID(this->Name))
  , GlobalGenerator(gg)
227
228
  , LocalGenerator(
      (cmLocalVisualStudio10Generator*)target->GetLocalGenerator())
229
{
230
  this->Makefile->GetConfigurations(this->Configurations);
231
  this->NsightTegra = gg->IsNsightTegra();
232
  for (int i = 0; i < 4; ++i) {
233
    this->NsightTegraVersion[i] = 0;
234
  }
235
236
237
  sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u",
         &this->NsightTegraVersion[0], &this->NsightTegraVersion[1],
         &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]);
238
  this->MSTools = !this->NsightTegra;
239
  this->Managed = false;
240
  this->TargetCompileAsWinRT = false;
241
242
  this->IsMissingFiles = false;
  this->DefaultArtifactDir =
243
    this->LocalGenerator->GetCurrentBinaryDirectory() + "/" +
244
    this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
245
246
  this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() ==
                         this->Makefile->GetCurrentBinaryDirectory());
247
248
249
250
251
252
}

cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
{
}

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
std::string cmVisualStudio10TargetGenerator::CalcCondition(
  const std::string& config) const
{
  std::ostringstream oss;
  oss << "'$(Configuration)|$(Platform)'=='";
  oss << config << "|" << this->Platform;
  oss << "'";
  // handle special case for 32 bit C# targets
  if (this->ProjectType == csproj && this->Platform == "Win32") {
    oss << " Or ";
    oss << "'$(Configuration)|$(Platform)'=='";
    oss << config << "|x86";
    oss << "'";
  }
  return oss.str();
}

270
271
void cmVisualStudio10TargetGenerator::Elem::WritePlatformConfigTag(
  const char* tag, const std::string& cond, const std::string& content)
272
{
273
  Elem(*this, tag).Attribute("Condition", cond).Content(content);
274
275
}

276
std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString(
277
278
279
280
281
282
283
284
285
286
  const char* line)
{
  this->S.fill(' ');
  this->S.width(this->Indent * 2);
  // write an empty string to get the fill level indent to print
  this->S << "";
  this->S << line;
  return this->S;
}

287
288
289
290
291
#define VS10_CXX_DEFAULT_PROPS "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"
#define VS10_CXX_PROPS "$(VCTargetsPath)\\Microsoft.Cpp.props"
#define VS10_CXX_USER_PROPS                                                   \
  "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"
#define VS10_CXX_TARGETS "$(VCTargetsPath)\\Microsoft.Cpp.targets"
292

293
294
295
296
297
298
299
300
#define VS10_CSharp_DEFAULT_PROPS                                             \
  "$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props"
// This does not seem to exist by default, it's just provided for consistency
// in case users want to have default custom props for C# targets
#define VS10_CSharp_USER_PROPS                                                \
  "$(UserRootDir)\\Microsoft.CSharp.$(Platform).user.props"
#define VS10_CSharp_TARGETS "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"

301
302
303
304
305
#define VS10_CSharp_NETCF_TARGETS                                             \
  "$(MSBuildExtensionsPath)\\Microsoft\\$(TargetFrameworkIdentifier)\\"       \
  "$(TargetFrameworkTargetsVersion)\\Microsoft.$(TargetFrameworkIdentifier)"  \
  ".CSharp.targets"

306
void cmVisualStudio10TargetGenerator::Generate()
307
308
{
  // do not generate external ms projects
309
  if (this->GeneratorTarget->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
310
      this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) {
311
    return;
312
  }
313
314
  const std::string ProjectFileExtension =
    computeProjectFileExtension(this->GeneratorTarget);
315
  if (ProjectFileExtension == ".vcxproj") {
316
317
    this->ProjectType = vcxproj;
    this->Managed = false;
318
  } else if (ProjectFileExtension == ".csproj") {
319
320
321
322
323
    if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
      std::string message = "The C# target \"" +
        this->GeneratorTarget->GetName() +
        "\" is of type STATIC_LIBRARY. This is discouraged (and may be "
        "disabled in future). Make it a SHARED library instead.";
324
      this->Makefile->IssueMessage(MessageType::DEPRECATION_WARNING, message);
325
    }
326
327
328
    this->ProjectType = csproj;
    this->Managed = true;
  }
329
  // Tell the global generator the name of the project file
330
331
  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
                                             this->Name.c_str());
332
333
  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
                                             ProjectFileExtension.c_str());
334
335
  this->DotNetHintReferences.clear();
  this->AdditionalUsingDirectories.clear();
336
  if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
337
    if (!this->ComputeClOptions()) {
338
      return;
339
340
    }
    if (!this->ComputeRcOptions()) {
341
      return;
342
    }
343
344
345
    if (!this->ComputeCudaOptions()) {
      return;
    }
346
347
348
    if (!this->ComputeCudaLinkOptions()) {
      return;
    }
349
    if (!this->ComputeMasmOptions()) {
350
      return;
351
    }
352
353
354
    if (!this->ComputeNasmOptions()) {
      return;
    }
355
    if (!this->ComputeLinkOptions()) {
356
      return;
357
    }
358
359
360
    if (!this->ComputeLibOptions()) {
      return;
    }
361
362
  }
  std::string path = this->LocalGenerator->GetCurrentBinaryDirectory();
363
  path += "/";
364
  path += this->Name;
365
  path += ProjectFileExtension;
366
  cmGeneratedFileStream BuildFileStream(path);
367
368
  const std::string PathToProjectFile = path;
  BuildFileStream.SetCopyIfDifferent(true);
369

370
  // Write the encoding header into the file
371
  char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
372
373
374
375
376
  BuildFileStream.write(magic, 3);
  BuildFileStream << "<?xml version=\"1.0\" encoding=\""
                  << this->GlobalGenerator->Encoding() << "\"?>"
                  << "\n";
  {
377
    Elem e0(BuildFileStream, "Project");
378
    e0.Attribute("DefaultTargets", "Build");
379
380
381
382
383
384
385
    const char* toolsVersion = this->GlobalGenerator->GetToolsVersion();
    if (this->GlobalGenerator->GetVersion() ==
          cmGlobalVisualStudioGenerator::VS12 &&
        this->GlobalGenerator->TargetsWindowsCE()) {
      toolsVersion = "4.0";
    }
    e0.Attribute("ToolsVersion", toolsVersion);
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    e0.Attribute("xmlns",
                 "http://schemas.microsoft.com/developer/msbuild/2003");

    if (this->NsightTegra) {
      Elem e1(e0, "PropertyGroup");
      e1.Attribute("Label", "NsightTegraProject");
      const unsigned int nsightTegraMajorVersion = this->NsightTegraVersion[0];
      const unsigned int nsightTegraMinorVersion = this->NsightTegraVersion[1];
      if (nsightTegraMajorVersion >= 2) {
        if (nsightTegraMajorVersion > 3 ||
            (nsightTegraMajorVersion == 3 && nsightTegraMinorVersion >= 1)) {
          e1.Element("NsightTegraProjectRevisionNumber", "11");
        } else {
          // Nsight Tegra 2.0 uses project revision 9.
          e1.Element("NsightTegraProjectRevisionNumber", "9");
        }
        // Tell newer versions to upgrade silently when loading.
        e1.Element("NsightTegraUpgradeOnceWithoutPrompt", "true");
404
      } else {
405
406
        // Require Nsight Tegra 1.6 for JCompile support.
        e1.Element("NsightTegraProjectRevisionNumber", "7");
407
      }
408
409
    }

410
411
412
413
414
    if (const char* hostArch =
          this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) {
      Elem e1(e0, "PropertyGroup");
      e1.Element("PreferredToolArchitecture", hostArch);
    }
415

416
417
418
    if (this->ProjectType != csproj) {
      this->WriteProjectConfigurations(e0);
    }
419

420
421
422
423
    {
      Elem e1(e0, "PropertyGroup");
      e1.Attribute("Label", "Globals");
      e1.Element("ProjectGuid", "{" + this->GUID + "}");
424

425
426
427
428
429
      if (this->MSTools &&
          this->GeneratorTarget->GetType() <= cmStateEnums::GLOBAL_TARGET) {
        this->WriteApplicationTypeSettings(e1);
        this->VerifyNecessaryFiles();
      }
430

431
432
433
434
435
436
437
438
      const char* vsProjectTypes =
        this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
      if (vsProjectTypes) {
        const char* tagName = "ProjectTypes";
        if (this->ProjectType == csproj) {
          tagName = "ProjectTypeGuids";
        }
        e1.Element(tagName, vsProjectTypes);
439
      }
440

441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
      const char* vsProjectName =
        this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
      const char* vsLocalPath =
        this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH");
      const char* vsProvider =
        this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER");

      if (vsProjectName && vsLocalPath && vsProvider) {
        e1.Element("SccProjectName", vsProjectName);
        e1.Element("SccLocalPath", vsLocalPath);
        e1.Element("SccProvider", vsProvider);

        const char* vsAuxPath =
          this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH");
        if (vsAuxPath) {
          e1.Element("SccAuxPath", vsAuxPath);
        }
458
      }
Steven Velez's avatar
Steven Velez committed
459

460
461
462
      if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
        e1.Element("WinMDAssembly", "true");
      }
463

464
465
466
467
468
469
470
      const char* vsGlobalKeyword =
        this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
      if (!vsGlobalKeyword) {
        e1.Element("Keyword", "Win32Proj");
      } else {
        e1.Element("Keyword", vsGlobalKeyword);
      }
471

472
473
474
475
476
      const char* vsGlobalRootNamespace =
        this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
      if (vsGlobalRootNamespace) {
        e1.Element("RootNamespace", vsGlobalRootNamespace);
      }
477

478
479
480
481
482
      e1.Element("Platform", this->Platform);
      const char* projLabel =
        this->GeneratorTarget->GetProperty("PROJECT_LABEL");
      if (!projLabel) {
        projLabel = this->Name.c_str();
483
      }
484
485
486
487
488
489
490
491
492
493
      e1.Element("ProjectName", projLabel);
      {
        // TODO: add deprecation warning for VS_* property?
        const char* targetFrameworkVersion =
          this->GeneratorTarget->GetProperty(
            "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
        if (!targetFrameworkVersion) {
          targetFrameworkVersion = this->GeneratorTarget->GetProperty(
            "DOTNET_TARGET_FRAMEWORK_VERSION");
        }
494
495
496
497
498
499
500
        if (!targetFrameworkVersion && this->ProjectType == csproj &&
            this->GlobalGenerator->TargetsWindowsCE() &&
            this->GlobalGenerator->GetVersion() ==
              cmGlobalVisualStudioGenerator::VS12) {
          // VS12 .NETCF default to .NET framework 3.9
          targetFrameworkVersion = "v3.9";
        }
501
502
503
        if (targetFrameworkVersion) {
          e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
        }
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
        if (this->ProjectType == csproj &&
            this->GlobalGenerator->TargetsWindowsCE()) {
          const char* targetFrameworkId = this->GeneratorTarget->GetProperty(
            "VS_TARGET_FRAMEWORK_IDENTIFIER");
          if (!targetFrameworkId) {
            targetFrameworkId = "WindowsEmbeddedCompact";
          }
          e1.Element("TargetFrameworkIdentifier", targetFrameworkId);
          const char* targetFrameworkVer = this->GeneratorTarget->GetProperty(
            "VS_TARGET_FRAMEWORKS_TARGET_VERSION");
          if (!targetFrameworkVer) {
            targetFrameworkVer = "v8.0";
          }
          e1.Element("TargetFrameworkTargetsVersion", targetFrameworkVer);
        }
519
      }
520

521
522
523
524
525
526
527
      // Disable the project upgrade prompt that is displayed the first time a
      // project using an older toolset version is opened in a newer version of
      // the IDE (respected by VS 2013 and above).
      if (this->GlobalGenerator->GetVersion() >=
          cmGlobalVisualStudioGenerator::VS12) {
        e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
      }
528

529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
      std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
      for (std::string const& keyIt : keys) {
        static const char* prefix = "VS_GLOBAL_";
        if (keyIt.find(prefix) != 0)
          continue;
        std::string globalKey = keyIt.substr(strlen(prefix));
        // Skip invalid or separately-handled properties.
        if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
            globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
          continue;
        }
        const char* value = this->GeneratorTarget->GetProperty(keyIt);
        if (!value)
          continue;
        e1.Element(globalKey.c_str(), value);
544
      }
545

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
      if (this->Managed) {
        std::string outputType;
        switch (this->GeneratorTarget->GetType()) {
          case cmStateEnums::OBJECT_LIBRARY:
          case cmStateEnums::STATIC_LIBRARY:
          case cmStateEnums::SHARED_LIBRARY:
            outputType = "Library";
            break;
          case cmStateEnums::MODULE_LIBRARY:
            outputType = "Module";
            break;
          case cmStateEnums::EXECUTABLE:
            if (this->GeneratorTarget->Target->GetPropertyAsBool(
                  "WIN32_EXECUTABLE")) {
              outputType = "WinExe";
            } else {
              outputType = "Exe";
            }
            break;
          case cmStateEnums::UTILITY:
          case cmStateEnums::GLOBAL_TARGET:
            outputType = "Utility";
            break;
          case cmStateEnums::UNKNOWN_LIBRARY:
          case cmStateEnums::INTERFACE_LIBRARY:
            break;
        }
        e1.Element("OutputType", outputType);
        e1.Element("AppDesignerFolder", "Properties");
575
      }
576
    }
577

578
579
    switch (this->ProjectType) {
      case vcxproj:
580
581
582
583
584
        if (this->GlobalGenerator->GetPlatformToolsetVersion()) {
          Elem(e0, "Import")
            .Attribute("Project",
                       this->GlobalGenerator->GetAuxiliaryToolset());
        }
585
        Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS);
586
587
588
589
        break;
      case csproj:
        Elem(e0, "Import")
          .Attribute("Project", VS10_CSharp_DEFAULT_PROPS)
590
          .Attribute("Condition", "Exists('" VS10_CSharp_DEFAULT_PROPS "')");
591
592
        break;
    }
593

594
    this->WriteProjectConfigurationValues(e0);
595

596
    if (this->ProjectType == vcxproj) {
597
      Elem(e0, "Import").Attribute("Project", VS10_CXX_PROPS);
598
    }
599
600
601
602
603
604
605
    {
      Elem e1(e0, "ImportGroup");
      e1.Attribute("Label", "ExtensionSettings");
      e1.SetHasElements();

      if (this->GlobalGenerator->IsCudaEnabled()) {
        Elem(e1, "Import")
606
607
608
609
          .Attribute("Project",
                     "$(VCTargetsPath)\\BuildCustomizations\\CUDA " +
                       this->GlobalGenerator->GetPlatformToolsetCudaString() +
                       ".props");
610
611
612
613
      }
      if (this->GlobalGenerator->IsMasmEnabled()) {
        Elem(e1, "Import")
          .Attribute("Project",
614
                     "$(VCTargetsPath)\\BuildCustomizations\\masm.props");
615
616
617
618
619
620
621
622
623
624
625
626
      }
      if (this->GlobalGenerator->IsNasmEnabled()) {
        // Always search in the standard modules location.
        std::string propsTemplate =
          GetCMakeFilePath("Templates/MSBuild/nasm.props.in");

        std::string propsLocal;
        propsLocal += this->DefaultArtifactDir;
        propsLocal += "\\nasm.props";
        ConvertToWindowsSlash(propsLocal);
        this->Makefile->ConfigureFile(propsTemplate.c_str(),
                                      propsLocal.c_str(), false, true, true);
627
        Elem(e1, "Import").Attribute("Project", propsLocal);
628
      }
629
    }
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
    {
      Elem e1(e0, "ImportGroup");
      e1.Attribute("Label", "PropertySheets");
      std::string props;
      switch (this->ProjectType) {
        case vcxproj:
          props = VS10_CXX_USER_PROPS;
          break;
        case csproj:
          props = VS10_CSharp_USER_PROPS;
          break;
      }
      if (const char* p =
            this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
        props = p;
      }
      if (!props.empty()) {
        ConvertToWindowsSlash(props);
        Elem(e1, "Import")
          .Attribute("Project", props)
          .Attribute("Condition", "exists('" + props + "')")
651
          .Attribute("Label", "LocalAppDataPlatform");
652
653
654
      }

      this->WritePlatformExtensions(e1);
655
    }
656
    Elem(e0, "PropertyGroup").Attribute("Label", "UserMacros");
657
658
    this->WriteWinRTPackageCertificateKeyFile(e0);
    this->WritePathAndIncrementalLinkOptions(e0);
659
    this->WriteCEDebugProjectConfigurationValues(e0);
660
661
662
663
664
665
666
667
668
    this->WriteItemDefinitionGroups(e0);
    this->WriteCustomCommands(e0);
    this->WriteAllSources(e0);
    this->WriteDotNetReferences(e0);
    this->WriteEmbeddedResourceGroup(e0);
    this->WriteXamlFilesGroup(e0);
    this->WriteWinRTReferences(e0);
    this->WriteProjectReferences(e0);
    this->WriteSDKReferences(e0);
669
670
    switch (this->ProjectType) {
      case vcxproj:
671
        Elem(e0, "Import").Attribute("Project", VS10_CXX_TARGETS);
672
673
        break;
      case csproj:
674
675
676
677
678
        if (this->GlobalGenerator->TargetsWindowsCE()) {
          Elem(e0, "Import").Attribute("Project", VS10_CSharp_NETCF_TARGETS);
        } else {
          Elem(e0, "Import").Attribute("Project", VS10_CSharp_TARGETS);
        }
679
680
        break;
    }
681

682
683
684
685
    this->WriteTargetSpecificReferences(e0);
    {
      Elem e1(e0, "ImportGroup");
      e1.Attribute("Label", "ExtensionTargets");
686
      e1.SetHasElements();
687
688
689
690
691
692
      this->WriteTargetsFileReferences(e1);
      if (this->GlobalGenerator->IsCudaEnabled()) {
        Elem(e1, "Import")
          .Attribute("Project",
                     "$(VCTargetsPath)\\BuildCustomizations\\CUDA " +
                       this->GlobalGenerator->GetPlatformToolsetCudaString() +
693
                       ".targets");
694
695
696
697
      }
      if (this->GlobalGenerator->IsMasmEnabled()) {
        Elem(e1, "Import")
          .Attribute("Project",
698
                     "$(VCTargetsPath)\\BuildCustomizations\\masm.targets");
699
700
701
702
      }
      if (this->GlobalGenerator->IsNasmEnabled()) {
        std::string nasmTargets =
          GetCMakeFilePath("Templates/MSBuild/nasm.targets");
703
        Elem(e1, "Import").Attribute("Project", nasmTargets);
704
      }
705
    }
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
    if (this->ProjectType == csproj) {
      for (std::string const& c : this->Configurations) {
        Elem e1(e0, "PropertyGroup");
        e1.Attribute("Condition", "'$(Configuration)' == '" + c + "'");
        e1.SetHasElements();
        this->WriteEvents(e1, c);
      }
      // make sure custom commands are executed before build (if necessary)
      {
        Elem e1(e0, "PropertyGroup");
        std::ostringstream oss;
        oss << "\n";
        for (std::string const& i : this->CSharpCustomCommandNames) {
          oss << "      " << i << ";\n";
        }
        oss << "      "
            << "$(BuildDependsOn)\n";
        e1.Element("BuildDependsOn", oss.str());
724
      }
725
    }
726
727
728
729
  }

  if (BuildFileStream.Close()) {
    this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile);
730
  }
731

732
733
734
735
  // The groups are stored in a separate file for VS 10
  this->WriteGroups();
}

736
void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
737
{
738
  std::vector<std::string> references;
739
740
  if (const char* vsDotNetReferences =
        this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) {
741
    cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
742
  }
743
  cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
744
745
746
  for (auto const& i : props) {
    if (i.first.find("VS_DOTNET_REFERENCE_") == 0) {
      std::string name = i.first.substr(20);
747
      if (!name.empty()) {
748
        std::string path = i.second.GetValue();
749
        if (!cmsys::SystemTools::FileIsFullPath(path)) {
750
          path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
751
        }
752
        ConvertToWindowsSlash(path);
753
754
        this->DotNetHintReferences[""].push_back(
          DotNetHintReference(name, path));
755
756
757
      }
    }
  }
758
  if (!references.empty() || !this->DotNetHintReferences.empty()) {
759
    Elem e1(e0, "ItemGroup");
760
    for (std::string const& ri : references) {
761
762
      // if the entry from VS_DOTNET_REFERENCES is an existing file, generate
      // a new hint-reference and name it from the filename
763
      if (cmsys::SystemTools::FileExists(ri, true)) {
764
765
        std::string name =
          cmsys::SystemTools::GetFilenameWithoutLastExtension(ri);
766
        std::string path = ri;
767
        ConvertToWindowsSlash(path);
768
769
        this->DotNetHintReferences[""].push_back(
          DotNetHintReference(name, path));
770
      } else {
771
        this->WriteDotNetReference(e1, ri, "", "");
772
773
      }
    }
774
775
776
777
    for (const auto& h : this->DotNetHintReferences) {
      // DotNetHintReferences is also populated from AddLibraries().
      // The configuration specific hint references are added there.
      for (const auto& i : h.second) {
778
        this->WriteDotNetReference(e1, i.first, i.second, h.first);
779
      }
780
    }
781
  }
782
783
}

784
void cmVisualStudio10TargetGenerator::WriteDotNetReference(
785
786
  Elem& e1, std::string const& ref, std::string const& hint,
  std::string const& config)
787
{
788
  Elem e2(e1, "Reference");
789
790
791
792
  // If 'config' is not empty, the reference is only added for the given
  // configuration. This is used when referencing imported managed assemblies.
  // See also cmVisualStudio10TargetGenerator::AddLibraries().
  if (!config.empty()) {
793
    e2.Attribute("Condition", this->CalcCondition(config));
794
  }
795
796
797
  e2.Attribute("Include", ref);
  e2.Element("CopyLocalSatelliteAssemblies", "true");
  e2.Element("ReferenceOutputAssembly", "true");
798
799
800
801
802
803
804
805
  if (!hint.empty()) {
    const char* privateReference = "True";
    if (const char* value = this->GeneratorTarget->GetProperty(
          "VS_DOTNET_REFERENCES_COPY_LOCAL")) {
      if (cmSystemTools::IsOff(value)) {
        privateReference = "False";
      }
    }
806
807
    e2.Element("Private", privateReference);
    e2.Element("HintPath", hint);
808
  }
809
  this->WriteDotNetReferenceCustomTags(e2, ref);
810
811
}

812
void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags(
813
  Elem& e2, std::string const& ref)
814
815
816
817
818
819
820
821
{

  static const std::string refpropPrefix = "VS_DOTNET_REFERENCEPROP_";
  static const std::string refpropInfix = "_TAG_";
  const std::string refPropFullPrefix = refpropPrefix + ref + refpropInfix;
  typedef std::map<std::string, std::string> CustomTags;
  CustomTags tags;
  cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
822
823
824
825
  for (const auto& i : props) {
    if (i.first.find(refPropFullPrefix) == 0) {
      std::string refTag = i.first.substr(refPropFullPrefix.length());
      std::string refVal = i.second.GetValue();
826
827
828
829
830
      if (!refTag.empty() && !refVal.empty()) {
        tags[refTag] = refVal;
      }
    }
  }
831
  for (auto const& tag : tags) {
832
    e2.Element(tag.first.c_str(), tag.second);
833
834
835
  }
}

836
void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
837
{
838
  std::vector<cmSourceFile const*> resxObjs;
839
840
  this->GeneratorTarget->GetResxSources(resxObjs, "");
  if (!resxObjs.empty()) {
841
    Elem e1(e0, "ItemGroup");
842
    std::string srcDir = this->Makefile->GetCurrentSourceDirectory();
843
    ConvertToWindowsSlash(srcDir);
844
845
    for (cmSourceFile const* oi : resxObjs) {
      std::string obj = oi->GetFullPath();
846
      ConvertToWindowsSlash(obj);
847
      bool useRelativePath = false;
848
      if (this->ProjectType == csproj && this->InSourceBuild) {
849
850
851
852
853
854
        // If we do an in-source build and the resource file is in a
        // subdirectory
        // of the .csproj file, we have to use relative pathnames, otherwise
        // visual studio does not show the file in the IDE. Sorry.
        if (obj.find(srcDir) == 0) {
          obj = this->ConvertPath(obj, true);
855
          ConvertToWindowsSlash(obj);
856
857
858
          useRelativePath = true;
        }
      }
859
860
      Elem e2(e1, "EmbeddedResource");
      e2.Attribute("Include", obj);
861

862
      if (this->ProjectType != csproj) {
863
        std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
864
        e2.Element("DependentUpon", hFileName);
865

866
        for (std::string const& c : this->Configurations) {
867
          std::string s;
868
869
870
          if (this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE") ||
              // Handle variant of VS_GLOBAL_<variable> for RootNamespace.
              this->GeneratorTarget->GetProperty("VS_GLOBAL_RootNamespace")) {
871
            s = "$(RootNamespace).";
872
          }
873
          s += "%(Filename).resources";
874
          e2.WritePlatformConfigTag("LogicalName", this->CalcCondition(c), s);
875
876
877
        }
      } else {
        std::string binDir = this->Makefile->GetCurrentBinaryDirectory();
878
        ConvertToWindowsSlash(binDir);
879
880
881
882
883
884
885
886
887
888
889
890
        // If the resource was NOT added using a relative path (which should
        // be the default), we have to provide a link here
        if (!useRelativePath) {
          std::string link;
          if (obj.find(srcDir) == 0) {
            link = obj.substr(srcDir.length() + 1);
          } else if (obj.find(binDir) == 0) {
            link = obj.substr(binDir.length() + 1);
          } else {
            link = cmsys::SystemTools::GetFilenameName(obj);
          }
          if (!link.empty()) {
891
            e2.Element("Link", link);
892
893
894
895
          }
        }
        // Determine if this is a generated resource from a .Designer.cs file
        std::string designerResource =
896
897
          cmSystemTools::GetFilenamePath(oi->GetFullPath()) + "/" +
          cmSystemTools::GetFilenameWithoutLastExtension(oi->GetFullPath()) +
898
899
900
          ".Designer.cs";
        if (cmsys::SystemTools::FileExists(designerResource)) {
          std::string generator = "PublicResXFileCodeGenerator";
901
          if (const char* g = oi->GetProperty("VS_RESOURCE_GENERATOR")) {
902
903
            generator = g;
          }
904
          if (!generator.empty()) {
905
            e2.Element("Generator", generator);
906
907
908
909
910
911
912
913
            if (designerResource.find(srcDir) == 0) {
              designerResource = designerResource.substr(srcDir.length() + 1);
            } else if (designerResource.find(binDir) == 0) {
              designerResource = designerResource.substr(binDir.length() + 1);
            } else {
              designerResource =
                cmsys::SystemTools::GetFilenameName(designerResource);
            }
914
            ConvertToWindowsSlash(designerResource);
915
            e2.Element("LastGenOutput", designerResource);
916
917
          }
        }
918
919
        const cmPropertyMap& props = oi->GetProperties();
        for (const auto& p : props) {
920
          static const std::string propNamePrefix = "VS_CSHARP_";
921
922
          if (p.first.find(propNamePrefix) == 0) {
            std::string tagName = p.first.substr(propNamePrefix.length());
923
            if (!tagName.empty()) {
924
              std::string value = props.GetPropertyValue(p.first);
925
              if (!value.empty()) {
926
                e2.Element(tagName.c_str(), value);
927
928
              }
            }
929
          }
930
        }
931
      }
932
    }
933
  }
934
935
}

936
void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0)
937
938
939
{
  std::vector<cmSourceFile const*> xamlObjs;
  this->GeneratorTarget->GetXamlSources(xamlObjs, "");
940
  if (!xamlObjs.empty()) {
941
    Elem e1(e0, "ItemGroup");
942
943
    for (cmSourceFile const* oi : xamlObjs) {
      std::string obj = oi->GetFullPath();
944
      const char* xamlType;
945
      const char* xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE");
946
      if (xamlTypeProperty) {
947
        xamlType = xamlTypeProperty;
948
      } else {
949
        xamlType = "Page";
950
      }
951

952
953
      Elem e2(e1, xamlType);
      this->WriteSource(e2, oi);
954
      e2.SetHasElements();
955
      if (this->ProjectType == csproj && !this->InSourceBuild) {
956
        // add <Link> tag to written XAML source if necessary
957
958
959
960
        const std::string& srcDir =
          this->Makefile->GetCurrentSourceDirectory();
        const std::string& binDir =
          this->Makefile->GetCurrentBinaryDirectory();
961
962
963
964
965
966
967
968
969
        std::string link;
        if (obj.find(srcDir) == 0) {
          link = obj.substr(srcDir.length() + 1);
        } else if (obj.find(binDir) == 0) {
          link = obj.substr(binDir.length() + 1);
        } else {
          link = cmsys::SystemTools::GetFilenameName(obj);
        }
        if (!link.empty()) {
970
          ConvertToWindowsSlash(link);
971
          e2.Element("Link", link);
972
973
        }
      }
974
      e2.Element("SubType", "Designer");
975
    }
976
  }
977
978
}

979
void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences(Elem& e0)
980
{
981
982
983
  if (this->MSTools) {
    if (this->GlobalGenerator->TargetsWindowsPhone() &&
        this->GlobalGenerator->GetSystemVersion() == "8.0") {
984
985
986
987
      Elem(e0, "Import")
        .Attribute("Project",
                   "$(MSBuildExtensionsPath)\\Microsoft\\WindowsPhone\\v"
                   "$(TargetPlatformVersion)\\Microsoft.Cpp.WindowsPhone."
988
                   "$(TargetPlatformVersion).targets");
989
    }
990
  }
991
992
}

993
void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences(Elem& e1)
994
{
995
  for (TargetsFileAndConfigs const& tac : this->TargetsFileAndConfigsVec) {
996
997
    std::ostringstream oss;
    oss << "Exists('" << tac.File << "')";
998
    if (!tac.Configs.empty()) {