cmVisualStudio10TargetGenerator.cxx 168 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
10
11
#include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio10Generator.h"
#include "cmLocalVisualStudio7Generator.h"
12
13
#include "cmMakefile.h"
#include "cmSourceFile.h"
14
#include "cmSystemTools.h"
15
16
#include "cmVisualStudioGeneratorOptions.h"
#include "windows.h"
17

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

21
22
static void ConvertToWindowsSlash(std::string& s);

23
24
25
26
27
28
29
static std::string cmVS10EscapeXML(std::string arg)
{
  cmSystemTools::ReplaceString(arg, "&", "&amp;");
  cmSystemTools::ReplaceString(arg, "<", "&lt;");
  cmSystemTools::ReplaceString(arg, ">", "&gt;");
  return arg;
}
30

31
32
33
34
35
36
static std::string cmVS10EscapeQuotes(std::string arg)
{
  cmSystemTools::ReplaceString(arg, "\"", "&quot;");
  return arg;
}

37
38
39
40
41
42
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;
43
44
  for (char c : comment) {
    switch (c) {
45
46
47
48
49
      case '\r':
        break;
      case '\n':
        echoable += '\t';
        break;
50
51
52
53
54
      case '"': /* no break */
      case '|': /* no break */
      case '&': /* no break */
      case '<': /* no break */
      case '>': /* no break */
55
56
      case '^':
        echoable += '^'; /* no break */
57
        CM_FALLTHROUGH;
58
      default:
59
        echoable += c;
60
        break;
61
    }
62
  }
63
64
65
  return echoable;
}

66
67
68
69
70
71
static bool cmVS10IsTargetsFile(std::string const& path)
{
  std::string const ext = cmSystemTools::GetFilenameLastExtension(path);
  return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
}

72
73
static std::string computeProjectFileExtension(cmGeneratorTarget const* t,
                                               const std::string& config)
74
75
76
{
  std::string res;
  res = ".vcxproj";
77
78
79
  std::string lang = t->GetLinkerLanguage(config);
  if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t) ||
      lang == "CSharp") {
80
81
82
83
84
    res = ".csproj";
  }
  return res;
}

85
86
cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
  cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
87
88
{
  this->GlobalGenerator = gg;
89
90
  this->GeneratorTarget = target;
  this->Makefile = target->Target->GetMakefile();
91
  this->Makefile->GetConfigurations(this->Configurations);
92
  this->LocalGenerator =
93
    (cmLocalVisualStudio7Generator*)this->GeneratorTarget->GetLocalGenerator();
94
  this->Name = this->GeneratorTarget->GetName();
95
  this->GUID = this->GlobalGenerator->GetGUID(this->Name);
96
97
98
99
100
101
102
103
104
105

  // overwrite the PLATFORM if required - Only for Managed code
  const char* vsdotnetplatform =
    this->GeneratorTarget->GetProperty("VS_DOTNET_PLATFORM");
  if (this->Managed && vsdotnetplatform) {
    this->Platform = vsdotnetplatform;
  } else {
    this->Platform = gg->GetPlatformName();
  }

106
  this->NsightTegra = gg->IsNsightTegra();
107
  for (int i = 0; i < 4; ++i) {
108
    this->NsightTegraVersion[i] = 0;
109
  }
110
111
112
  sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u",
         &this->NsightTegraVersion[0], &this->NsightTegraVersion[1],
         &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]);
113
  this->MSTools = !this->NsightTegra;
114
  this->Managed = false;
115
  this->TargetCompileAsWinRT = false;
116
  this->BuildFileStream = 0;
117
118
  this->IsMissingFiles = false;
  this->DefaultArtifactDir =
119
    this->LocalGenerator->GetCurrentBinaryDirectory() + std::string("/") +
120
    this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
121
122
123
  this->InSourceBuild =
    (strcmp(this->Makefile->GetCurrentSourceDirectory(),
            this->Makefile->GetCurrentBinaryDirectory()) == 0);
124
125
126
127
}

cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
{
128
  if (!this->BuildFileStream) {
129
    return;
130
131
  }
  if (this->BuildFileStream->Close()) {
132
    this->GlobalGenerator->FileReplacedDuringGenerate(this->PathToProjectFile);
133
  }
134
135
136
137
  delete this->BuildFileStream;
}

void cmVisualStudio10TargetGenerator::WritePlatformConfigTag(
138
139
  const char* tag, const std::string& config, int indentLevel,
  const char* attribute, const char* end, std::ostream* stream)
140
141

{
142
  if (!stream) {
143
    stream = this->BuildFileStream;
144
  }
145
  stream->fill(' ');
146
  stream->width(indentLevel * 2);
Brad King's avatar
Brad King committed
147
  (*stream) << ""; // applies indentation
148
149
150
151
152
  (*stream) << "<" << tag << " Condition=\"";
  (*stream) << "'$(Configuration)|$(Platform)'=='";
  (*stream) << config << "|" << this->Platform;
  (*stream) << "'";
  // handle special case for 32 bit C# targets
153
  if (this->ProjectType == csproj && this->Platform == "Win32") {
154
155
156
157
158
159
    (*stream) << " Or ";
    (*stream) << "'$(Configuration)|$(Platform)'=='";
    (*stream) << config << "|x86";
    (*stream) << "'";
  }
  (*stream) << "\"";
160
161
162
  if (attribute) {
    (*stream) << attribute;
  }
163
  // close the tag
164
165
166
167
  (*stream) << ">";
  if (end) {
    (*stream) << end;
  }
168
169
170
171
172
173
}

void cmVisualStudio10TargetGenerator::WriteString(const char* line,
                                                  int indentLevel)
{
  this->BuildFileStream->fill(' ');
174
  this->BuildFileStream->width(indentLevel * 2);
175
  // write an empty string to get the fill level indent to print
176
177
  (*this->BuildFileStream) << "";
  (*this->BuildFileStream) << line;
178
179
}

180
181
182
183
184
#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"
185

186
187
188
189
190
191
192
193
#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"

194
void cmVisualStudio10TargetGenerator::Generate()
195
196
{
  // do not generate external ms projects
197
  if (this->GeneratorTarget->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
198
      this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) {
199
    return;
200
  }
201
202
  this->ProjectFileExtension = computeProjectFileExtension(
    this->GeneratorTarget, *this->Configurations.begin());
203
204
205
206
207
208
209
  if (this->ProjectFileExtension == ".vcxproj") {
    this->ProjectType = vcxproj;
    this->Managed = false;
  } else if (this->ProjectFileExtension == ".csproj") {
    this->ProjectType = csproj;
    this->Managed = true;
  }
210
  // Tell the global generator the name of the project file
211
212
  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
                                             this->Name.c_str());
213
214
  this->GeneratorTarget->Target->SetProperty(
    "GENERATOR_FILE_NAME_EXT", this->ProjectFileExtension.c_str());
215
  if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
216
    if (!this->ComputeClOptions()) {
217
      return;
218
219
    }
    if (!this->ComputeRcOptions()) {
220
      return;
221
    }
222
223
224
    if (!this->ComputeCudaOptions()) {
      return;
    }
225
226
227
    if (!this->ComputeCudaLinkOptions()) {
      return;
    }
228
    if (!this->ComputeMasmOptions()) {
229
      return;
230
    }
231
232
233
    if (!this->ComputeNasmOptions()) {
      return;
    }
234
    if (!this->ComputeLinkOptions()) {
235
      return;
236
    }
237
238
239
    if (!this->ComputeLibOptions()) {
      return;
    }
240
241
  }
  std::string path = this->LocalGenerator->GetCurrentBinaryDirectory();
242
  path += "/";
243
  path += this->Name;
244
  path += this->ProjectFileExtension;
245
  this->BuildFileStream = new cmGeneratedFileStream(path.c_str());
246
  this->PathToProjectFile = path;
247
  this->BuildFileStream->SetCopyIfDifferent(true);
248

249
  // Write the encoding header into the file
250
  char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
251
  this->BuildFileStream->write(magic, 3);
252

253
  // get the tools version to use
254
  const std::string toolsVer(this->GlobalGenerator->GetToolsVersion());
