cmVisualStudio10TargetGenerator.cxx 167 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 <memory> // IWYU pragma: keep
19

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

28
29
30
31
32
33
static std::string cmVS10EscapeQuotes(std::string arg)
{
  cmSystemTools::ReplaceString(arg, "\"", "&quot;");
  return arg;
}

34
35
36
37
38
39
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;
40
41
42
43
44
45
46
  for (std::string::iterator c = comment.begin(); c != comment.end(); ++c) {
    switch (*c) {
      case '\r':
        break;
      case '\n':
        echoable += '\t';
        break;
47
48
49
50
51
      case '"': /* no break */
      case '|': /* no break */
      case '&': /* no break */
      case '<': /* no break */
      case '>': /* no break */
52
53
54
55
56
      case '^':
        echoable += '^'; /* no break */
      default:
        echoable += *c;
        break;
57
    }
58
  }
59
60
61
  return echoable;
}

62
63
64
65
66
67
static bool cmVS10IsTargetsFile(std::string const& path)
{
  std::string const ext = cmSystemTools::GetFilenameLastExtension(path);
  return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
}

68
69
70
71
72
73
74
75
76
77
static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
{
  std::string res;
  res = ".vcxproj";
  if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t)) {
    res = ".csproj";
  }
  return res;
}

78
79
cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
  cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
80
81
{
  this->GlobalGenerator = gg;
82
83
  this->GeneratorTarget = target;
  this->Makefile = target->Target->GetMakefile();
84
  this->Makefile->GetConfigurations(this->Configurations);
85
  this->LocalGenerator =
86
    (cmLocalVisualStudio7Generator*)this->GeneratorTarget->GetLocalGenerator();
87
  this->Name = this->GeneratorTarget->GetName();
88
  this->GUID = this->GlobalGenerator->GetGUID(this->Name);
Brad King's avatar
Brad King committed
89
  this->Platform = gg->GetPlatformName();
90
  this->NsightTegra = gg->IsNsightTegra();
91
  for (int i = 0; i < 4; ++i) {
92
    this->NsightTegraVersion[i] = 0;
93
  }
94
95
96
  sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u",
         &this->NsightTegraVersion[0], &this->NsightTegraVersion[1],
         &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]);
97
  this->MSTools = !this->NsightTegra;
98
  this->Managed = false;
99
  this->TargetCompileAsWinRT = false;
100
  this->BuildFileStream = 0;
101
102
  this->IsMissingFiles = false;
  this->DefaultArtifactDir =
103
    this->LocalGenerator->GetCurrentBinaryDirectory() + std::string("/") +
104
    this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
105
106
107
  this->InSourceBuild =
    (strcmp(this->Makefile->GetCurrentSourceDirectory(),
            this->Makefile->GetCurrentBinaryDirectory()) == 0);
108
109
110
111
}

cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
{
112
113
  for (OptionsMap::iterator i = this->ClOptions.begin();
       i != this->ClOptions.end(); ++i) {
114
    delete i->second;
115
116
117
  }
  for (OptionsMap::iterator i = this->LinkOptions.begin();
       i != this->LinkOptions.end(); ++i) {
118
    delete i->second;
119
  }
120
121
122
123
  for (OptionsMap::iterator i = this->CudaOptions.begin();
       i != this->CudaOptions.end(); ++i) {
    delete i->second;
  }
124
125
126
127
  for (OptionsMap::iterator i = this->CudaLinkOptions.begin();
       i != this->CudaLinkOptions.end(); ++i) {
    delete i->second;
  }
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
203
204
205
206
207
208
209
  this->ProjectFileExtension =
    computeProjectFileExtension(this->GeneratorTarget);
  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
404
  for (std::vector<std::string>::const_iterator keyIt = keys.begin();
       keyIt != keys.end(); ++keyIt) {
405
    static const char* prefix = "VS_GLOBAL_";
406
    if (keyIt->find(prefix) != 0)
407
408
409
      continue;
    std::string globalKey = keyIt->substr(strlen(prefix));
    // Skip invalid or separately-handled properties.
410
    if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
411
        globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
412
      continue;
413
    }
414
    const char* value = this->GeneratorTarget->GetProperty(*keyIt);
415
416
417
    if (!value)
      continue;
    this->WriteString("<", 2);
418
    (*this->BuildFileStream) << globalKey << ">" << cmVS10EscapeXML(value)
419
                             << "</" << globalKey << ">\n";
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
454
  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);
  }

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

  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;
  }

470
  this->WriteProjectConfigurationValues();
471

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

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

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

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
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";
  }
678
  this->WriteDotNetReferenceCustomTags(ref);
679
680
681
  this->WriteString("</Reference>\n", 2);
}

