1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmVisualStudio10TargetGenerator.h"
13 #include "cmGlobalVisualStudio10Generator.h"
14 #include "cmGeneratorTarget.h"
16 #include "cmComputeLinkInformation.h"
17 #include "cmGeneratedFileStream.h"
18 #include "cmMakefile.h"
19 #include "cmSourceFile.h"
20 #include "cmVisualStudioGeneratorOptions.h"
21 #include "cmLocalVisualStudio7Generator.h"
22 #include "cmVS10CLFlagTable.h"
23 #include "cmVS10LinkFlagTable.h"
24 #include "cmVS10LibFlagTable.h"
25 #include "cmVS11CLFlagTable.h"
26 #include "cmVS11LinkFlagTable.h"
27 #include "cmVS11LibFlagTable.h"
28 #include "cmVS12CLFlagTable.h"
29 #include "cmVS12LinkFlagTable.h"
30 #include "cmVS12LibFlagTable.h"
32 #include <cmsys/auto_ptr.hxx>
34 static cmVS7FlagTable const*
35 cmVSGetCLFlagTable(cmLocalVisualStudioGenerator* lg)
37 if(lg->GetVersion() >= cmLocalVisualStudioGenerator::VS12)
38 { return cmVS12CLFlagTable; }
39 else if(lg->GetVersion() == cmLocalVisualStudioGenerator::VS11)
40 { return cmVS11CLFlagTable; }
42 { return cmVS10CLFlagTable; }
45 static cmVS7FlagTable const*
46 cmVSGetLibFlagTable(cmLocalVisualStudioGenerator* lg)
48 if(lg->GetVersion() >= cmLocalVisualStudioGenerator::VS12)
49 { return cmVS12LibFlagTable; }
50 else if(lg->GetVersion() == cmLocalVisualStudioGenerator::VS11)
51 { return cmVS11LibFlagTable; }
53 { return cmVS10LibFlagTable; }
56 static cmVS7FlagTable const*
57 cmVSGetLinkFlagTable(cmLocalVisualStudioGenerator* lg)
59 if(lg->GetVersion() >= cmLocalVisualStudioGenerator::VS12)
60 { return cmVS12LinkFlagTable; }
61 else if(lg->GetVersion() == cmLocalVisualStudioGenerator::VS11)
62 { return cmVS11LinkFlagTable; }
64 { return cmVS10LinkFlagTable; }
67 static std::string cmVS10EscapeXML(std::string arg)
69 cmSystemTools::ReplaceString(arg, "&", "&");
70 cmSystemTools::ReplaceString(arg, "<", "<");
71 cmSystemTools::ReplaceString(arg, ">", ">");
75 static std::string cmVS10EscapeComment(std::string comment)
77 // MSBuild takes the CDATA of a <Message></Message> element and just
78 // does "echo $CDATA" with no escapes. We must encode the string.
79 // http://technet.microsoft.com/en-us/library/cc772462%28WS.10%29.aspx
81 for(std::string::iterator c = comment.begin(); c != comment.end(); ++c)
86 case '\n': echoable += '\t'; break;
87 case '"': /* no break */
88 case '|': /* no break */
89 case '&': /* no break */
90 case '<': /* no break */
91 case '>': /* no break */
92 case '^': echoable += '^'; /* no break */
93 default: echoable += *c; break;
99 cmVisualStudio10TargetGenerator::
100 cmVisualStudio10TargetGenerator(cmTarget* target,
101 cmGlobalVisualStudio10Generator* gg)
103 this->GlobalGenerator = gg;
104 this->Target = target;
105 this->GeneratorTarget = gg->GetGeneratorTarget(target);
106 this->Makefile = target->GetMakefile();
107 this->LocalGenerator =
108 (cmLocalVisualStudio7Generator*)
109 this->Makefile->GetLocalGenerator();
110 this->Name = this->Target->GetName();
111 this->GlobalGenerator->CreateGUID(this->Name.c_str());
112 this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str());
113 this->Platform = gg->GetPlatformName();
114 this->BuildFileStream = 0;
117 cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
119 for(OptionsMap::iterator i = this->ClOptions.begin();
120 i != this->ClOptions.end(); ++i)
124 for(OptionsMap::iterator i = this->LinkOptions.begin();
125 i != this->LinkOptions.end(); ++i)
129 if(!this->BuildFileStream)
133 if (this->BuildFileStream->Close())
135 this->GlobalGenerator
136 ->FileReplacedDuringGenerate(this->PathToVcxproj);
138 delete this->BuildFileStream;
141 void cmVisualStudio10TargetGenerator::WritePlatformConfigTag(
145 const char* attribute,
147 std::ostream* stream)
152 stream = this->BuildFileStream;
155 stream->width(indentLevel*2 );
157 (*stream ) << "<" << tag
158 << " Condition=\"'$(Configuration)|$(Platform)'=='";
159 (*stream ) << config << "|" << this->Platform << "'\"";
162 (*stream ) << attribute;
172 void cmVisualStudio10TargetGenerator::WriteString(const char* line,
175 this->BuildFileStream->fill(' ');
176 this->BuildFileStream->width(indentLevel*2 );
177 // write an empty string to get the fill level indent to print
178 (*this->BuildFileStream ) << "";
179 (*this->BuildFileStream ) << line;
182 #define VS10_USER_PROPS "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"
184 void cmVisualStudio10TargetGenerator::Generate()
186 // do not generate external ms projects
187 if(this->Target->GetProperty("EXTERNAL_MSPROJECT"))
191 // Tell the global generator the name of the project file
192 this->Target->SetProperty("GENERATOR_FILE_NAME",this->Name.c_str());
193 this->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
195 if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
197 if(!this->ComputeClOptions())
201 if(!this->ComputeLinkOptions())
206 cmMakefile* mf = this->Target->GetMakefile();
207 std::string path = mf->GetStartOutputDirectory();
211 this->BuildFileStream =
212 new cmGeneratedFileStream(path.c_str());
213 this->PathToVcxproj = path;
214 this->BuildFileStream->SetCopyIfDifferent(true);
216 // Write the encoding header into the file
217 char magic[] = {0xEF,0xBB, 0xBF};
218 this->BuildFileStream->write(magic, 3);
220 //get the tools version to use
221 const std::string toolsVer(this->GlobalGenerator->GetToolsVersion());
222 std::string project_defaults="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
223 project_defaults.append("<Project DefaultTargets=\"Build\" ToolsVersion=\"");
224 project_defaults.append(toolsVer +"\" ");
225 project_defaults.append(
226 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
227 this->WriteString(project_defaults.c_str(),0);
229 this->WriteProjectConfigurations();
230 this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
231 this->WriteString("<ProjectGUID>", 2);
232 (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGUID>\n";
234 const char* vsProjectTypes =
235 this->Target->GetProperty("VS_GLOBAL_PROJECT_TYPES");
238 this->WriteString("<ProjectTypes>", 2);
239 (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectTypes) <<
243 const char* vsProjectName = this->Target->GetProperty("VS_SCC_PROJECTNAME");
244 const char* vsLocalPath = this->Target->GetProperty("VS_SCC_LOCALPATH");
245 const char* vsProvider = this->Target->GetProperty("VS_SCC_PROVIDER");
247 if( vsProjectName && vsLocalPath && vsProvider )
249 this->WriteString("<SccProjectName>", 2);
250 (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectName) <<
251 "</SccProjectName>\n";
252 this->WriteString("<SccLocalPath>", 2);
253 (*this->BuildFileStream) << cmVS10EscapeXML(vsLocalPath) <<
255 this->WriteString("<SccProvider>", 2);
256 (*this->BuildFileStream) << cmVS10EscapeXML(vsProvider) <<
259 const char* vsAuxPath = this->Target->GetProperty("VS_SCC_AUXPATH");
262 this->WriteString("<SccAuxPath>", 2);
263 (*this->BuildFileStream) << cmVS10EscapeXML(vsAuxPath) <<
268 const char* vsGlobalKeyword =
269 this->Target->GetProperty("VS_GLOBAL_KEYWORD");
272 this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2);
276 this->WriteString("<Keyword>", 2);
277 (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalKeyword) <<
281 const char* vsGlobalRootNamespace =
282 this->Target->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
283 if(vsGlobalRootNamespace)
285 this->WriteString("<RootNamespace>", 2);
286 (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalRootNamespace) <<
287 "</RootNamespace>\n";
290 this->WriteString("<Platform>", 2);
291 (*this->BuildFileStream) << this->Platform << "</Platform>\n";
292 const char* projLabel = this->Target->GetProperty("PROJECT_LABEL");
295 projLabel = this->Name.c_str();
297 this->WriteString("<ProjectName>", 2);
298 (*this->BuildFileStream) << projLabel << "</ProjectName>\n";
299 if(const char* targetFrameworkVersion = this->Target->GetProperty(
300 "VS_DOTNET_TARGET_FRAMEWORK_VERSION"))
302 this->WriteString("<TargetFrameworkVersion>", 2);
303 (*this->BuildFileStream) << targetFrameworkVersion
304 << "</TargetFrameworkVersion>\n";
306 this->WriteString("</PropertyGroup>\n", 1);
307 this->WriteString("<Import Project="
308 "\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n",
310 this->WriteProjectConfigurationValues();
312 "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n", 1);
313 this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1);
314 if (this->GlobalGenerator->IsMasmEnabled())
316 this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
317 "BuildCustomizations\\masm.props\" />\n", 2);
319 this->WriteString("</ImportGroup>\n", 1);
320 this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1);
321 this->WriteString("<Import Project=\"" VS10_USER_PROPS "\""
322 " Condition=\"exists('" VS10_USER_PROPS "')\""
323 " Label=\"LocalAppDataPlatform\" />", 2);
324 this->WriteString("</ImportGroup>\n", 1);
325 this->WriteString("<PropertyGroup Label=\"UserMacros\" />\n", 1);
326 this->WritePathAndIncrementalLinkOptions();
327 this->WriteItemDefinitionGroups();
328 this->WriteCustomCommands();
329 this->WriteAllSources();
330 this->WriteDotNetReferences();
331 this->WriteEmbeddedResourceGroup();
332 this->WriteWinRTReferences();
333 this->WriteProjectReferences();
335 "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\""
337 this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1);
338 if (this->GlobalGenerator->IsMasmEnabled())
340 this->WriteString("<Import Project=\"$(VCTargetsPath)\\"
341 "BuildCustomizations\\masm.targets\" />\n", 2);
343 this->WriteString("</ImportGroup>\n", 1);
344 this->WriteString("</Project>", 0);
345 // The groups are stored in a separate file for VS 10
349 void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
351 std::vector<std::string> references;
352 if(const char* vsDotNetReferences =
353 this->Target->GetProperty("VS_DOTNET_REFERENCES"))
355 cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
357 if(!references.empty())
359 this->WriteString("<ItemGroup>\n", 1);
360 for(std::vector<std::string>::iterator ri = references.begin();
361 ri != references.end(); ++ri)
363 this->WriteString("<Reference Include=\"", 2);
364 (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n";
365 this->WriteString("<CopyLocalSatelliteAssemblies>true"
366 "</CopyLocalSatelliteAssemblies>\n", 3);
367 this->WriteString("<ReferenceOutputAssembly>true"
368 "</ReferenceOutputAssembly>\n", 3);
369 this->WriteString("</Reference>\n", 2);
371 this->WriteString("</ItemGroup>\n", 1);
375 void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
377 std::vector<cmSourceFile*> const& resxObjs =
378 this->GeneratorTarget->ResxSources;
379 if(!resxObjs.empty())
381 this->WriteString("<ItemGroup>\n", 1);
382 for(std::vector<cmSourceFile*>::const_iterator oi = resxObjs.begin();
383 oi != resxObjs.end(); ++oi)
385 std::string obj = (*oi)->GetFullPath();
386 this->WriteString("<EmbeddedResource Include=\"", 2);
387 this->ConvertToWindowsSlash(obj);
388 (*this->BuildFileStream ) << obj << "\">\n";
390 this->WriteString("<DependentUpon>", 3);
391 std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
392 (*this->BuildFileStream ) << hFileName;
393 this->WriteString("</DependentUpon>\n", 3);
395 std::vector<std::string> const * configs =
396 this->GlobalGenerator->GetConfigurations();
397 for(std::vector<std::string>::const_iterator i = configs->begin();
398 i != configs->end(); ++i)
400 this->WritePlatformConfigTag("LogicalName", i->c_str(), 3);
401 if(this->Target->GetProperty("VS_GLOBAL_ROOTNAMESPACE"))
403 (*this->BuildFileStream ) << "$(RootNamespace).";
405 (*this->BuildFileStream ) << "%(Filename)";
406 (*this->BuildFileStream ) << ".resources";
407 (*this->BuildFileStream ) << "</LogicalName>\n";
410 this->WriteString("</EmbeddedResource>\n", 2);
412 this->WriteString("</ItemGroup>\n", 1);
416 void cmVisualStudio10TargetGenerator::WriteWinRTReferences()
418 std::vector<std::string> references;
419 if(const char* vsWinRTReferences =
420 this->Target->GetProperty("VS_WINRT_REFERENCES"))
422 cmSystemTools::ExpandListArgument(vsWinRTReferences, references);
424 if(!references.empty())
426 this->WriteString("<ItemGroup>\n", 1);
427 for(std::vector<std::string>::iterator ri = references.begin();
428 ri != references.end(); ++ri)
430 this->WriteString("<Reference Include=\"", 2);
431 (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n";
432 this->WriteString("<IsWinMDFile>true</IsWinMDFile>\n", 3);
433 this->WriteString("</Reference>\n", 2);
435 this->WriteString("</ItemGroup>\n", 1);
439 // ConfigurationType Application, Utility StaticLibrary DynamicLibrary
441 void cmVisualStudio10TargetGenerator::WriteProjectConfigurations()
443 this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1);
444 std::vector<std::string> *configs =
445 static_cast<cmGlobalVisualStudio7Generator *>
446 (this->GlobalGenerator)->GetConfigurations();
447 for(std::vector<std::string>::iterator i = configs->begin();
448 i != configs->end(); ++i)
450 this->WriteString("<ProjectConfiguration Include=\"", 2);
451 (*this->BuildFileStream ) << *i << "|" << this->Platform << "\">\n";
452 this->WriteString("<Configuration>", 3);
453 (*this->BuildFileStream ) << *i << "</Configuration>\n";
454 this->WriteString("<Platform>", 3);
455 (*this->BuildFileStream) << this->Platform << "</Platform>\n";
456 this->WriteString("</ProjectConfiguration>\n", 2);
458 this->WriteString("</ItemGroup>\n", 1);
461 void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
463 cmGlobalVisualStudio10Generator* gg =
464 static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
465 std::vector<std::string> *configs =
466 static_cast<cmGlobalVisualStudio7Generator *>
467 (this->GlobalGenerator)->GetConfigurations();
468 for(std::vector<std::string>::iterator i = configs->begin();
469 i != configs->end(); ++i)
471 this->WritePlatformConfigTag("PropertyGroup",
473 1, " Label=\"Configuration\"", "\n");
474 std::string configType = "<ConfigurationType>";
475 switch(this->Target->GetType())
477 case cmTarget::SHARED_LIBRARY:
478 case cmTarget::MODULE_LIBRARY:
479 configType += "DynamicLibrary";
481 case cmTarget::OBJECT_LIBRARY:
482 case cmTarget::STATIC_LIBRARY:
483 configType += "StaticLibrary";
485 case cmTarget::EXECUTABLE:
486 configType += "Application";
488 case cmTarget::UTILITY:
489 configType += "Utility";
491 case cmTarget::GLOBAL_TARGET:
492 case cmTarget::UNKNOWN_LIBRARY:
495 configType += "</ConfigurationType>\n";
496 this->WriteString(configType.c_str(), 2);
498 const char* mfcFlag =
499 this->Target->GetMakefile()->GetDefinition("CMAKE_MFC_FLAG");
500 std::string mfcFlagValue = mfcFlag ? mfcFlag : "0";
502 std::string useOfMfcValue = "false";
503 if(mfcFlagValue == "1")
505 useOfMfcValue = "Static";
507 else if(mfcFlagValue == "2")
509 useOfMfcValue = "Dynamic";
511 std::string mfcLine = "<UseOfMfc>";
512 mfcLine += useOfMfcValue + "</UseOfMfc>\n";
513 this->WriteString(mfcLine.c_str(), 2);
515 if((this->Target->GetType() <= cmTarget::OBJECT_LIBRARY &&
516 this->ClOptions[*i]->UsingUnicode()) ||
517 this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS"))
519 this->WriteString("<CharacterSet>Unicode</CharacterSet>\n", 2);
521 else if (this->Target->GetType() <= cmTarget::MODULE_LIBRARY &&
522 this->ClOptions[*i]->UsingSBCS())
524 this->WriteString("<CharacterSet>NotSet</CharacterSet>\n", 2);
528 this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2);
530 if(const char* toolset = gg->GetPlatformToolset())
532 std::string pts = "<PlatformToolset>";
534 pts += "</PlatformToolset>\n";
535 this->WriteString(pts.c_str(), 2);
537 if(this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS"))
539 this->WriteString("<WindowsAppContainer>true"
540 "</WindowsAppContainer>\n", 2);
543 this->WriteString("</PropertyGroup>\n", 1);
547 void cmVisualStudio10TargetGenerator::WriteCustomCommands()
549 this->SourcesVisited.clear();
550 for(std::vector<cmSourceFile*>::const_iterator
551 si = this->GeneratorTarget->CustomCommands.begin();
552 si != this->GeneratorTarget->CustomCommands.end(); ++si)
554 this->WriteCustomCommand(*si);
558 //----------------------------------------------------------------------------
559 void cmVisualStudio10TargetGenerator::WriteCustomCommand(cmSourceFile* sf)
561 if(this->SourcesVisited.insert(sf).second)
563 if(std::vector<cmSourceFile*> const* depends =
564 this->Target->GetSourceDepends(sf))
566 for(std::vector<cmSourceFile*>::const_iterator di = depends->begin();
567 di != depends->end(); ++di)
569 this->WriteCustomCommand(*di);
572 if(cmCustomCommand const* command = sf->GetCustomCommand())
574 this->WriteString("<ItemGroup>\n", 1);
575 this->WriteCustomRule(sf, *command);
576 this->WriteString("</ItemGroup>\n", 1);
582 cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source,
583 cmCustomCommand const &
586 std::string sourcePath = source->GetFullPath();
587 // VS 10 will always rebuild a custom command attached to a .rule
588 // file that doesn't exist so create the file explicitly.
589 if (source->GetPropertyAsBool("__CMAKE_RULE"))
591 if(!cmSystemTools::FileExists(sourcePath.c_str()))
593 // Make sure the path exists for the file
594 std::string path = cmSystemTools::GetFilenamePath(sourcePath);
595 cmSystemTools::MakeDirectory(path.c_str());
596 std::ofstream fout(sourcePath.c_str());
599 fout << "# generated from CMake\n";
605 std::string error = "Could not create file: [";
609 (error.c_str(), cmSystemTools::GetLastSystemError().c_str());
613 cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
614 std::string comment = lg->ConstructComment(command);
615 comment = cmVS10EscapeComment(comment);
616 std::vector<std::string> *configs =
617 static_cast<cmGlobalVisualStudio7Generator *>
618 (this->GlobalGenerator)->GetConfigurations();
620 this->WriteSource("CustomBuild", source, ">\n");
622 for(std::vector<std::string>::iterator i = configs->begin();
623 i != configs->end(); ++i)
626 cmVS10EscapeXML(lg->ConstructScript(command, i->c_str()));
627 this->WritePlatformConfigTag("Message",i->c_str(), 3);
628 (*this->BuildFileStream ) << cmVS10EscapeXML(comment) << "</Message>\n";
629 this->WritePlatformConfigTag("Command", i->c_str(), 3);
630 (*this->BuildFileStream ) << script << "</Command>\n";
631 this->WritePlatformConfigTag("AdditionalInputs", i->c_str(), 3);
633 (*this->BuildFileStream ) << source->GetFullPath();
634 for(std::vector<std::string>::const_iterator d =
635 command.GetDepends().begin();
636 d != command.GetDepends().end();
640 if(this->LocalGenerator->GetRealDependency(d->c_str(), i->c_str(), dep))
642 this->ConvertToWindowsSlash(dep);
643 (*this->BuildFileStream ) << ";" << dep;
646 (*this->BuildFileStream ) << ";%(AdditionalInputs)</AdditionalInputs>\n";
647 this->WritePlatformConfigTag("Outputs", i->c_str(), 3);
648 const char* sep = "";
649 for(std::vector<std::string>::const_iterator o =
650 command.GetOutputs().begin();
651 o != command.GetOutputs().end();
654 std::string out = *o;
655 this->ConvertToWindowsSlash(out);
656 (*this->BuildFileStream ) << sep << out;
659 (*this->BuildFileStream ) << "</Outputs>\n";
660 if(this->LocalGenerator->GetVersion() > cmLocalVisualStudioGenerator::VS10)
662 // VS >= 11 let us turn off linking of custom command outputs.
663 this->WritePlatformConfigTag("LinkObjects", i->c_str(), 3);
664 (*this->BuildFileStream ) << "false</LinkObjects>\n";
667 this->WriteString("</CustomBuild>\n", 2);
671 cmVisualStudio10TargetGenerator::ConvertPath(std::string const& path,
675 ? cmSystemTools::RelativePath(
676 this->Makefile->GetCurrentOutputDirectory(), path.c_str())
677 : this->LocalGenerator->Convert(path.c_str(),
678 cmLocalGenerator::START_OUTPUT,
679 cmLocalGenerator::UNCHANGED);
682 void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s)
684 // first convert all of the slashes
685 std::string::size_type pos = 0;
686 while((pos = s.find('/', pos)) != std::string::npos)
692 void cmVisualStudio10TargetGenerator::WriteGroups()
694 // collect up group information
695 std::vector<cmSourceGroup> sourceGroups =
696 this->Makefile->GetSourceGroups();
697 std::vector<cmSourceFile*> classes = this->Target->GetSourceFiles();
699 std::set<cmSourceGroup*> groupsUsed;
700 for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
701 s != classes.end(); s++)
703 cmSourceFile* sf = *s;
704 std::string const& source = sf->GetFullPath();
705 cmSourceGroup& sourceGroup =
706 this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
707 groupsUsed.insert(&sourceGroup);
710 this->AddMissingSourceGroups(groupsUsed, sourceGroups);
712 // Write out group file
713 std::string path = this->Makefile->GetStartOutputDirectory();
716 path += ".vcxproj.filters";
717 cmGeneratedFileStream fout(path.c_str());
718 fout.SetCopyIfDifferent(true);
719 char magic[] = {0xEF,0xBB, 0xBF};
720 fout.write(magic, 3);
721 cmGeneratedFileStream* save = this->BuildFileStream;
722 this->BuildFileStream = & fout;
724 //get the tools version to use
725 const std::string toolsVer(this->GlobalGenerator->GetToolsVersion());
726 std::string project_defaults="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
727 project_defaults.append("<Project ToolsVersion=\"");
728 project_defaults.append(toolsVer +"\" ");
729 project_defaults.append(
730 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n");
731 this->WriteString(project_defaults.c_str(),0);
733 for(ToolSourceMap::const_iterator ti = this->Tools.begin();
734 ti != this->Tools.end(); ++ti)
736 this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups);
739 std::vector<cmSourceFile*> const& resxObjs =
740 this->GeneratorTarget->ResxSources;
741 if(!resxObjs.empty())
743 this->WriteString("<ItemGroup>\n", 1);
744 for(std::vector<cmSourceFile*>::const_iterator oi = resxObjs.begin();
745 oi != resxObjs.end(); ++oi)
747 std::string obj = (*oi)->GetFullPath();
748 this->WriteString("<EmbeddedResource Include=\"", 2);
749 this->ConvertToWindowsSlash(obj);
750 (*this->BuildFileStream ) << obj << "\">\n";
751 this->WriteString("<Filter>Resource Files</Filter>\n", 3);
752 this->WriteString("</EmbeddedResource>\n", 2);
754 this->WriteString("</ItemGroup>\n", 1);
757 // Add object library contents as external objects.
758 std::vector<std::string> objs;
759 this->GeneratorTarget->UseObjectLibraries(objs);
762 this->WriteString("<ItemGroup>\n", 1);
763 for(std::vector<std::string>::const_iterator
764 oi = objs.begin(); oi != objs.end(); ++oi)
766 std::string obj = *oi;
767 this->WriteString("<Object Include=\"", 2);
768 this->ConvertToWindowsSlash(obj);
769 (*this->BuildFileStream ) << obj << "\">\n";
770 this->WriteString("<Filter>Object Libraries</Filter>\n", 3);
771 this->WriteString("</Object>\n", 2);
773 this->WriteString("</ItemGroup>\n", 1);
776 this->WriteString("<ItemGroup>\n", 1);
777 for(std::set<cmSourceGroup*>::iterator g = groupsUsed.begin();
778 g != groupsUsed.end(); ++g)
780 cmSourceGroup* sg = *g;
781 const char* name = sg->GetFullName();
782 if(strlen(name) != 0)
784 this->WriteString("<Filter Include=\"", 2);
785 (*this->BuildFileStream) << name << "\">\n";
786 std::string guidName = "SG_Filter_";
788 this->GlobalGenerator->CreateGUID(guidName.c_str());
789 this->WriteString("<UniqueIdentifier>", 3);
791 = this->GlobalGenerator->GetGUID(guidName.c_str());
792 (*this->BuildFileStream)
795 << "</UniqueIdentifier>\n";
796 this->WriteString("</Filter>\n", 2);
801 this->WriteString("<Filter Include=\"Object Libraries\">\n", 2);
802 std::string guidName = "SG_Filter_Object Libraries";
803 this->GlobalGenerator->CreateGUID(guidName.c_str());
804 this->WriteString("<UniqueIdentifier>", 3);
806 this->GlobalGenerator->GetGUID(guidName.c_str());
807 (*this->BuildFileStream) << "{" << guid << "}"
808 << "</UniqueIdentifier>\n";
809 this->WriteString("</Filter>\n", 2);
812 if(!this->GeneratorTarget->ResxSources.empty())
814 this->WriteString("<Filter Include=\"Resource Files\">\n", 2);
815 std::string guidName = "SG_Filter_Resource Files";
816 this->GlobalGenerator->CreateGUID(guidName.c_str());
817 this->WriteString("<UniqueIdentifier>", 3);
819 this->GlobalGenerator->GetGUID(guidName.c_str());
820 (*this->BuildFileStream) << "{" << guid << "}"
821 << "</UniqueIdentifier>\n";
822 this->WriteString("<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;", 3);
823 (*this->BuildFileStream) << "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;";
824 (*this->BuildFileStream) << "mfcribbon-ms</Extensions>\n";
825 this->WriteString("</Filter>\n", 2);
828 this->WriteString("</ItemGroup>\n", 1);
829 this->WriteString("</Project>\n", 0);
830 // restore stream pointer
831 this->BuildFileStream = save;
835 this->GlobalGenerator->FileReplacedDuringGenerate(path);
839 // Add to groupsUsed empty source groups that have non-empty children.
841 cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
842 std::set<cmSourceGroup*>& groupsUsed,
843 const std::vector<cmSourceGroup>& allGroups
846 for(std::vector<cmSourceGroup>::const_iterator current = allGroups.begin();
847 current != allGroups.end(); ++current)
849 std::vector<cmSourceGroup> const& children = current->GetGroupChildren();
852 continue; // the group is really empty
855 this->AddMissingSourceGroups(groupsUsed, children);
857 cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(&(*current));
858 if(groupsUsed.find(current_ptr) != groupsUsed.end())
860 continue; // group has already been added to set
863 // check if it least one of the group's descendants is not empty
864 // (at least one child must already have been added)
865 std::vector<cmSourceGroup>::const_iterator child_it = children.begin();
866 while(child_it != children.end())
868 cmSourceGroup* child_ptr = const_cast<cmSourceGroup*>(&(*child_it));
869 if(groupsUsed.find(child_ptr) != groupsUsed.end())
871 break; // found a child that was already added => add current group too
876 if(child_it == children.end())
878 continue; // no descendants have source files => ignore this group
881 groupsUsed.insert(current_ptr);
886 cmVisualStudio10TargetGenerator::
887 WriteGroupSources(const char* name,
888 ToolSources const& sources,
889 std::vector<cmSourceGroup>& sourceGroups)
891 this->WriteString("<ItemGroup>\n", 1);
892 for(ToolSources::const_iterator s = sources.begin();
893 s != sources.end(); ++s)
895 cmSourceFile* sf = s->SourceFile;
896 std::string const& source = sf->GetFullPath();
897 cmSourceGroup& sourceGroup =
898 this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
899 const char* filter = sourceGroup.GetFullName();
900 this->WriteString("<", 2);
901 std::string path = this->ConvertPath(source, s->RelativePath);
902 this->ConvertToWindowsSlash(path);
903 (*this->BuildFileStream) << name << " Include=\""
907 (*this->BuildFileStream) << "\">\n";
908 this->WriteString("<Filter>", 3);
909 (*this->BuildFileStream) << filter << "</Filter>\n";
910 this->WriteString("</", 2);
911 (*this->BuildFileStream) << name << ">\n";
915 (*this->BuildFileStream) << "\" />\n";
918 this->WriteString("</ItemGroup>\n", 1);
921 void cmVisualStudio10TargetGenerator::WriteSource(
922 const char* tool, cmSourceFile* sf, const char* end)
924 // Visual Studio tools append relative paths to the current dir, as in:
926 // c:\path\to\current\dir\..\..\..\relative\path\to\source.c
928 // and fail if this exceeds the maximum allowed path length. Our path
929 // conversion uses full paths outside the build tree to allow deeper trees.
930 bool forceRelative = false;
931 std::string sourceFile = this->ConvertPath(sf->GetFullPath(), false);
932 if(this->LocalGenerator->GetVersion() == cmLocalVisualStudioGenerator::VS10
933 && cmSystemTools::FileIsFullPath(sourceFile.c_str()))
935 // Normal path conversion resulted in a full path. VS 10 (but not 11)
936 // refuses to show the property page in the IDE for a source file with a
937 // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a
938 // relative path but to allow deeper build trees CMake 2.8.[5678] used a
939 // full path except for custom commands. Custom commands do not work
940 // without a relative path, but they do not seem to be involved in tools
941 // with the above behavior. For other sources we now use a relative path
942 // when the combined path will not be too long so property pages appear.
943 std::string sourceRel = this->ConvertPath(sf->GetFullPath(), true);
944 size_t const maxLen = 250;
945 if(sf->GetCustomCommand() ||
946 ((strlen(this->Makefile->GetCurrentOutputDirectory()) + 1 +
947 sourceRel.length()) <= maxLen))
949 forceRelative = true;
950 sourceFile = sourceRel;
954 this->GlobalGenerator->PathTooLong(this->Target, sf, sourceRel);
957 this->ConvertToWindowsSlash(sourceFile);
958 this->WriteString("<", 2);
959 (*this->BuildFileStream ) << tool << " Include=\"" << sourceFile << "\"";
961 if(sf->GetExtension() == "h" &&
962 this->IsResxHeader(sf->GetFullPath()))
964 (*this->BuildFileStream ) << ">\n";
965 this->WriteString("<FileType>CppForm</FileType>\n", 3);
966 this->WriteString("</ClInclude>\n", 2);
970 (*this->BuildFileStream ) << (end? end : " />\n");
973 ToolSource toolSource = {sf, forceRelative};
974 this->Tools[tool].push_back(toolSource);
977 void cmVisualStudio10TargetGenerator::WriteSources(
978 const char* tool, std::vector<cmSourceFile*> const& sources)
980 for(std::vector<cmSourceFile*>::const_iterator
981 si = sources.begin(); si != sources.end(); ++si)
983 this->WriteSource(tool, *si);
987 void cmVisualStudio10TargetGenerator::WriteAllSources()
989 if(this->Target->GetType() > cmTarget::UTILITY)
993 this->WriteString("<ItemGroup>\n", 1);
995 this->WriteSources("ClInclude", this->GeneratorTarget->HeaderSources);
996 this->WriteSources("Midl", this->GeneratorTarget->IDLSources);
998 for(std::vector<cmSourceFile*>::const_iterator
999 si = this->GeneratorTarget->ObjectSources.begin();
1000 si != this->GeneratorTarget->ObjectSources.end(); ++si)
1002 const char* lang = (*si)->GetLanguage();
1003 const char* tool = NULL;
1004 if (strcmp(lang, "C") == 0 || strcmp(lang, "CXX") == 0)
1008 else if (strcmp(lang, "ASM_MASM") == 0 &&
1009 this->GlobalGenerator->IsMasmEnabled())
1013 else if (strcmp(lang, "RC") == 0)
1015 tool = "ResourceCompile";
1020 this->WriteSource(tool, *si, " ");
1021 if (this->OutputSourceSpecificFlags(*si))
1023 this->WriteString("</", 2);
1024 (*this->BuildFileStream ) << tool << ">\n";
1028 (*this->BuildFileStream ) << " />\n";
1033 this->WriteSource("None", *si);
1037 if(this->LocalGenerator->GetVersion() > cmLocalVisualStudioGenerator::VS10)
1039 // For VS >= 11 we use LinkObjects to avoid linking custom command
1040 // outputs. Use Object for all external objects, generated or not.
1041 this->WriteSources("Object", this->GeneratorTarget->ExternalObjects);
1045 // If an object file is generated in this target, then vs10 will use
1046 // it in the build, and we have to list it as None instead of Object.
1047 for(std::vector<cmSourceFile*>::const_iterator
1048 si = this->GeneratorTarget->ExternalObjects.begin();
1049 si != this->GeneratorTarget->ExternalObjects.end(); ++si)
1051 std::vector<cmSourceFile*> const* d=this->Target->GetSourceDepends(*si);
1052 this->WriteSource((d && !d->empty())? "None":"Object", *si);
1056 this->WriteSources("None", this->GeneratorTarget->ExtraSources);
1058 // Add object library contents as external objects.
1059 std::vector<std::string> objs;
1060 this->GeneratorTarget->UseObjectLibraries(objs);
1061 for(std::vector<std::string>::const_iterator
1062 oi = objs.begin(); oi != objs.end(); ++oi)
1064 std::string obj = *oi;
1065 this->WriteString("<Object Include=\"", 2);
1066 this->ConvertToWindowsSlash(obj);
1067 (*this->BuildFileStream ) << obj << "\" />\n";
1070 this->WriteString("</ItemGroup>\n", 1);
1073 bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
1074 cmSourceFile* source)
1076 cmSourceFile& sf = *source;
1078 std::string objectName;
1079 if(this->GeneratorTarget->ExplicitObjectName.find(&sf)
1080 != this->GeneratorTarget->ExplicitObjectName.end())
1082 objectName = this->GeneratorTarget->Objects[&sf];
1085 std::string defines;
1086 if(const char* cflags = sf.GetProperty("COMPILE_FLAGS"))
1090 if(const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS"))
1095 this->GlobalGenerator->GetLanguageFromExtension
1096 (sf.GetExtension().c_str());
1097 const char* sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
1098 const char* linkLanguage = this->Target->GetLinkerLanguage();
1099 bool needForceLang = false;
1100 // source file does not match its extension language
1101 if(lang && sourceLang && strcmp(lang, sourceLang) != 0)
1103 needForceLang = true;
1106 // if the source file does not match the linker language
1107 // then force c or c++
1108 if(needForceLang || (linkLanguage && lang
1109 && strcmp(lang, linkLanguage) != 0))
1111 if(strcmp(lang, "CXX") == 0)
1113 // force a C++ file type
1116 else if(strcmp(lang, "C") == 0)
1122 bool hasFlags = false;
1123 // for the first time we need a new line if there is something
1125 const char* firstString = ">\n";
1126 if(objectName.size())
1128 (*this->BuildFileStream ) << firstString;
1131 this->WriteString("<ObjectFileName>", 3);
1132 (*this->BuildFileStream )
1133 << "$(IntDir)/" << objectName << "</ObjectFileName>\n";
1135 std::vector<std::string> *configs =
1136 static_cast<cmGlobalVisualStudio7Generator *>
1137 (this->GlobalGenerator)->GetConfigurations();
1138 for( std::vector<std::string>::iterator config = configs->begin();
1139 config != configs->end(); ++config)
1141 std::string configUpper = cmSystemTools::UpperCase(*config);
1142 std::string configDefines = defines;
1143 std::string defPropName = "COMPILE_DEFINITIONS_";
1144 defPropName += configUpper;
1145 if(const char* ccdefs = sf.GetProperty(defPropName.c_str()))
1147 if(configDefines.size())
1149 configDefines += ";";
1151 configDefines += ccdefs;
1153 // if we have flags or defines for this config then
1155 if(flags.size() || configDefines.size())
1157 (*this->BuildFileStream ) << firstString;
1158 firstString = ""; // only do firstString once
1160 cmVisualStudioGeneratorOptions
1161 clOptions(this->LocalGenerator,
1162 cmVisualStudioGeneratorOptions::Compiler,
1163 cmVSGetCLFlagTable(this->LocalGenerator), 0, this);
1164 clOptions.Parse(flags.c_str());
1165 clOptions.AddDefines(configDefines.c_str());
1166 clOptions.SetConfiguration((*config).c_str());
1167 clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
1168 clOptions.OutputFlagMap(*this->BuildFileStream, " ");
1169 clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream,
1177 void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
1179 cmTarget::TargetType ttype = this->Target->GetType();
1180 if(ttype > cmTarget::GLOBAL_TARGET)
1185 this->WriteString("<PropertyGroup>\n", 2);
1186 this->WriteString("<_ProjectFileVersion>10.0.20506.1"
1187 "</_ProjectFileVersion>\n", 3);
1188 std::vector<std::string> *configs =
1189 static_cast<cmGlobalVisualStudio7Generator *>
1190 (this->GlobalGenerator)->GetConfigurations();
1191 for(std::vector<std::string>::iterator config = configs->begin();
1192 config != configs->end(); ++config)
1194 if(ttype >= cmTarget::UTILITY)
1196 this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
1197 *this->BuildFileStream
1198 << "$(Platform)\\$(Configuration)\\$(ProjectName)\\"
1203 std::string intermediateDir = this->LocalGenerator->
1204 GetTargetDirectory(*this->Target);
1205 intermediateDir += "/";
1206 intermediateDir += *config;
1207 intermediateDir += "/";
1209 std::string targetNameFull;
1210 if(ttype == cmTarget::OBJECT_LIBRARY)
1212 outDir = intermediateDir;
1213 targetNameFull = this->Target->GetName();
1214 targetNameFull += ".lib";
1218 outDir = this->Target->GetDirectory(config->c_str()) + "/";
1219 targetNameFull = this->Target->GetFullName(config->c_str());
1221 this->ConvertToWindowsSlash(intermediateDir);
1222 this->ConvertToWindowsSlash(outDir);
1224 this->WritePlatformConfigTag("OutDir", config->c_str(), 3);
1225 *this->BuildFileStream << outDir
1228 this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
1229 *this->BuildFileStream << intermediateDir
1232 this->WritePlatformConfigTag("TargetName", config->c_str(), 3);
1233 *this->BuildFileStream
1234 << cmSystemTools::GetFilenameWithoutLastExtension(
1235 targetNameFull.c_str())
1236 << "</TargetName>\n";
1238 this->WritePlatformConfigTag("TargetExt", config->c_str(), 3);
1239 *this->BuildFileStream
1240 << cmSystemTools::GetFilenameLastExtension(targetNameFull.c_str())
1241 << "</TargetExt>\n";
1243 this->OutputLinkIncremental(*config);
1246 this->WriteString("</PropertyGroup>\n", 2);
1252 cmVisualStudio10TargetGenerator::
1253 OutputLinkIncremental(std::string const& configName)
1255 // static libraries and things greater than modules do not need
1256 // to set this option
1257 if(this->Target->GetType() == cmTarget::STATIC_LIBRARY
1258 || this->Target->GetType() > cmTarget::MODULE_LIBRARY)
1262 Options& linkOptions = *(this->LinkOptions[configName]);
1264 const char* incremental = linkOptions.GetFlag("LinkIncremental");
1265 this->WritePlatformConfigTag("LinkIncremental", configName.c_str(), 3);
1266 *this->BuildFileStream << (incremental?incremental:"true")
1267 << "</LinkIncremental>\n";
1268 linkOptions.RemoveFlag("LinkIncremental");
1270 const char* manifest = linkOptions.GetFlag("GenerateManifest");
1271 this->WritePlatformConfigTag("GenerateManifest", configName.c_str(), 3);
1272 *this->BuildFileStream << (manifest?manifest:"true")
1273 << "</GenerateManifest>\n";
1274 linkOptions.RemoveFlag("GenerateManifest");
1276 // Some link options belong here. Use them now and remove them so that
1277 // WriteLinkOptions does not use them.
1278 const char* flags[] = {
1282 for(const char** f = flags; *f; ++f)
1284 const char* flag = *f;
1285 if(const char* value = linkOptions.GetFlag(flag))
1287 this->WritePlatformConfigTag(flag, configName.c_str(), 3);
1288 *this->BuildFileStream << value << "</" << flag << ">\n";
1289 linkOptions.RemoveFlag(flag);
1294 //----------------------------------------------------------------------------
1295 bool cmVisualStudio10TargetGenerator::ComputeClOptions()
1297 std::vector<std::string> const* configs =
1298 this->GlobalGenerator->GetConfigurations();
1299 for(std::vector<std::string>::const_iterator i = configs->begin();
1300 i != configs->end(); ++i)
1302 if(!this->ComputeClOptions(*i))
1310 //----------------------------------------------------------------------------
1311 bool cmVisualStudio10TargetGenerator::ComputeClOptions(
1312 std::string const& configName)
1314 // much of this was copied from here:
1315 // copied from cmLocalVisualStudio7Generator.cxx 805
1316 // TODO: Integrate code below with cmLocalVisualStudio7Generator.
1318 cmsys::auto_ptr<Options> pOptions(
1319 new Options(this->LocalGenerator, Options::Compiler,
1320 cmVSGetCLFlagTable(this->LocalGenerator)));
1321 Options& clOptions = *pOptions;
1324 // collect up flags for
1325 if(this->Target->GetType() < cmTarget::UTILITY)
1327 const char* linkLanguage =
1328 this->Target->GetLinkerLanguage(configName.c_str());
1331 cmSystemTools::Error
1332 ("CMake can not determine linker language for target: ",
1333 this->Name.c_str());
1336 if(strcmp(linkLanguage, "C") == 0 || strcmp(linkLanguage, "CXX") == 0
1337 || strcmp(linkLanguage, "Fortran") == 0)
1339 std::string baseFlagVar = "CMAKE_";
1340 baseFlagVar += linkLanguage;
1341 baseFlagVar += "_FLAGS";
1343 Target->GetMakefile()->GetRequiredDefinition(baseFlagVar.c_str());
1344 std::string flagVar = baseFlagVar + std::string("_") +
1345 cmSystemTools::UpperCase(configName);
1348 Target->GetMakefile()->GetRequiredDefinition(flagVar.c_str());
1350 // set the correct language
1351 if(strcmp(linkLanguage, "C") == 0)
1355 if(strcmp(linkLanguage, "CXX") == 0)
1359 this->LocalGenerator->AddCompileOptions(flags, this->Target,
1360 linkLanguage, configName.c_str());
1363 // Get preprocessor definitions for this directory.
1364 std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags();
1365 clOptions.FixExceptionHandlingDefault();
1366 clOptions.AddFlag("PrecompiledHeader", "NotUsing");
1367 std::string asmLocation = configName + "/";
1368 clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str());
1369 clOptions.Parse(flags.c_str());
1370 clOptions.Parse(defineFlags.c_str());
1371 std::vector<std::string> targetDefines;
1372 this->Target->GetCompileDefinitions(targetDefines, configName.c_str());
1373 clOptions.AddDefines(targetDefines);
1374 clOptions.SetVerboseMakefile(
1375 this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
1377 // Add a definition for the configuration name.
1378 std::string configDefine = "CMAKE_INTDIR=\"";
1379 configDefine += configName;
1380 configDefine += "\"";
1381 clOptions.AddDefine(configDefine);
1382 if(const char* exportMacro = this->Target->GetExportMacro())
1384 clOptions.AddDefine(exportMacro);
1387 this->ClOptions[configName] = pOptions.release();
1391 //----------------------------------------------------------------------------
1392 void cmVisualStudio10TargetGenerator::WriteClOptions(
1393 std::string const& configName,
1394 std::vector<std::string> const& includes)
1396 Options& clOptions = *(this->ClOptions[configName]);
1397 this->WriteString("<ClCompile>\n", 2);
1398 clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
1399 this->OutputIncludes(includes);
1400 clOptions.OutputFlagMap(*this->BuildFileStream, " ");
1402 // If not in debug mode, write the DebugInformationFormat field
1403 // without value so PDBs don't get generated uselessly.
1404 if(!clOptions.IsDebug())
1406 this->WriteString("<DebugInformationFormat>"
1407 "</DebugInformationFormat>\n", 3);
1410 clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
1412 this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
1413 this->WriteString("</ClCompile>\n", 2);
1416 void cmVisualStudio10TargetGenerator::
1417 OutputIncludes(std::vector<std::string> const & includes)
1419 this->WriteString("<AdditionalIncludeDirectories>", 3);
1420 for(std::vector<std::string>::const_iterator i = includes.begin();
1421 i != includes.end(); ++i)
1423 std::string incDir = *i;
1424 this->ConvertToWindowsSlash(incDir);
1425 *this->BuildFileStream << cmVS10EscapeXML(incDir) << ";";
1427 this->WriteString("%(AdditionalIncludeDirectories)"
1428 "</AdditionalIncludeDirectories>\n", 0);
1433 void cmVisualStudio10TargetGenerator::
1434 WriteRCOptions(std::string const& configName,
1435 std::vector<std::string> const & includes)
1437 this->WriteString("<ResourceCompile>\n", 2);
1438 Options& clOptions = *(this->ClOptions[configName]);
1439 clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
1441 this->OutputIncludes(includes);
1442 this->WriteString("</ResourceCompile>\n", 2);
1447 cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const& config)
1449 if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
1453 std::string libflags;
1454 this->LocalGenerator->GetStaticLibraryFlags(libflags,
1455 cmSystemTools::UpperCase(config), this->Target);
1456 if(!libflags.empty())
1458 this->WriteString("<Lib>\n", 2);
1459 cmVisualStudioGeneratorOptions
1460 libOptions(this->LocalGenerator,
1461 cmVisualStudioGeneratorOptions::Linker,
1462 cmVSGetLibFlagTable(this->LocalGenerator), 0, this);
1463 libOptions.Parse(libflags.c_str());
1464 libOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
1465 libOptions.OutputFlagMap(*this->BuildFileStream, " ");
1466 this->WriteString("</Lib>\n", 2);
1470 //----------------------------------------------------------------------------
1471 bool cmVisualStudio10TargetGenerator::ComputeLinkOptions()
1473 if(this->Target->GetType() == cmTarget::EXECUTABLE ||
1474 this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
1475 this->Target->GetType() == cmTarget::MODULE_LIBRARY)
1477 std::vector<std::string> const* configs =
1478 this->GlobalGenerator->GetConfigurations();
1479 for(std::vector<std::string>::const_iterator i = configs->begin();
1480 i != configs->end(); ++i)
1482 if(!this->ComputeLinkOptions(*i))
1491 //----------------------------------------------------------------------------
1493 cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config)
1495 cmsys::auto_ptr<Options> pOptions(
1496 new Options(this->LocalGenerator, Options::Linker,
1497 cmVSGetLinkFlagTable(this->LocalGenerator), 0, this));
1498 Options& linkOptions = *pOptions;
1500 const char* linkLanguage =
1501 this->Target->GetLinkerLanguage(config.c_str());
1504 cmSystemTools::Error
1505 ("CMake can not determine linker language for target: ",
1506 this->Name.c_str());
1510 std::string CONFIG = cmSystemTools::UpperCase(config);
1512 const char* linkType = "SHARED";
1513 if(this->Target->GetType() == cmTarget::MODULE_LIBRARY)
1515 linkType = "MODULE";
1517 if(this->Target->GetType() == cmTarget::EXECUTABLE)
1521 std::string stackVar = "CMAKE_";
1522 stackVar += linkLanguage;
1523 stackVar += "_STACK_SIZE";
1524 const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
1528 flags += " /STACK:";
1531 std::string linkFlagVarBase = "CMAKE_";
1532 linkFlagVarBase += linkType;
1533 linkFlagVarBase += "_LINKER_FLAGS";
1536 Target->GetMakefile()->GetRequiredDefinition(linkFlagVarBase.c_str());
1537 std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
1540 Target->GetMakefile()->GetRequiredDefinition(linkFlagVar.c_str());
1541 const char* targetLinkFlags = this->Target->GetProperty("LINK_FLAGS");
1545 flags += targetLinkFlags;
1547 std::string flagsProp = "LINK_FLAGS_";
1548 flagsProp += CONFIG;
1549 if(const char* flagsConfig = this->Target->GetProperty(flagsProp.c_str()))
1552 flags += flagsConfig;
1554 if ( this->Target->GetPropertyAsBool("WIN32_EXECUTABLE") )
1556 linkOptions.AddFlag("SubSystem", "Windows");
1560 linkOptions.AddFlag("SubSystem", "Console");
1562 std::string standardLibsVar = "CMAKE_";
1563 standardLibsVar += linkLanguage;
1564 standardLibsVar += "_STANDARD_LIBRARIES";
1566 libs = this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
1567 // Remove trailing spaces from libs
1568 std::string::size_type pos = libs.size()-1;
1569 if(libs.size() != 0)
1571 while(libs[pos] == ' ')
1576 if(pos != libs.size()-1)
1578 libs = libs.substr(0, pos+1);
1580 // Replace spaces in libs with ;
1581 cmSystemTools::ReplaceString(libs, " ", ";");
1582 cmComputeLinkInformation* pcli =
1583 this->Target->GetLinkInformation(config.c_str());
1586 cmSystemTools::Error
1587 ("CMake can not compute cmComputeLinkInformation for target: ",
1588 this->Name.c_str());
1591 // add the libraries for the target to libs string
1592 cmComputeLinkInformation& cli = *pcli;
1593 this->AddLibraries(cli, libs);
1594 linkOptions.AddFlag("AdditionalDependencies", libs.c_str());
1596 std::vector<std::string> const& ldirs = cli.GetDirectories();
1597 const char* sep = "";
1598 std::string linkDirs;
1599 for(std::vector<std::string>::const_iterator d = ldirs.begin();
1600 d != ldirs.end(); ++d)
1602 // first just full path
1607 // next path with configuration type Debug, Release, etc
1609 linkDirs += "/$(Configuration)";
1612 linkDirs += "%(AdditionalLibraryDirectories)";
1613 linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs.c_str());
1614 linkOptions.AddFlag("AdditionalDependencies", libs.c_str());
1615 linkOptions.AddFlag("Version", "");
1616 if(linkOptions.IsDebug() || flags.find("/debug") != flags.npos)
1618 linkOptions.AddFlag("GenerateDebugInformation", "true");
1622 linkOptions.AddFlag("GenerateDebugInformation", "false");
1624 std::string targetName;
1625 std::string targetNameSO;
1626 std::string targetNameFull;
1627 std::string targetNameImport;
1628 std::string targetNamePDB;
1629 if(this->Target->GetType() == cmTarget::EXECUTABLE)
1631 this->Target->GetExecutableNames(targetName, targetNameFull,
1632 targetNameImport, targetNamePDB,
1637 this->Target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
1638 targetNameImport, targetNamePDB,
1642 std::string pdb = this->Target->GetPDBDirectory(config.c_str());
1644 pdb += targetNamePDB;
1645 std::string imLib = this->Target->GetDirectory(config.c_str(), true);
1647 imLib += targetNameImport;
1649 linkOptions.AddFlag("ImportLibrary", imLib.c_str());
1650 linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str());
1651 linkOptions.Parse(flags.c_str());
1652 if(!this->GeneratorTarget->ModuleDefinitionFile.empty())
1654 linkOptions.AddFlag("ModuleDefinitionFile",
1655 this->GeneratorTarget->ModuleDefinitionFile.c_str());
1658 this->LinkOptions[config] = pOptions.release();
1662 //----------------------------------------------------------------------------
1664 cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const& config)
1666 if(this->Target->GetType() == cmTarget::STATIC_LIBRARY
1667 || this->Target->GetType() > cmTarget::MODULE_LIBRARY)
1671 Options& linkOptions = *(this->LinkOptions[config]);
1672 this->WriteString("<Link>\n", 2);
1674 linkOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
1675 linkOptions.OutputFlagMap(*this->BuildFileStream, " ");
1677 this->WriteString("</Link>\n", 2);
1678 if(!this->GlobalGenerator->NeedLinkLibraryDependencies(*this->Target))
1680 this->WriteString("<ProjectReference>\n", 2);
1682 " <LinkLibraryDependencies>false</LinkLibraryDependencies>\n", 2);
1683 this->WriteString("</ProjectReference>\n", 2);
1687 void cmVisualStudio10TargetGenerator::AddLibraries(
1688 cmComputeLinkInformation& cli,
1689 std::string& libstring)
1691 typedef cmComputeLinkInformation::ItemVector ItemVector;
1692 ItemVector libs = cli.GetItems();
1693 const char* sep = ";";
1694 for(ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l)
1698 std::string path = this->LocalGenerator->
1699 Convert(l->Value.c_str(),
1700 cmLocalGenerator::START_OUTPUT,
1701 cmLocalGenerator::UNCHANGED);
1702 this->ConvertToWindowsSlash(path);
1709 libstring += l->Value;
1715 void cmVisualStudio10TargetGenerator::
1716 WriteMidlOptions(std::string const& /*config*/,
1717 std::vector<std::string> const & includes)
1719 // This processes *any* of the .idl files specified in the project's file
1720 // list (and passed as the item metadata %(Filename) expressing the rule
1721 // input filename) into output files at the per-config *build* dir
1722 // ($(IntDir)) each.
1724 // IOW, this MIDL section is intended to provide a fully generic syntax
1725 // content suitable for most cases (read: if you get errors, then it's quite
1726 // probable that the error is on your side of the .idl setup).
1728 // Also, note that the marked-as-generated _i.c file in the Visual Studio
1729 // generator case needs to be referred to as $(IntDir)\foo_i.c at the
1730 // project's file list, otherwise the compiler-side processing won't pick it
1731 // up (for non-directory form, it ends up looking in project binary dir
1732 // only). Perhaps there's something to be done to make this more automatic
1733 // on the CMake side?
1734 this->WriteString("<Midl>\n", 2);
1735 this->OutputIncludes(includes);
1736 this->WriteString("<OutputDirectory>$(IntDir)</OutputDirectory>\n", 3);
1737 this->WriteString("<HeaderFileName>%(Filename).h</HeaderFileName>\n", 3);
1739 "<TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n", 3);
1741 "<InterfaceIdentifierFileName>"
1742 "%(Filename)_i.c</InterfaceIdentifierFileName>\n", 3);
1743 this->WriteString("<ProxyFileName>%(Filename)_p.c</ProxyFileName>\n",3);
1744 this->WriteString("</Midl>\n", 2);
1748 void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
1750 std::vector<std::string> *configs =
1751 static_cast<cmGlobalVisualStudio7Generator *>
1752 (this->GlobalGenerator)->GetConfigurations();
1753 for(std::vector<std::string>::iterator i = configs->begin();
1754 i != configs->end(); ++i)
1756 std::vector<std::string> includes;
1757 this->LocalGenerator->GetIncludeDirectories(includes,
1758 this->GeneratorTarget,
1760 this->WritePlatformConfigTag("ItemDefinitionGroup", i->c_str(), 1);
1761 *this->BuildFileStream << "\n";
1762 // output cl compile flags <ClCompile></ClCompile>
1763 if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
1765 this->WriteClOptions(*i, includes);
1766 // output rc compile flags <ResourceCompile></ResourceCompile>
1767 this->WriteRCOptions(*i, includes);
1769 // output midl flags <Midl></Midl>
1770 this->WriteMidlOptions(*i, includes);
1772 this->WriteEvents(*i);
1773 // output link flags <Link></Link>
1774 this->WriteLinkOptions(*i);
1775 // output lib flags <Lib></Lib>
1776 this->WriteLibOptions(*i);
1777 this->WriteString("</ItemDefinitionGroup>\n", 1);
1782 cmVisualStudio10TargetGenerator::WriteEvents(std::string const& configName)
1784 this->WriteEvent("PreLinkEvent",
1785 this->Target->GetPreLinkCommands(), configName);
1786 this->WriteEvent("PreBuildEvent",
1787 this->Target->GetPreBuildCommands(), configName);
1788 this->WriteEvent("PostBuildEvent",
1789 this->Target->GetPostBuildCommands(), configName);
1792 void cmVisualStudio10TargetGenerator::WriteEvent(
1794 std::vector<cmCustomCommand> & commands,
1795 std::string const& configName)
1797 if(commands.size() == 0)
1801 this->WriteString("<", 2);
1802 (*this->BuildFileStream ) << name << ">\n";
1803 cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
1805 const char* pre = "";
1806 std::string comment;
1807 for(std::vector<cmCustomCommand>::iterator i = commands.begin();
1808 i != commands.end(); ++i)
1810 cmCustomCommand& command = *i;
1812 comment += lg->ConstructComment(command);
1816 cmVS10EscapeXML(lg->ConstructScript(command, configName.c_str()));
1818 comment = cmVS10EscapeComment(comment);
1819 this->WriteString("<Message>",3);
1820 (*this->BuildFileStream ) << cmVS10EscapeXML(comment) << "</Message>\n";
1821 this->WriteString("<Command>", 3);
1822 (*this->BuildFileStream ) << script;
1823 (*this->BuildFileStream ) << "</Command>" << "\n";
1824 this->WriteString("</", 2);
1825 (*this->BuildFileStream ) << name << ">\n";
1829 void cmVisualStudio10TargetGenerator::WriteProjectReferences()
1831 cmGlobalGenerator::TargetDependSet const& unordered
1832 = this->GlobalGenerator->GetTargetDirectDepends(*this->Target);
1833 typedef cmGlobalVisualStudioGenerator::OrderedTargetDependSet
1834 OrderedTargetDependSet;
1835 OrderedTargetDependSet depends(unordered);
1836 this->WriteString("<ItemGroup>\n", 1);
1837 for( OrderedTargetDependSet::const_iterator i = depends.begin();
1838 i != depends.end(); ++i)
1841 // skip fortran targets as they can not be processed by MSBuild
1842 // the only reference will be in the .sln file
1843 if(static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
1844 ->TargetIsFortranOnly(*dt))
1848 this->WriteString("<ProjectReference Include=\"", 2);
1849 cmMakefile* mf = dt->GetMakefile();
1850 std::string name = dt->GetName();
1852 const char* p = dt->GetProperty("EXTERNAL_MSPROJECT");
1859 path = mf->GetStartOutputDirectory();
1861 path += dt->GetName();
1864 (*this->BuildFileStream) << path << "\">\n";
1865 this->WriteString("<Project>", 3);
1866 (*this->BuildFileStream)
1867 << this->GlobalGenerator->GetGUID(name.c_str())
1869 this->WriteString("</ProjectReference>\n", 2);
1871 this->WriteString("</ItemGroup>\n", 1);
1874 bool cmVisualStudio10TargetGenerator::
1875 IsResxHeader(const std::string& headerFile)
1877 std::set<std::string>::iterator it =
1878 this->GeneratorTarget->ExpectedResxHeaders.find(headerFile);
1880 return it != this->GeneratorTarget->ExpectedResxHeaders.end();