255
  std::string project_defaults = "<?xml version=\"1.0\" encoding=\"" +
256
    this->GlobalGenerator->Encoding() + "\"?>\n";
257
  project_defaults.append("<Project DefaultTargets=\"Build\" ToolsVersion=\"");
258
  project_defaults.append(toolsVer + "\" ");
259
  project_defaults.append(
260
261
    "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
  this->WriteString(project_defaults.c_str(), 0);
262

263
  if (this->NsightTegra) {
264
    this->WriteString("<PropertyGroup Label=\"NsightTegraProject\">\n", 1);
265
266
    const int nsightTegraMajorVersion = this->NsightTegraVersion[0];
    const int nsightTegraMinorVersion = this->NsightTegraVersion[1];
267
    if (nsightTegraMajorVersion >= 2) {
268
269
      this->WriteString("<NsightTegraProjectRevisionNumber>", 2);
      if (nsightTegraMajorVersion > 3 ||
270
          (nsightTegraMajorVersion == 3 && nsightTegraMinorVersion >= 1)) {
271
        (*this->BuildFileStream) << "11";
272
      } else {
273
274
        // Nsight Tegra 2.0 uses project revision 9.
        (*this->BuildFileStream) << "9";
275
      }
276
      (*this->BuildFileStream) << "</NsightTegraProjectRevisionNumber>\n";
277
278
279
      // Tell newer versions to upgrade silently when loading.
      this->WriteString("<NsightTegraUpgradeOnceWithoutPrompt>"
                        "true"
280
281
282
                        "</NsightTegraUpgradeOnceWithoutPrompt>\n",
                        2);
    } else {
283
284
285
      // Require Nsight Tegra 1.6 for JCompile support.
      this->WriteString("<NsightTegraProjectRevisionNumber>"
                        "7"
286
287
                        "</NsightTegraProjectRevisionNumber>\n",
                        2);
288
    }
289
290
    this->WriteString("</PropertyGroup>\n", 1);
  }
291

292
293
294
295
296
297
298
299
300
  if (const char* hostArch =
        this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) {
    this->WriteString("<PropertyGroup>\n", 1);
    this->WriteString("<PreferredToolArchitecture>", 2);
    (*this->BuildFileStream) << cmVS10EscapeXML(hostArch)
                             << "</PreferredToolArchitecture>\n";
    this->WriteString("</PropertyGroup>\n", 1);
  }

301
  if (this->ProjectType != csproj) {
302
303
    this->WriteProjectConfigurations();
  }
304
  this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
305
306
  this->WriteString("<ProjectGuid>", 2);
  (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGuid>\n";
307

308
  if (this->MSTools &&
309
      this->GeneratorTarget->GetType() <= cmStateEnums::GLOBAL_TARGET) {
310
    this->WriteApplicationTypeSettings();
311
    this->VerifyNecessaryFiles();
312
  }
313

314
  const char* vsProjectTypes =
315
    this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
316
  if (vsProjectTypes) {
317
    std::string tagName = "ProjectTypes";
318
    if (this->ProjectType == csproj) {
319
320
321
322
323
324
      tagName = "ProjectTypeGuids";
    }
    this->WriteString("", 2);
    (*this->BuildFileStream) << "<" << tagName << ">"
                             << cmVS10EscapeXML(vsProjectTypes) << "</"
                             << tagName << ">\n";
325
  }
326

327
  const char* vsProjectName =
328
    this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
329
  const char* vsLocalPath =
330
    this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH");
331
  const char* vsProvider =
332
    this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER");
Steven Velez's avatar
Steven Velez committed
333

334
  if (vsProjectName && vsLocalPath && vsProvider) {
Steven Velez's avatar
Steven Velez committed
335
    this->WriteString("<SccProjectName>", 2);
336
337
    (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectName)
                             << "</SccProjectName>\n";
Steven Velez's avatar
Steven Velez committed
338
    this->WriteString("<SccLocalPath>", 2);
339
340
    (*this->BuildFileStream) << cmVS10EscapeXML(vsLocalPath)
                             << "</SccLocalPath>\n";
Steven Velez's avatar
Steven Velez committed
341
    this->WriteString("<SccProvider>", 2);
342
343
    (*this->BuildFileStream) << cmVS10EscapeXML(vsProvider)
                             << "</SccProvider>\n";
344

345
    const char* vsAuxPath =
346
347
      this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH");
    if (vsAuxPath) {
348
      this->WriteString("<SccAuxPath>", 2);
349
350
      (*this->BuildFileStream) << cmVS10EscapeXML(vsAuxPath)
                               << "</SccAuxPath>\n";
Steven Velez's avatar
Steven Velez committed
351
    }
352
  }
Steven Velez's avatar
Steven Velez committed
353

354
  if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
355
    this->WriteString("<WinMDAssembly>true</WinMDAssembly>\n", 2);
356
  }
357

358
  const char* vsGlobalKeyword =
359
    this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
360
  if (!vsGlobalKeyword) {
361
    this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2);
362
  } else {
363
    this->WriteString("<Keyword>", 2);
364
365
366
    (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalKeyword)
                             << "</Keyword>\n";
  }
