Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmGlobalVisualStudio6Generator.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 "cmGlobalVisualStudio6Generator.h"
13 #include "cmLocalVisualStudio6Generator.h"
14 #include "cmMakefile.h"
15 #include "cmake.h"
16 #include "cmGeneratedFileStream.h"
17
18 // Utility function to make a valid VS6 *.dsp filename out
19 // of a CMake target name:
20 //
21 std::string GetVS6TargetName(const std::string& targetName)
22 {
23   std::string name(targetName);
24
25   // Eliminate hyphens. VS6 cannot handle hyphens in *.dsp filenames...
26   // Replace them with underscores.
27   //
28   cmSystemTools::ReplaceString(name, "-", "_");
29
30   return name;
31 }
32
33 cmGlobalVisualStudio6Generator::cmGlobalVisualStudio6Generator()
34 {
35   this->FindMakeProgramFile = "CMakeVS6FindMake.cmake";
36 }
37
38 void cmGlobalVisualStudio6Generator
39 ::EnableLanguage(std::vector<std::string>const& lang, 
40                  cmMakefile *mf, 
41                  bool optional)
42 {
43   mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
44   mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
45   mf->AddDefinition("CMAKE_GENERATOR_RC", "rc"); 
46   mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
47   mf->AddDefinition("CMAKE_GENERATOR_Fortran", "ifort");
48   mf->AddDefinition("MSVC_C_ARCHITECTURE_ID", "X86");
49   mf->AddDefinition("MSVC_CXX_ARCHITECTURE_ID", "X86");
50   mf->AddDefinition("MSVC60", "1");
51   this->GenerateConfigurations(mf);
52   this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
53 }
54
55 void cmGlobalVisualStudio6Generator::GenerateConfigurations(cmMakefile* mf)
56 {
57   std::string fname= mf->GetRequiredDefinition("CMAKE_ROOT");
58   const char* def= mf->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY");
59   if(def)
60     {
61     fname = def;
62     }
63   else
64     {
65     fname += "/Templates";
66     }
67   fname += "/CMakeVisualStudio6Configurations.cmake";
68   if(!mf->ReadListFile(mf->GetCurrentListFile(), fname.c_str()))
69     {
70     cmSystemTools::Error("Cannot open ", fname.c_str(),
71                          ".  Please copy this file from the main "
72                          "CMake/Templates directory and edit it for "
73                          "your build configurations.");
74     }
75   else if(!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
76     {
77     cmSystemTools::Error("CMAKE_CONFIGURATION_TYPES not set by ",
78                          fname.c_str(),
79                          ".  Please copy this file from the main "
80                          "CMake/Templates directory and edit it for "
81                          "your build configurations.");
82     }
83 }
84
85 std::string cmGlobalVisualStudio6Generator
86 ::GenerateBuildCommand(const char* makeProgram,
87                        const char *projectName, 
88                        const char* additionalOptions, 
89                        const char *targetName,
90                        const char* config, 
91                        bool ignoreErrors,
92                        bool)
93 {
94   // Ingoring errors is not implemented in visual studio 6
95   (void) ignoreErrors;
96
97   // now build the test
98   std::vector<std::string> mp;
99   mp.push_back("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio"
100                "\\6.0\\Setup;VsCommonDir]/MSDev98/Bin");
101   cmSystemTools::ExpandRegistryValues(mp[0]);
102   std::string originalCommand = makeProgram;
103   std::string makeCommand = 
104     cmSystemTools::FindProgram(makeProgram, mp);
105   if(makeCommand.size() == 0)
106     {
107     std::string e = "Generator cannot find Visual Studio 6 msdev program \"";
108     e += originalCommand;
109     e += "\" specified by CMAKE_MAKE_PROGRAM cache entry.  ";
110     e += "Please fix the setting.";
111     cmSystemTools::Error(e.c_str());
112     return "";
113     }
114   makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
115
116   // if there are spaces in the makeCommand, assume a full path
117   // and convert it to a path with no spaces in it as the
118   // RunSingleCommand does not like spaces
119 #if defined(_WIN32) && !defined(__CYGWIN__)      
120   if(makeCommand.find(' ') != std::string::npos)
121     {
122     cmSystemTools::GetShortPath(makeCommand.c_str(), makeCommand);
123     }
124 #endif
125   makeCommand += " ";
126   makeCommand += projectName;
127   makeCommand += ".dsw /MAKE \"";
128   bool clean = false;
129   if ( targetName && strcmp(targetName, "clean") == 0 )
130     {
131     clean = true;
132     targetName = "ALL_BUILD";
133     }
134   if (targetName && strlen(targetName))
135     {
136     makeCommand += targetName;
137     }
138   else
139     {
140     makeCommand += "ALL_BUILD";
141     }
142   makeCommand += " - ";
143   if(config && strlen(config))
144     {
145     makeCommand += config;
146     }
147   else
148     {
149     makeCommand += "Debug";
150     }
151   if(clean)
152     {
153     makeCommand += "\" /CLEAN";
154     }
155   else
156     {
157     makeCommand += "\" /BUILD";
158     }
159   if ( additionalOptions )
160     {
161     makeCommand += " ";
162     makeCommand += additionalOptions;
163     }
164   return makeCommand;
165 }
166
167 ///! Create a local generator appropriate to this Global Generator
168 cmLocalGenerator *cmGlobalVisualStudio6Generator::CreateLocalGenerator()
169 {
170   cmLocalGenerator *lg = new cmLocalVisualStudio6Generator;
171   lg->SetGlobalGenerator(this);
172   return lg;
173 }
174
175
176 void cmGlobalVisualStudio6Generator::Generate()
177 {
178   // first do the superclass method
179   this->cmGlobalVisualStudioGenerator::Generate();
180
181   // Now write out the DSW
182   this->OutputDSWFile();
183 }
184
185 // Write a DSW file to the stream
186 void cmGlobalVisualStudio6Generator
187 ::WriteDSWFile(std::ostream& fout,cmLocalGenerator* root,
188                std::vector<cmLocalGenerator*>& generators)
189 {
190   // Write out the header for a DSW file
191   this->WriteDSWHeader(fout);
192
193   // Collect all targets under this root generator and the transitive
194   // closure of their dependencies.
195   TargetDependSet projectTargets;
196   TargetDependSet originalTargets;
197   this->GetTargetSets(projectTargets, originalTargets, root, generators);
198   OrderedTargetDependSet orderedProjectTargets(projectTargets);
199
200   for(OrderedTargetDependSet::const_iterator
201         tt = orderedProjectTargets.begin();
202       tt != orderedProjectTargets.end(); ++tt)
203     {
204     cmTarget* target = *tt;
205     cmMakefile* mf = target->GetMakefile();
206     // Write the project into the DSW file
207     const char* expath = target->GetProperty("EXTERNAL_MSPROJECT");
208     if(expath)
209       {
210       std::string project = target->GetName();
211       std::string location = expath;
212       this->WriteExternalProject(fout, project.c_str(),
213                                  location.c_str(), target->GetUtilities());
214       }
215     else
216       {
217       std::string dspname = GetVS6TargetName(target->GetName());
218       std::string dir = target->GetMakefile()->GetStartOutputDirectory();
219       dir = root->Convert(dir.c_str(), cmLocalGenerator::START_OUTPUT);
220       this->WriteProject(fout, dspname.c_str(), dir.c_str(), *target);
221       }
222     }
223
224   // Write the footer for the DSW file
225   this->WriteDSWFooter(fout);
226 }
227
228 void cmGlobalVisualStudio6Generator
229 ::OutputDSWFile(cmLocalGenerator* root, 
230                 std::vector<cmLocalGenerator*>& generators)
231 {
232   if(generators.size() == 0)
233     {
234     return;
235     }
236   std::string fname = root->GetMakefile()->GetStartOutputDirectory();
237   fname += "/";
238   fname += root->GetMakefile()->GetProjectName();
239   fname += ".dsw";
240   std::ofstream fout(fname.c_str());
241   if(!fout)
242     {
243     cmSystemTools::Error("Error can not open DSW file for write: ",
244                          fname.c_str());
245     cmSystemTools::ReportLastSystemError("");
246     return;
247     }
248   this->WriteDSWFile(fout, root, generators);
249 }
250
251 // output the DSW file
252 void cmGlobalVisualStudio6Generator::OutputDSWFile()
253
254   std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
255   for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
256     {
257     this->OutputDSWFile(it->second[0], it->second);
258     }
259 }
260
261 // Write a dsp file into the DSW file,
262 // Note, that dependencies from executables to 
263 // the libraries it uses are also done here
264 void cmGlobalVisualStudio6Generator::WriteProject(std::ostream& fout, 
265                                                   const char* dspname,
266                                                   const char* dir,
267                                                   cmTarget& target)
268 {
269   fout << "#########################################################"
270     "######################\n\n";
271   fout << "Project: \"" << dspname << "\"=" 
272        << dir << "\\" << dspname << ".dsp - Package Owner=<4>\n\n";
273   fout << "Package=<5>\n{{{\n}}}\n\n";
274   fout << "Package=<4>\n";
275   fout << "{{{\n";
276   VSDependSet const& depends = this->VSTargetDepends[&target];
277   for(VSDependSet::const_iterator di = depends.begin();
278       di != depends.end(); ++di)
279     {
280     const char* name = di->c_str();
281     fout << "Begin Project Dependency\n";
282     fout << "Project_Dep_Name " << GetVS6TargetName(name) << "\n";
283     fout << "End Project Dependency\n";
284     }
285   fout << "}}}\n\n";
286
287   UtilityDependsMap::iterator ui = this->UtilityDepends.find(&target);
288   if(ui != this->UtilityDepends.end())
289     {
290     const char* uname = ui->second.c_str();
291     fout << "Project: \"" << uname << "\"="
292          << dir << "\\" << uname << ".dsp - Package Owner=<4>\n\n";
293     fout <<
294       "Package=<5>\n{{{\n}}}\n\n"
295       "Package=<4>\n"
296       "{{{\n"
297       "Begin Project Dependency\n"
298       "Project_Dep_Name " << dspname << "\n"
299       "End Project Dependency\n"
300       "}}}\n\n";
301       ;
302     }
303 }
304
305
306 // Write a dsp file into the DSW file,
307 // Note, that dependencies from executables to 
308 // the libraries it uses are also done here
309 void cmGlobalVisualStudio6Generator::WriteExternalProject(std::ostream& fout, 
310                                const char* name,
311                                const char* location,
312                                const std::set<cmStdString>& dependencies)
313 {
314  fout << "#########################################################"
315     "######################\n\n";
316   fout << "Project: \"" << name << "\"=" 
317        << location << " - Package Owner=<4>\n\n";
318   fout << "Package=<5>\n{{{\n}}}\n\n";
319   fout << "Package=<4>\n";
320   fout << "{{{\n";
321
322   
323   std::set<cmStdString>::const_iterator i, end;
324   // write dependencies.
325   i = dependencies.begin();
326   end = dependencies.end();
327   for(;i!= end; ++i)
328   {
329     fout << "Begin Project Dependency\n";
330     fout << "Project_Dep_Name " << GetVS6TargetName(*i) << "\n";
331     fout << "End Project Dependency\n";
332   }
333   fout << "}}}\n\n";
334 }
335
336
337
338 // Standard end of dsw file
339 void cmGlobalVisualStudio6Generator::WriteDSWFooter(std::ostream& fout)
340 {
341   fout << "######################################################"
342     "#########################\n\n";
343   fout << "Global:\n\n";
344   fout << "Package=<5>\n{{{\n}}}\n\n";
345   fout << "Package=<3>\n{{{\n}}}\n\n";
346   fout << "#####################################################"
347     "##########################\n\n";
348 }
349
350   
351 // ouput standard header for dsw file
352 void cmGlobalVisualStudio6Generator::WriteDSWHeader(std::ostream& fout)
353 {
354   fout << "Microsoft Developer Studio Workspace File, Format Version 6.00\n";
355   fout << "# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\n\n";
356 }
357
358 //----------------------------------------------------------------------------
359 std::string
360 cmGlobalVisualStudio6Generator::WriteUtilityDepend(cmTarget* target)
361 {
362   std::string pname = target->GetName();
363   pname += "_UTILITY";
364   pname = GetVS6TargetName(pname.c_str());
365   std::string fname = target->GetMakefile()->GetStartOutputDirectory();
366   fname += "/";
367   fname += pname;
368   fname += ".dsp";
369   cmGeneratedFileStream fout(fname.c_str());
370   fout.SetCopyIfDifferent(true);
371   fout <<
372     "# Microsoft Developer Studio Project File - Name=\""
373        << pname << "\" - Package Owner=<4>\n"
374     "# Microsoft Developer Studio Generated Build File, Format Version 6.00\n"
375     "# ** DO NOT EDIT **\n"
376     "\n"
377     "# TARGTYPE \"Win32 (x86) Generic Project\" 0x010a\n"
378     "\n"
379     "CFG=" << pname << " - Win32 Debug\n"
380     "!MESSAGE \"" << pname << " - Win32 Debug\""
381     " (based on \"Win32 (x86) Generic Project\")\n"
382     "!MESSAGE \"" << pname << " - Win32 Release\" "
383     "(based on \"Win32 (x86) Generic Project\")\n"
384     "!MESSAGE \"" << pname << " - Win32 MinSizeRel\" "
385     "(based on \"Win32 (x86) Generic Project\")\n"
386     "!MESSAGE \"" << pname << " - Win32 RelWithDebInfo\" "
387     "(based on \"Win32 (x86) Generic Project\")\n"
388     "\n"
389     "# Begin Project\n"
390     "# Begin Target\n"
391     "# Name \"" << pname << " - Win32 Debug\"\n"
392     "# Name \"" << pname << " - Win32 Release\"\n"
393     "# Name \"" << pname << " - Win32 MinSizeRel\"\n"
394     "# Name \"" << pname << " - Win32 RelWithDebInfo\"\n"
395     "# End Target\n"
396     "# End Project\n"
397     ;
398   return pname;
399 }
400
401 //----------------------------------------------------------------------------
402 void cmGlobalVisualStudio6Generator
403 ::GetDocumentation(cmDocumentationEntry& entry) const
404 {
405   entry.Name = this->GetName();
406   entry.Brief = "Generates Visual Studio 6 project files.";
407   entry.Full = "";
408 }
409
410 //----------------------------------------------------------------------------
411 void
412 cmGlobalVisualStudio6Generator
413 ::AppendDirectoryForConfig(const char* prefix,
414                            const char* config,
415                            const char* suffix,
416                            std::string& dir)
417 {
418   if(config)
419     {
420     dir += prefix;
421     dir += config;
422     dir += suffix;
423     }
424 }