Imported Upstream version 2.8.11.2
[platform/upstream/cmake.git] / Source / cmGlobalVisualStudio8Generator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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 "windows.h" // this must be first to define GetCurrentDirectory
13 #include "cmGlobalVisualStudio8Generator.h"
14 #include "cmLocalVisualStudio7Generator.h"
15 #include "cmMakefile.h"
16 #include "cmVisualStudioWCEPlatformParser.h"
17 #include "cmake.h"
18 #include "cmGeneratedFileStream.h"
19
20 static const char vs8generatorName[] = "Visual Studio 8 2005";
21
22 class cmGlobalVisualStudio8Generator::Factory
23   : public cmGlobalGeneratorFactory
24 {
25 public:
26   virtual cmGlobalGenerator* CreateGlobalGenerator(const char* name) const {
27     if(strstr(name, vs8generatorName) != name)
28       {
29       return 0;
30       }
31
32     const char* p = name + sizeof(vs8generatorName) - 1;
33     if(p[0] == '\0')
34       {
35       return new cmGlobalVisualStudio8Generator(
36         name, NULL, NULL);
37       }
38
39     if(p[0] != ' ')
40       {
41       return 0;
42       }
43
44     ++p;
45
46     if(!strcmp(p, "Win64"))
47       {
48       return new cmGlobalVisualStudio8Generator(
49         name, "x64", "CMAKE_FORCE_WIN64");
50       }
51
52     cmVisualStudioWCEPlatformParser parser(p);
53     parser.ParseVersion("8.0");
54     if (!parser.Found())
55       {
56       return 0;
57       }
58
59     cmGlobalVisualStudio8Generator* ret = new cmGlobalVisualStudio8Generator(
60       name, parser.GetArchitectureFamily(), NULL);
61     ret->PlatformName = p;
62     ret->WindowsCEVersion = parser.GetOSVersion();
63     return ret;
64   }
65
66   virtual void GetDocumentation(cmDocumentationEntry& entry) const {
67     entry.Name = vs8generatorName;
68     entry.Brief = "Generates Visual Studio 8 2005 project files.";
69     entry.Full =
70       "It is possible to append a space followed by the platform name "
71       "to create project files for a specific target platform. E.g. "
72       "\"Visual Studio 8 2005 Win64\" will create project files for "
73       "the x64 processor.";
74   }
75
76   virtual void GetGenerators(std::vector<std::string>& names) const {
77     names.push_back(vs8generatorName);
78     names.push_back(vs8generatorName + std::string(" Win64"));
79     cmVisualStudioWCEPlatformParser parser;
80     parser.ParseVersion("8.0");
81     const std::vector<std::string>& availablePlatforms =
82       parser.GetAvailablePlatforms();
83     for(std::vector<std::string>::const_iterator i =
84         availablePlatforms.begin(); i != availablePlatforms.end(); ++i)
85       {
86       names.push_back("Visual Studio 8 2005 " + *i);
87       }
88   }
89 };
90
91 //----------------------------------------------------------------------------
92 cmGlobalGeneratorFactory* cmGlobalVisualStudio8Generator::NewFactory()
93 {
94   return new Factory;
95 }
96
97 //----------------------------------------------------------------------------
98 cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator(
99   const char* name, const char* architectureId,
100   const char* additionalPlatformDefinition)
101 {
102   this->FindMakeProgramFile = "CMakeVS8FindMake.cmake";
103   this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms";
104   this->Name = name;
105   if (architectureId)
106     {
107     this->ArchitectureId = architectureId;
108     }
109   if (additionalPlatformDefinition)
110     {
111     this->AdditionalPlatformDefinition = additionalPlatformDefinition;
112     }
113 }
114
115 //----------------------------------------------------------------------------
116 const char* cmGlobalVisualStudio8Generator::GetPlatformName() const
117 {
118   if (!this->PlatformName.empty())
119     {
120     return this->PlatformName.c_str();
121     }
122   if (this->ArchitectureId == "X86")
123     {
124     return "Win32";
125     }
126   return this->ArchitectureId.c_str();
127 }
128
129 //----------------------------------------------------------------------------
130 ///! Create a local generator appropriate to this Global Generator
131 cmLocalGenerator *cmGlobalVisualStudio8Generator::CreateLocalGenerator()
132 {
133   cmLocalVisualStudio7Generator *lg =
134     new cmLocalVisualStudio7Generator(cmLocalVisualStudioGenerator::VS8);
135   lg->SetPlatformName(this->GetPlatformName());
136   lg->SetExtraFlagTable(this->GetExtraFlagTableVS8());
137   lg->SetGlobalGenerator(this);
138   return lg;
139 }
140
141 //----------------------------------------------------------------------------
142 void cmGlobalVisualStudio8Generator::AddPlatformDefinitions(cmMakefile* mf)
143 {
144   cmGlobalVisualStudio71Generator::AddPlatformDefinitions(mf);
145   mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName());
146
147   if(this->TargetsWindowsCE())
148   {
149     mf->AddDefinition("CMAKE_VS_WINCE_VERSION",
150       this->WindowsCEVersion.c_str());
151   }
152 }
153
154 //----------------------------------------------------------------------------
155 // ouput standard header for dsw file
156 void cmGlobalVisualStudio8Generator::WriteSLNHeader(std::ostream& fout)
157 {
158   fout << "Microsoft Visual Studio Solution File, Format Version 9.00\n";
159   fout << "# Visual Studio 2005\n";
160 }
161
162 //----------------------------------------------------------------------------
163 void cmGlobalVisualStudio8Generator
164 ::GetDocumentation(cmDocumentationEntry& entry)
165 {
166   entry.Name = cmGlobalVisualStudio8Generator::GetActualName();
167   entry.Brief = "Generates Visual Studio 8 2005 project files.";
168   entry.Full = "";
169 }
170
171 //----------------------------------------------------------------------------
172 void cmGlobalVisualStudio8Generator::Configure()
173 {
174   this->cmGlobalVisualStudio7Generator::Configure();
175   this->CreateGUID(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
176 }
177
178 //----------------------------------------------------------------------------
179 std::string cmGlobalVisualStudio8Generator::GetUserMacrosDirectory()
180 {
181   // Some VS8 sp0 versions cannot run macros.
182   // See http://support.microsoft.com/kb/928209
183   const char* vc8sp1Registry =
184     "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\"
185     "InstalledProducts\\KB926601;";
186   const char* vc8exSP1Registry =
187     "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\"
188     "InstalledProducts\\KB926748;";
189   std::string vc8sp1;
190   if (!cmSystemTools::ReadRegistryValue(vc8sp1Registry, vc8sp1) &&
191       !cmSystemTools::ReadRegistryValue(vc8exSP1Registry, vc8sp1))
192     {
193     return "";
194     }
195
196   std::string base;
197   std::string path;
198
199   // base begins with the VisualStudioProjectsLocation reg value...
200   if (cmSystemTools::ReadRegistryValue(
201     "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\8.0;"
202     "VisualStudioProjectsLocation",
203     base))
204     {
205     cmSystemTools::ConvertToUnixSlashes(base);
206
207     // 8.0 macros folder:
208     path = base + "/VSMacros80";
209     }
210
211   // path is (correctly) still empty if we did not read the base value from
212   // the Registry value
213   return path;
214 }
215
216 //----------------------------------------------------------------------------
217 std::string cmGlobalVisualStudio8Generator::GetUserMacrosRegKeyBase()
218 {
219   return "Software\\Microsoft\\VisualStudio\\8.0\\vsmacros";
220 }
221
222 //----------------------------------------------------------------------------
223 void cmGlobalVisualStudio8Generator::AddCheckTarget()
224 {
225   // Add a special target on which all other targets depend that
226   // checks the build system and optionally re-runs CMake.
227   const char* no_working_directory = 0;
228   std::vector<std::string> no_depends;
229   std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators;
230   cmLocalVisualStudio7Generator* lg =
231     static_cast<cmLocalVisualStudio7Generator*>(generators[0]);
232   cmMakefile* mf = lg->GetMakefile();
233
234   // Skip the target if no regeneration is to be done.
235   if(mf->IsOn("CMAKE_SUPPRESS_REGENERATION"))
236     {
237     return;
238     }
239
240   std::string cmake_command = mf->GetRequiredDefinition("CMAKE_COMMAND");
241   cmCustomCommandLines noCommandLines;
242   cmTarget* tgt =
243     mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
244                           no_working_directory, no_depends,
245                           noCommandLines);
246
247   // Organize in the "predefined targets" folder:
248   //
249   if (this->UseFolderProperty())
250     {
251     tgt->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
252     }
253
254   // Create a list of all stamp files for this project.
255   std::vector<std::string> stamps;
256   std::string stampList = cmake::GetCMakeFilesDirectoryPostSlash();
257   stampList += "generate.stamp.list";
258   {
259   std::string stampListFile =
260     generators[0]->GetMakefile()->GetCurrentOutputDirectory();
261   stampListFile += "/";
262   stampListFile += stampList;
263   std::string stampFile;
264   cmGeneratedFileStream fout(stampListFile.c_str());
265   for(std::vector<cmLocalGenerator*>::const_iterator
266         gi = generators.begin(); gi != generators.end(); ++gi)
267     {
268     stampFile = (*gi)->GetMakefile()->GetCurrentOutputDirectory();
269     stampFile += "/";
270     stampFile += cmake::GetCMakeFilesDirectoryPostSlash();
271     stampFile += "generate.stamp";
272     fout << stampFile << "\n";
273     stamps.push_back(stampFile);
274     }
275   }
276
277   // Add a custom rule to re-run CMake if any input files changed.
278   {
279   // Collect the input files used to generate all targets in this
280   // project.
281   std::vector<std::string> listFiles;
282   for(unsigned int j = 0; j < generators.size(); ++j)
283     {
284     cmMakefile* lmf = generators[j]->GetMakefile();
285     listFiles.insert(listFiles.end(), lmf->GetListFiles().begin(),
286                      lmf->GetListFiles().end());
287     }
288   // Sort the list of input files and remove duplicates.
289   std::sort(listFiles.begin(), listFiles.end(),
290             std::less<std::string>());
291   std::vector<std::string>::iterator new_end =
292     std::unique(listFiles.begin(), listFiles.end());
293   listFiles.erase(new_end, listFiles.end());
294
295   // Create a rule to re-run CMake.
296   std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash();
297   stampName += "generate.stamp";
298   const char* dsprule = mf->GetRequiredDefinition("CMAKE_COMMAND");
299   cmCustomCommandLine commandLine;
300   commandLine.push_back(dsprule);
301   std::string argH = "-H";
302   argH += lg->Convert(mf->GetHomeDirectory(),
303                       cmLocalGenerator::START_OUTPUT,
304                       cmLocalGenerator::UNCHANGED, true);
305   commandLine.push_back(argH);
306   std::string argB = "-B";
307   argB += lg->Convert(mf->GetHomeOutputDirectory(),
308                       cmLocalGenerator::START_OUTPUT,
309                       cmLocalGenerator::UNCHANGED, true);
310   commandLine.push_back(argB);
311   commandLine.push_back("--check-stamp-list");
312   commandLine.push_back(stampList.c_str());
313   commandLine.push_back("--vs-solution-file");
314   commandLine.push_back("\"$(SolutionPath)\"");
315   cmCustomCommandLines commandLines;
316   commandLines.push_back(commandLine);
317
318   // Add the rule.  Note that we cannot use the CMakeLists.txt
319   // file as the main dependency because it would get
320   // overwritten by the CreateVCProjBuildRule.
321   // (this could be avoided with per-target source files)
322   const char* no_main_dependency = 0;
323   if(cmSourceFile* file =
324      mf->AddCustomCommandToOutput(
325        stamps, listFiles,
326        no_main_dependency, commandLines, "Checking Build System",
327        no_working_directory, true))
328     {
329     tgt->AddSourceFile(file);
330     }
331   else
332     {
333     cmSystemTools::Error("Error adding rule for ", stamps[0].c_str());
334     }
335   }
336 }
337
338 //----------------------------------------------------------------------------
339 void cmGlobalVisualStudio8Generator::Generate()
340 {
341   this->AddCheckTarget();
342
343   // All targets depend on the build-system check target.
344   for(std::map<cmStdString,cmTarget *>::const_iterator
345         ti = this->TotalTargets.begin();
346       ti != this->TotalTargets.end(); ++ti)
347     {
348     if(ti->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET)
349       {
350       ti->second->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
351       }
352     }
353
354   // Now perform the main generation.
355   this->cmGlobalVisualStudio7Generator::Generate();
356 }
357
358 //----------------------------------------------------------------------------
359 void
360 cmGlobalVisualStudio8Generator
361 ::WriteSolutionConfigurations(std::ostream& fout)
362 {
363   fout << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n";
364   for(std::vector<std::string>::iterator i = this->Configurations.begin();
365       i != this->Configurations.end(); ++i)
366     {
367     fout << "\t\t" << *i << "|" << this->GetPlatformName()
368          << " = "  << *i << "|" << this->GetPlatformName() << "\n";
369     }
370   fout << "\tEndGlobalSection\n";
371 }
372
373 //----------------------------------------------------------------------------
374 void
375 cmGlobalVisualStudio8Generator
376 ::WriteProjectConfigurations(
377   std::ostream& fout, const char* name, cmTarget::TargetType type,
378   const std::set<std::string>& configsPartOfDefaultBuild,
379   const char* platformMapping)
380 {
381   std::string guid = this->GetGUID(name);
382   for(std::vector<std::string>::iterator i = this->Configurations.begin();
383       i != this->Configurations.end(); ++i)
384     {
385     fout << "\t\t{" << guid << "}." << *i
386          << "|" << this->GetPlatformName() << ".ActiveCfg = " << *i << "|"
387          << (platformMapping ? platformMapping : this->GetPlatformName())
388          << "\n";
389       std::set<std::string>::const_iterator
390         ci = configsPartOfDefaultBuild.find(*i);
391       if(!(ci == configsPartOfDefaultBuild.end()))
392       {
393       fout << "\t\t{" << guid << "}." << *i
394            << "|" << this->GetPlatformName() << ".Build.0 = " << *i << "|"
395            << (platformMapping ? platformMapping : this->GetPlatformName())
396            << "\n";
397       }
398     bool needsDeploy = (type == cmTarget::EXECUTABLE ||
399                         type == cmTarget::SHARED_LIBRARY);
400     if(this->TargetsWindowsCE() && needsDeploy)
401       {
402       fout << "\t\t{" << guid << "}." << *i
403            << "|" << this->GetPlatformName() << ".Deploy.0 = " << *i << "|"
404            << (platformMapping ? platformMapping : this->GetPlatformName())
405            << "\n";
406       }
407     }
408 }
409
410 //----------------------------------------------------------------------------
411 bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
412 {
413   // Skip over the cmGlobalVisualStudioGenerator implementation!
414   // We do not need the support that VS <= 7.1 needs.
415   return this->cmGlobalGenerator::ComputeTargetDepends();
416 }
417
418 //----------------------------------------------------------------------------
419 void cmGlobalVisualStudio8Generator::WriteProjectDepends(
420   std::ostream& fout, const char*, const char*, cmTarget& t)
421 {
422   TargetDependSet const& unordered = this->GetTargetDirectDepends(t);
423   OrderedTargetDependSet depends(unordered);
424   for(OrderedTargetDependSet::const_iterator i = depends.begin();
425       i != depends.end(); ++i)
426     {
427     std::string guid = this->GetGUID((*i)->GetName());
428     fout << "\t\t{" << guid << "} = {" << guid << "}\n";
429     }
430 }
431
432 //----------------------------------------------------------------------------
433 bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies(
434   cmTarget& target)
435 {
436   // Look for utility dependencies that magically link.
437   for(std::set<cmStdString>::const_iterator ui =
438         target.GetUtilities().begin();
439       ui != target.GetUtilities().end(); ++ui)
440     {
441     if(cmTarget* depTarget = this->FindTarget(0, ui->c_str()))
442       {
443       if(depTarget->GetProperty("EXTERNAL_MSPROJECT"))
444         {
445         // This utility dependency names an external .vcproj target.
446         // We use LinkLibraryDependencies="true" to link to it without
447         // predicting the .lib file location or name.
448         return true;
449         }
450       }
451     }
452   return false;
453 }
454
455 //----------------------------------------------------------------------------
456 static cmVS7FlagTable cmVS8ExtraFlagTable[] =
457 {
458   {"CallingConvention", "Gd", "cdecl", "0", 0 },
459   {"CallingConvention", "Gr", "fastcall", "1", 0 },
460   {"CallingConvention", "Gz", "stdcall", "2", 0 },
461
462   {"Detect64BitPortabilityProblems", "Wp64",
463    "Detect 64Bit Portability Problems", "true", 0 },
464   {"ErrorReporting", "errorReport:prompt", "Report immediately", "1", 0 },
465   {"ErrorReporting", "errorReport:queue", "Queue for next login", "2", 0 },
466   // Precompiled header and related options.  Note that the
467   // UsePrecompiledHeader entries are marked as "Continue" so that the
468   // corresponding PrecompiledHeaderThrough entry can be found.
469   {"UsePrecompiledHeader", "Yu", "Use Precompiled Header", "2",
470    cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},
471   {"PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
472    cmVS7FlagTable::UserValueRequired},
473   // There is no YX option in the VS8 IDE.
474
475   // Exception handling mode.  If no entries match, it will be FALSE.
476   {"ExceptionHandling", "GX", "enable c++ exceptions", "1", 0},
477   {"ExceptionHandling", "EHsc", "enable c++ exceptions", "1", 0},
478   {"ExceptionHandling", "EHa", "enable SEH exceptions", "2", 0},
479
480   {"EnablePREfast", "analyze", "", "true", 0},
481   {"EnablePREfast", "analyze-", "", "false", 0},
482
483   // Language options
484   {"TreatWChar_tAsBuiltInType", "Zc:wchar_t",
485    "wchar_t is a built-in type", "true", 0},
486   {"TreatWChar_tAsBuiltInType", "Zc:wchar_t-",
487    "wchar_t is not a built-in type", "false", 0},
488
489   {0,0,0,0,0}
490 };
491 cmIDEFlagTable const* cmGlobalVisualStudio8Generator::GetExtraFlagTableVS8()
492 {
493   return cmVS8ExtraFlagTable;
494 }