367

368
  const char* vsGlobalRootNamespace =
369
    this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
370
  if (vsGlobalRootNamespace) {
371
    this->WriteString("<RootNamespace>", 2);
372
373
374
    (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalRootNamespace)
                             << "</RootNamespace>\n";
  }
375

Brad King's avatar
Brad King committed
376
  this->WriteString("<Platform>", 2);
377
378
  (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform)
                           << "</Platform>\n";
379
  const char* projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
380
  if (!projLabel) {
381
    projLabel = this->Name.c_str();
382
  }
383
  this->WriteString("<ProjectName>", 2);
384
  (*this->BuildFileStream) << cmVS10EscapeXML(projLabel) << "</ProjectName>\n";
385
386
  if (const char* targetFrameworkVersion = this->GeneratorTarget->GetProperty(
        "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
387
    this->WriteString("<TargetFrameworkVersion>", 2);
388
    (*this->BuildFileStream) << cmVS10EscapeXML(targetFrameworkVersion)
389
                             << "</TargetFrameworkVersion>\n";
390
  }
391

392
393
394
395
396
397
398
399
400
401
  // 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) {
    this->WriteString("<VCProjectUpgraderObjectName>NoUpgrade"
                      "</VCProjectUpgraderObjectName>\n",
                      2);
  }

402
  std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
403
  for (std::string const& keyIt : keys) {
404
    static const char* prefix = "VS_GLOBAL_";
405
    if (keyIt.find(prefix) != 0)
406
      continue;
407
    std::string globalKey = keyIt.substr(strlen(prefix));
408
    // Skip invalid or separately-handled properties.
409
    if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
410
        globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
411
      continue;
412
    }
413
    const char* value = this->GeneratorTarget->GetProperty(keyIt);
414
415
416
    if (!value)
      continue;
    this->WriteString("<", 2);
417
    (*this->BuildFileStream) << globalKey << ">" << cmVS10EscapeXML(value)
418
                             << "</" << globalKey << ">\n";
419
  }
420

421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
  if (this->Managed) {
    std::string outputType = "<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;
    }
    outputType += "</OutputType>\n";
    this->WriteString(outputType.c_str(), 2);
    this->WriteString("<AppDesignerFolder>Properties</AppDesignerFolder>\n",
                      2);
  }

454
  this->WriteString("</PropertyGroup>\n", 1);
455
456
457
458
459
460
461
462
463
464
465
466
467
468

  switch (this->ProjectType) {
    case vcxproj:
      this->WriteString("<Import Project=\"" VS10_CXX_DEFAULT_PROPS "\" />\n",
                        1);
      break;
    case csproj:
      this->WriteString("<Import Project=\"" VS10_CSharp_DEFAULT_PROPS "\" "
                        "Condition=\"Exists('" VS10_CSharp_DEFAULT_PROPS "')\""
                        "/>\n",
                        1);
      break;
  }

469
  this->WriteProjectConfigurationValues();
470

471
  if (this->ProjectType == vcxproj) {
472
473
    this->WriteString("<Import Project=\"" VS10_CXX_PROPS "\" />\n", 1);
  }