682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
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();
  for (cmPropertyMap::const_iterator i = props.begin(); i != props.end();
       ++i) {
    if (i->first.find(refPropFullPrefix) == 0) {
      std::string refTag = i->first.substr(refPropFullPrefix.length());
      std::string refVal = i->second.GetValue();
      if (!refTag.empty() && !refVal.empty()) {
        tags[refTag] = refVal;
      }
    }
  }
  for (CustomTags::const_iterator tag = tags.begin(); tag != tags.end();
       ++tag) {
    this->WriteString("<", 3);
    (*this->BuildFileStream) << tag->first << ">"
                             << cmVS10EscapeXML(tag->second) << "</"
                             << tag->first << ">\n";
  }
}

711
712
void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
{
713
  std::vector<cmSourceFile const*> resxObjs;
714
715
  this->GeneratorTarget->GetResxSources(resxObjs, "");
  if (!resxObjs.empty()) {
716
    this->WriteString("<ItemGroup>\n", 1);
717
718
    std::string srcDir = this->Makefile->GetCurrentSourceDirectory();
    this->ConvertToWindowsSlash(srcDir);
719
720
721
    for (std::vector<cmSourceFile const*>::const_iterator oi =
           resxObjs.begin();
         oi != resxObjs.end(); ++oi) {
722
723
724
      std::string obj = (*oi)->GetFullPath();
      this->WriteString("<EmbeddedResource Include=\"", 2);
      this->ConvertToWindowsSlash(obj);
725
      bool useRelativePath = false;
726
      if (this->ProjectType == csproj && this->InSourceBuild) {
727
728
729
730
731
732
733
734
735
736
        // 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);
          this->ConvertToWindowsSlash(obj);
          useRelativePath = true;
        }
      }
737
      (*this->BuildFileStream) << obj << "\">\n";
738

739
      if (this->ProjectType != csproj) {
740
741
742
743
744
745
746
        this->WriteString("<DependentUpon>", 3);
        std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
        (*this->BuildFileStream) << hFileName << "</DependentUpon>\n";

        for (std::vector<std::string>::const_iterator i =
               this->Configurations.begin();
             i != this->Configurations.end(); ++i) {
747
          this->WritePlatformConfigTag("LogicalName", *i, 3);
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
          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();
        this->ConvertToWindowsSlash(binDir);
        // 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 =
          cmSystemTools::GetFilenamePath((*oi)->GetFullPath()) + "/" +
          cmSystemTools::GetFilenameWithoutLastExtension(
            (*oi)->GetFullPath()) +
          ".Designer.cs";
        if (cmsys::SystemTools::FileExists(designerResource)) {
          std::string generator = "PublicResXFileCodeGenerator";
          if (const char* g = (*oi)->GetProperty("VS_RESOURCE_GENERATOR")) {
            generator = g;
          }
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
          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);
            }
            this->ConvertToWindowsSlash(designerResource);
            this->WriteString("<LastGenOutput>", 3);
            (*this->BuildFileStream) << designerResource
                                     << "</LastGenOutput>\n";
          }
        }
        const cmPropertyMap& props = (*oi)->GetProperties();
        for (cmPropertyMap::const_iterator p = props.begin(); p != props.end();
             ++p) {
          static const std::string propNamePrefix = "VS_CSHARP_";
809
          if (p->first.find(propNamePrefix) == 0) {
810
811
812
813
814
815
816
817
818
819
            std::string tagName = p->first.substr(propNamePrefix.length());
            if (!tagName.empty()) {
              std::string value = props.GetPropertyValue(p->first);
              if (!value.empty()) {
                this->WriteString("<", 3);
                (*this->BuildFileStream) << tagName << ">";
                (*this->BuildFileStream) << cmVS10EscapeXML(value);
                (*this->BuildFileStream) << "</" << tagName << ">\n";
              }
            }
820
          }
821
        }
822
      }
823
824
825

      this->WriteString("</EmbeddedResource>\n", 2);
    }
826
827
    this->WriteString("</ItemGroup>\n", 1);
  }
828
829
}

830
831
832
833
void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup()
{
  std::vector<cmSourceFile const*> xamlObjs;
  this->GeneratorTarget->GetXamlSources(xamlObjs, "");
834
  if (!xamlObjs.empty()) {
835
    this->WriteString("<ItemGroup>\n", 1);
836
837
838
    for (std::vector<cmSourceFile const*>::const_iterator oi =
           xamlObjs.begin();
         oi != xamlObjs.end(); ++oi) {
839
840
      std::string obj = (*oi)->GetFullPath();
      std::string xamlType;
841
842
      const char* xamlTypeProperty = (*oi)->GetProperty("VS_XAML_TYPE");
      if (xamlTypeProperty) {
843
        xamlType = xamlTypeProperty;
844
      } else {
845
        xamlType = "Page";
846
      }
847
848

      this->WriteSource(xamlType, *oi, ">\n");
849
      if (this->ProjectType == csproj && !this->InSourceBuild) {
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
        // 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()) {
          this->ConvertToWindowsSlash(link);
          this->WriteString("<Link>", 3);
          (*this->BuildFileStream) << link << "</Link>\n";
        }
      }
867
868
869
870
      this->WriteString("<SubType>Designer</SubType>\n", 3);
      this->WriteString("</", 2);
      (*this->BuildFileStream) << xamlType << ">\n";
    }
871
872
    this->WriteString("</ItemGroup>\n", 1);
  }