474
  this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1);
475
476
477
478
479
480
481
482
  if (this->GlobalGenerator->IsCudaEnabled()) {
    this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
                      "BuildCustomizations\\CUDA ",
                      2);
    (*this->BuildFileStream)
      << cmVS10EscapeXML(this->GlobalGenerator->GetPlatformToolsetCudaString())
      << ".props\" />\n";
  }
483
  if (this->GlobalGenerator->IsMasmEnabled()) {
484
    this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
485
486
487
                      "BuildCustomizations\\masm.props\" />\n",
                      2);
  }
488
489
490
491
492
493
494
495
  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";
496
    ConvertToWindowsSlash(propsLocal);
497
498
499
500
501
502
    this->Makefile->ConfigureFile(propsTemplate.c_str(), propsLocal.c_str(),
                                  false, true, true);
    std::string import = std::string("<Import Project=\"") +
      cmVS10EscapeXML(propsLocal) + "\" />\n";
    this->WriteString(import.c_str(), 2);
  }
503
504
  this->WriteString("</ImportGroup>\n", 1);
  this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1);
505
  {
506
507
508
509
510
511
512
513
514
    std::string props;
    switch (this->ProjectType) {
      case vcxproj:
        props = VS10_CXX_USER_PROPS;
        break;
      case csproj:
        props = VS10_CSharp_USER_PROPS;
        break;
    }
515
    if (const char* p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) {
516
      props = p;
517
518
    }
    if (!props.empty()) {
519
      ConvertToWindowsSlash(props);
520
521
522
523
524
      this->WriteString("", 2);
      (*this->BuildFileStream)
        << "<Import Project=\"" << cmVS10EscapeXML(props) << "\""
        << " Condition=\"exists('" << cmVS10EscapeXML(props) << "')\""
        << " Label=\"LocalAppDataPlatform\" />\n";
525
526
    }
  }
527
  this->WritePlatformExtensions();
528
529
  this->WriteString("</ImportGroup>\n", 1);
  this->WriteString("<PropertyGroup Label=\"UserMacros\" />\n", 1);
530
  this->WriteWinRTPackageCertificateKeyFile();
531
532
533
  this->WritePathAndIncrementalLinkOptions();
  this->WriteItemDefinitionGroups();
  this->WriteCustomCommands();
534
  this->WriteAllSources();
535
  this->WriteDotNetReferences();
536
  this->WriteEmbeddedResourceGroup();
537
  this->WriteXamlFilesGroup();
538
  this->WriteWinRTReferences();
539
  this->WriteProjectReferences();
540
  this->WriteSDKReferences();
541
542
543
544
545
546
547
548
  switch (this->ProjectType) {
    case vcxproj:
      this->WriteString("<Import Project=\"" VS10_CXX_TARGETS "\" />\n", 1);
      break;
    case csproj:
      this->WriteString("<Import Project=\"" VS10_CSharp_TARGETS "\" />\n", 1);
      break;
  }
549

550
  this->WriteTargetSpecificReferences();
551
  this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1);
552
  this->WriteTargetsFileReferences();
553
554
555
556
557
558
559
560
  if (this->GlobalGenerator->IsCudaEnabled()) {
    this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
                      "BuildCustomizations\\CUDA ",
                      2);
    (*this->BuildFileStream)
      << cmVS10EscapeXML(this->GlobalGenerator->GetPlatformToolsetCudaString())
      << ".targets\" />\n";
  }
561
  if (this->GlobalGenerator->IsMasmEnabled()) {
562
    this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
563
564
565
                      "BuildCustomizations\\masm.targets\" />\n",
                      2);
  }
566
567
568
569
570
571
572
  if (this->GlobalGenerator->IsNasmEnabled()) {
    std::string nasmTargets =
      GetCMakeFilePath("Templates/MSBuild/nasm.targets");
    std::string import = "<Import Project=\"";
    import += cmVS10EscapeXML(nasmTargets) + "\" />\n";
    this->WriteString(import.c_str(), 2);
  }
573
  this->WriteString("</ImportGroup>\n", 1);
574
  if (this->ProjectType == csproj) {
575
    for (std::string const& i : this->Configurations) {
576
577
      this->WriteString("<PropertyGroup Condition=\"'$(Configuration)' == '",
                        1);
578
579
      (*this->BuildFileStream) << i << "'\">\n";
      this->WriteEvents(i);
580
581
      this->WriteString("</PropertyGroup>\n", 1);
    }
582
583
584
    // make sure custom commands are executed before build (if necessary)
    this->WriteString("<PropertyGroup>\n", 1);
    this->WriteString("<BuildDependsOn>\n", 2);
585
586
    for (std::string const& i : this->CSharpCustomCommandNames) {
      this->WriteString(i.c_str(), 3);
587
588
589
590
591
      (*this->BuildFileStream) << ";\n";
    }
    this->WriteString("$(BuildDependsOn)\n", 3);
    this->WriteString("</BuildDependsOn>\n", 2);
    this->WriteString("</PropertyGroup>\n", 1);
592
  }
593
594
595
596
597
  this->WriteString("</Project>", 0);
  // The groups are stored in a separate file for VS 10
  this->WriteGroups();
}

598
599
void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
{
600
  std::vector<std::string> references;
601
602
  typedef std::pair<std::string, std::string> HintReference;
  std::vector<HintReference> hintReferences;
603
604
  if (const char* vsDotNetReferences =
        this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) {
605
    cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
606
  }
607
  cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
608
609
610
  for (auto const& i : props) {
    if (i.first.find("VS_DOTNET_REFERENCE_") == 0) {
      std::string name = i.first.substr(20);
611
      if (!name.empty()) {
612
        std::string path = i.second.GetValue();
613
614
615
616
617
        if (!cmsys::SystemTools::FileIsFullPath(path)) {
          path = std::string(this->GeneratorTarget->Target->GetMakefile()
                               ->GetCurrentSourceDirectory()) +
            "/" + path;
        }
618
        ConvertToWindowsSlash(path);
619
620
621
622
623
        hintReferences.push_back(HintReference(name, path));
      }
    }
  }
  if (!references.empty() || !hintReferences.empty()) {
624
    this->WriteString("<ItemGroup>\n", 1);
625
    for (std::string const& ri : references) {
626
627
      // if the entry from VS_DOTNET_REFERENCES is an existing file, generate
      // a new hint-reference and name it from the filename
628
629
630
      if (cmsys::SystemTools::FileExists(ri, true)) {
        std::string name = cmsys::SystemTools::GetFilenameWithoutExtension(ri);
        std::string path = ri;
631
        ConvertToWindowsSlash(path);
632
633
        hintReferences.push_back(HintReference(name, path));
      } else {
634
        this->WriteDotNetReference(ri, "");
635
636
      }
    }
637
638
    for (const auto& i : hintReferences) {
      this->WriteDotNetReference(i.first, i.second);
639
    }
640
641
    this->WriteString("</ItemGroup>\n", 1);
  }
642
643
}

644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
void cmVisualStudio10TargetGenerator::WriteDotNetReference(
  std::string const& ref, std::string const& hint)
{
  this->WriteString("<Reference Include=\"", 2);
  (*this->BuildFileStream) << cmVS10EscapeXML(ref) << "\">\n";
  this->WriteString("<CopyLocalSatelliteAssemblies>true"
                    "</CopyLocalSatelliteAssemblies>\n",
                    3);
  this->WriteString("<ReferenceOutputAssembly>true"
                    "</ReferenceOutputAssembly>\n",
                    3);
  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";
      }
    }
    this->WriteString("<Private>", 3);
    (*this->BuildFileStream) << privateReference << "</Private>\n";
    this->WriteString("<HintPath>", 3);
    (*this->BuildFileStream) << hint << "</HintPath>\n";
  }
668
  this->WriteDotNetReferenceCustomTags(ref);
669
670
671
  this->WriteString("</Reference>\n", 2);
}

672
673
674
675
676
677
678
679
680
681
void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags(
  std::string const& ref)
{

  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();
682
683
684
685
  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();
686
687
688
689
690
      if (!refTag.empty() && !refVal.empty()) {
        tags[refTag] = refVal;
      }
    }
  }