873
874
}

875
876
void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences()
{
877
878
879
880
881
882
883
884
  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);
885
    }
886
  }
887
888
}

889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
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";
  }
}

914
915
void cmVisualStudio10TargetGenerator::WriteWinRTReferences()
{
916
  std::vector<std::string> references;
917
918
  if (const char* vsWinRTReferences =
        this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) {
919
    cmSystemTools::ExpandListArgument(vsWinRTReferences, references);
920
  }
921

922
923
924
  if (this->GlobalGenerator->TargetsWindowsPhone() &&
      this->GlobalGenerator->GetSystemVersion() == "8.0" &&
      references.empty()) {
925
    references.push_back("platform.winmd");
926
927
  }
  if (!references.empty()) {
928
    this->WriteString("<ItemGroup>\n", 1);
929
930
    for (std::vector<std::string>::iterator ri = references.begin();
         ri != references.end(); ++ri) {
931
      this->WriteString("<Reference Include=\"", 2);
932
      (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n";
933
934
935
      this->WriteString("<IsWinMDFile>true</IsWinMDFile>\n", 3);
      this->WriteString("</Reference>\n", 2);
    }
936
937
    this->WriteString("</ItemGroup>\n", 1);
  }
938
939
}

940
941
942
943
944
// ConfigurationType Application, Utility StaticLibrary DynamicLibrary

void cmVisualStudio10TargetGenerator::WriteProjectConfigurations()
{
  this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1);
945
946
947
  for (std::vector<std::string>::const_iterator i =
         this->Configurations.begin();
       i != this->Configurations.end(); ++i) {
948
    this->WriteString("<ProjectConfiguration Include=\"", 2);
949
    (*this->BuildFileStream) << *i << "|" << this->Platform << "\">\n";
950
    this->WriteString("<Configuration>", 3);
951
    (*this->BuildFileStream) << *i << "</Configuration>\n";
Brad King's avatar
Brad King committed
952
    this->WriteString("<Platform>", 3);
953
954
    (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform)
                             << "</Platform>\n";
955
    this->WriteString("</ProjectConfiguration>\n", 2);
956
  }
957
958
959
960
961
  this->WriteString("</ItemGroup>\n", 1);
}

void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
{
962
963
964
  for (std::vector<std::string>::const_iterator i =
         this->Configurations.begin();
       i != this->Configurations.end(); ++i) {
965
    this->WritePlatformConfigTag("PropertyGroup", *i, 1,
966
                                 " Label=\"Configuration\"", "\n");
967

968
    if (this->ProjectType != csproj) {
969
970
971
972
973
974
975
976
      std::string configType = "<ConfigurationType>";
      if (const char* vsConfigurationType =
            this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) {
        configType += cmVS10EscapeXML(vsConfigurationType);
      } else {
        switch (this->GeneratorTarget->GetType()) {
          case cmStateEnums::SHARED_LIBRARY:
          case cmStateEnums::MODULE_LIBRARY:
977
            configType += "DynamicLibrary";
978
979
980
            break;
          case cmStateEnums::OBJECT_LIBRARY:
          case cmStateEnums::STATIC_LIBRARY:
981
            configType += "StaticLibrary";
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
            break;
          case cmStateEnums::EXECUTABLE:
            if (this->NsightTegra &&
                !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) {
              // Android executables are .so too.
              configType += "DynamicLibrary";
            } else {
              configType += "Application";
            }
            break;
          case cmStateEnums::UTILITY:
          case cmStateEnums::GLOBAL_TARGET:
            if (this->NsightTegra) {
              // Tegra-Android platform does not understand "Utility".
              configType += "StaticLibrary";
            } else {
              configType += "Utility";
            }
            break;
          case cmStateEnums::UNKNOWN_LIBRARY:
          case cmStateEnums::INTERFACE_LIBRARY:
            break;
        }
1005
      }
1006
1007
      configType += "</ConfigurationType>\n";
      this->WriteString(configType.c_str(), 2);
1008
    }
1009

1010
    if (this->MSTools) {
1011
1012
1013
1014
1015
      if (!this->Managed) {
        this->WriteMSToolConfigurationValues(*i);
      } else {
        this->WriteMSToolConfigurationValuesManaged(*i);
      }
1016