691
  for (auto const& tag : tags) {
692
    this->WriteString("<", 3);
693
694
    (*this->BuildFileStream) << tag.first << ">" << cmVS10EscapeXML(tag.second)
                             << "</" << tag.first << ">\n";
695
696
697
  }
}

698
699
void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
{
700
  std::vector<cmSourceFile const*> resxObjs;
701
702
  this->GeneratorTarget->GetResxSources(resxObjs, "");
  if (!resxObjs.empty()) {
703
    this->WriteString("<ItemGroup>\n", 1);
704
    std::string srcDir = this->Makefile->GetCurrentSourceDirectory();
705
    ConvertToWindowsSlash(srcDir);
706
707
    for (cmSourceFile const* oi : resxObjs) {
      std::string obj = oi->GetFullPath();
708
      this->WriteString("<EmbeddedResource Include=\"", 2);
709
      ConvertToWindowsSlash(obj);
710
      bool useRelativePath = false;
711
      if (this->ProjectType == csproj && this->InSourceBuild) {
712
713
714
715
716
717
        // 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);
718
          ConvertToWindowsSlash(obj);
719
720
721
          useRelativePath = true;
        }
      }
722
      (*this->BuildFileStream) << obj << "\">\n";
723

724
      if (this->ProjectType != csproj) {
725
726
727
728
        this->WriteString("<DependentUpon>", 3);
        std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
        (*this->BuildFileStream) << hFileName << "</DependentUpon>\n";

729
730
        for (std::string const& i : this->Configurations) {
          this->WritePlatformConfigTag("LogicalName", i, 3);
731
732
733
734
735
736
737
738
739
740
741
          if (this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE") ||
              // Handle variant of VS_GLOBAL_<variable> for RootNamespace.
              this->GeneratorTarget->GetProperty("VS_GLOBAL_RootNamespace")) {
            (*this->BuildFileStream) << "$(RootNamespace).";
          }
          (*this->BuildFileStream) << "%(Filename)";
          (*this->BuildFileStream) << ".resources";
          (*this->BuildFileStream) << "</LogicalName>\n";
        }
      } else {
        std::string binDir = this->Makefile->GetCurrentBinaryDirectory();
742
        ConvertToWindowsSlash(binDir);
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
        // 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()) {
            this->WriteString("<Link>", 3);
            (*this->BuildFileStream) << link << "</Link>\n";
          }
        }
        // Determine if this is a generated resource from a .Designer.cs file
        std::string designerResource =
761
762
          cmSystemTools::GetFilenamePath(oi->GetFullPath()) + "/" +
          cmSystemTools::GetFilenameWithoutLastExtension(oi->GetFullPath()) +
763
764
765
          ".Designer.cs";
        if (cmsys::SystemTools::FileExists(designerResource)) {
          std::string generator = "PublicResXFileCodeGenerator";
766
          if (const char* g = oi->GetProperty("VS_RESOURCE_GENERATOR")) {
767
768
            generator = g;
          }
769
770
771
772
773
774
775
776
777
778
779
780
          if (!generator.empty()) {
            this->WriteString("<Generator>", 3);
            (*this->BuildFileStream) << cmVS10EscapeXML(generator)
                                     << "</Generator>\n";
            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);
            }
781
            ConvertToWindowsSlash(designerResource);
782
783
784
785
786
            this->WriteString("<LastGenOutput>", 3);
            (*this->BuildFileStream) << designerResource
                                     << "</LastGenOutput>\n";
          }
        }
787
788
        const cmPropertyMap& props = oi->GetProperties();
        for (const auto& p : props) {
789
          static const std::string propNamePrefix = "VS_CSHARP_";
790
791
          if (p.first.find(propNamePrefix) == 0) {
            std::string tagName = p.first.substr(propNamePrefix.length());
792
            if (!tagName.empty()) {
793
              std::string value = props.GetPropertyValue(p.first);
794
795
796
797
798
799
800
              if (!value.empty()) {
                this->WriteString("<", 3);
                (*this->BuildFileStream) << tagName << ">";
                (*this->BuildFileStream) << cmVS10EscapeXML(value);
                (*this->BuildFileStream) << "</" << tagName << ">\n";
              }
            }
801
          }
802
        }
803
      }
804
805
806

      this->WriteString("</EmbeddedResource>\n", 2);
    }
807
808
    this->WriteString("</ItemGroup>\n", 1);
  }
809
810
}

811
812
813
814
void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup()
{
  std::vector<cmSourceFile const*> xamlObjs;
  this->GeneratorTarget->GetXamlSources(xamlObjs, "");
815
  if (!xamlObjs.empty()) {
816
    this->WriteString("<ItemGroup>\n", 1);
817
818
    for (cmSourceFile const* oi : xamlObjs) {
      std::string obj = oi->GetFullPath();
819
      std::string xamlType;
820
      const char* xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE");
821
      if (xamlTypeProperty) {
822
        xamlType = xamlTypeProperty;
823
      } else {
824
        xamlType = "Page";
825
      }
826

827
      this->WriteSource(xamlType, oi, ">\n");
828
      if (this->ProjectType == csproj && !this->InSourceBuild) {
829
830
831
832
833
834
835
836
837
838
839
840
        // add <Link> tag to written XAML source if necessary
        const std::string srcDir = this->Makefile->GetCurrentSourceDirectory();
        const std::string binDir = this->Makefile->GetCurrentBinaryDirectory();
        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()) {
841
          ConvertToWindowsSlash(link);
842
843
844
845
          this->WriteString("<Link>", 3);
          (*this->BuildFileStream) << link << "</Link>\n";
        }
      }
846
847
848
849
      this->WriteString("<SubType>Designer</SubType>\n", 3);
      this->WriteString("</", 2);
      (*this->BuildFileStream) << xamlType << ">\n";
    }
850
851
    this->WriteString("</ItemGroup>\n", 1);
  }
852
853
}

854
855
void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences()
{
856
857
858
859
860
861
862
863
  if (this->MSTools) {
    if (this->GlobalGenerator->TargetsWindowsPhone() &&
        this->GlobalGenerator->GetSystemVersion() == "8.0") {
      this->WriteString("<Import Project=\""
                        "$(MSBuildExtensionsPath)\\Microsoft\\WindowsPhone\\v"
                        "$(TargetPlatformVersion)\\Microsoft.Cpp.WindowsPhone."
                        "$(TargetPlatformVersion).targets\" />\n",
                        1);
864
    }
865
  }
866
867
}

868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences()
{
  for (std::vector<TargetsFileAndConfigs>::iterator i =
         this->TargetsFileAndConfigsVec.begin();
       i != this->TargetsFileAndConfigsVec.end(); ++i) {
    TargetsFileAndConfigs const& tac = *i;
    this->WriteString("<Import Project=\"", 3);
    (*this->BuildFileStream) << tac.File << "\" ";
    (*this->BuildFileStream) << "Condition=\"";
    (*this->BuildFileStream) << "Exists('" << tac.File << "')";
    if (!tac.Configs.empty()) {
      (*this->BuildFileStream) << " And (";
      for (size_t j = 0; j < tac.Configs.size(); ++j) {
        if (j > 0) {
          (*this->BuildFileStream) << " Or ";
        }
        (*this->BuildFileStream) << "'$(Configuration)'=='" << tac.Configs[j]
                                 << "'";
      }
      (*this->BuildFileStream) << ")";
    }
    (*this->BuildFileStream) << "\" />\n";
  }
}

893
894
void cmVisualStudio10TargetGenerator::WriteWinRTReferences()
{
895
  std::vector<std::string> references;
896
897
  if (const char* vsWinRTReferences =
        this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) {
898
    cmSystemTools::ExpandListArgument(vsWinRTReferences, references);
899
  }
900

901
902
903
  if (this->GlobalGenerator->TargetsWindowsPhone() &&
      this->GlobalGenerator->GetSystemVersion() == "8.0" &&
      references.empty()) {
904
    references.push_back("platform.winmd");
905
906
  }
  if (!references.empty()) {
907
    this->WriteString("<ItemGroup>\n", 1);