Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmExtraEclipseCDT4Generator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2004-2009 Kitware, Inc.
4   Copyright 2004 Alexander Neundorf (neundorf@kde.org)
5   Copyright 2007 Miguel A. Figueroa-Villanueva
6
7   Distributed under the OSI-approved BSD License (the "License");
8   see accompanying file Copyright.txt for details.
9
10   This software is distributed WITHOUT ANY WARRANTY; without even the
11   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12   See the License for more information.
13 ============================================================================*/
14 #include "cmExtraEclipseCDT4Generator.h"
15 #include "cmGlobalUnixMakefileGenerator3.h"
16 #include "cmLocalUnixMakefileGenerator3.h"
17 #include "cmMakefile.h"
18 #include "cmGeneratedFileStream.h"
19 #include "cmTarget.h"
20 #include "cmSourceFile.h"
21
22 #include "cmSystemTools.h"
23 #include <stdlib.h>
24 #include <assert.h>
25
26 //----------------------------------------------------------------------------
27 cmExtraEclipseCDT4Generator
28 ::cmExtraEclipseCDT4Generator() : cmExternalMakefileProjectGenerator()
29 {
30 // TODO: Verify if __CYGWIN__ should be checked.
31 //#if defined(_WIN32) && !defined(__CYGWIN__)
32 #if defined(_WIN32)
33   this->SupportedGlobalGenerators.push_back("NMake Makefiles");
34   this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
35 //  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
36 #endif
37   this->SupportedGlobalGenerators.push_back("Ninja");
38   this->SupportedGlobalGenerators.push_back("Unix Makefiles");
39
40   this->SupportsVirtualFolders = true;
41   this->GenerateLinkedResources = true;
42   this->SupportsGmakeErrorParser = true;
43 }
44
45 //----------------------------------------------------------------------------
46 void cmExtraEclipseCDT4Generator
47 ::GetDocumentation(cmDocumentationEntry& entry, const char*) const
48 {
49   entry.Name = this->GetName();
50   entry.Brief = "Generates Eclipse CDT 4.0 project files.";
51   entry.Full =
52     "Project files for Eclipse will be created in the top directory. "
53     "In out of source builds, a linked resource to the top level source "
54     "directory will be created. "
55     "Additionally a hierarchy of makefiles is generated into the "
56     "build tree. The appropriate make program can build the project through "
57     "the default make target. A \"make install\" target is also provided.";
58 }
59
60 //----------------------------------------------------------------------------
61 void cmExtraEclipseCDT4Generator::Generate()
62 {
63   const cmMakefile* mf
64     = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
65
66   std::string eclipseVersion = mf->GetSafeDefinition("CMAKE_ECLIPSE_VERSION");
67   cmsys::RegularExpression regex(".*([0-9]+\\.[0-9]+).*");
68   if (regex.find(eclipseVersion.c_str()))
69     {
70     unsigned int majorVersion = 0;
71     unsigned int minorVersion = 0;
72     int res=sscanf(regex.match(1).c_str(), "%u.%u", &majorVersion,
73                                                     &minorVersion);
74     if (res == 2)
75       {
76       int version = majorVersion * 1000 + minorVersion;
77       if (version < 3006) // 3.6 is Helios
78         {
79         this->SupportsVirtualFolders = false;
80         }
81       if (version < 3007) // 3.7 is Indigo
82         {
83         this->SupportsGmakeErrorParser = false;
84         }
85       }
86     }
87
88   // TODO: Decide if these are local or member variables
89   this->HomeDirectory       = mf->GetHomeDirectory();
90   this->HomeOutputDirectory = mf->GetHomeOutputDirectory();
91
92   this->GenerateLinkedResources = mf->IsOn(
93                                     "CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES");
94
95   this->IsOutOfSourceBuild = (this->HomeDirectory!=this->HomeOutputDirectory);
96
97   this->GenerateSourceProject = (this->IsOutOfSourceBuild &&
98                             mf->IsOn("CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT"));
99
100   if ((this->GenerateSourceProject == false)
101     && (mf->IsOn("ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT")))
102     {
103     mf->IssueMessage(cmake::WARNING,
104               "ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT is set to TRUE, "
105               "but this variable is not supported anymore since CMake 2.8.7.\n"
106               "Enable CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT instead.");
107     }
108
109   if (cmSystemTools::IsSubDirectory(this->HomeOutputDirectory.c_str(),
110                                     this->HomeDirectory.c_str()))
111     {
112     mf->IssueMessage(cmake::WARNING, "The build directory is a subdirectory "
113                      "of the source directory.\n"
114                      "This is not supported well by Eclipse. It is strongly "
115                      "recommended to use a build directory which is a "
116                      "sibling of the source directory.");
117     }
118
119   // NOTE: This is not good, since it pollutes the source tree. However,
120   //       Eclipse doesn't allow CVS/SVN to work when the .project is not in
121   //       the cvs/svn root directory. Hence, this is provided as an option.
122   if (this->GenerateSourceProject)
123     {
124     // create .project file in the source tree
125     this->CreateSourceProjectFile();
126     }
127
128   // create a .project file
129   this->CreateProjectFile();
130
131   // create a .cproject file
132   this->CreateCProjectFile();
133 }
134
135 void cmExtraEclipseCDT4Generator::CreateSourceProjectFile()
136 {
137   assert(this->HomeDirectory != this->HomeOutputDirectory);
138
139   // set up the project name: <project>-Source@<baseSourcePathName>
140   const cmMakefile* mf
141      = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
142   std::string name = this->GenerateProjectName(mf->GetProjectName(), "Source",
143                                    this->GetPathBasename(this->HomeDirectory));
144
145   const std::string filename = this->HomeDirectory + "/.project";
146   cmGeneratedFileStream fout(filename.c_str());
147   if (!fout)
148     {
149     return;
150     }
151
152   fout <<
153     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
154     "<projectDescription>\n"
155     "\t<name>" << this->EscapeForXML(name) << "</name>\n"
156     "\t<comment></comment>\n"
157     "\t<projects>\n"
158     "\t</projects>\n"
159     "\t<buildSpec>\n"
160     "\t</buildSpec>\n"
161     "\t<natures>\n"
162     "\t</natures>\n"
163     "\t<linkedResources>\n";
164
165   if (this->SupportsVirtualFolders)
166     {
167     this->CreateLinksToSubprojects(fout, this->HomeDirectory);
168     this->SrcLinkedResources.clear();
169     }
170
171   fout <<
172     "\t</linkedResources>\n"
173     "</projectDescription>\n"
174     ;
175 }
176
177
178 //----------------------------------------------------------------------------
179 void cmExtraEclipseCDT4Generator::AddEnvVar(cmGeneratedFileStream& fout,
180                                             const char* envVar, cmMakefile* mf)
181 {
182   // get the variables from the environment and from the cache and then
183   // figure out which one to use:
184
185   const char* envVarValue = getenv(envVar);
186
187   std::string cacheEntryName = "CMAKE_ECLIPSE_ENVVAR_";
188   cacheEntryName += envVar;
189   const char* cacheValue = mf->GetCacheManager()->GetCacheValue(
190                                                        cacheEntryName.c_str());
191
192   // now we have both, decide which one to use
193   std::string valueToUse;
194   if (envVarValue==0 && cacheValue==0)
195     {
196     // nothing known, do nothing
197     valueToUse = "";
198     }
199   else if (envVarValue!=0 && cacheValue==0)
200     {
201     // The variable is in the env, but not in the cache. Use it and put it
202     // in the cache
203     valueToUse = envVarValue;
204     mf->AddCacheDefinition(cacheEntryName.c_str(), valueToUse.c_str(),
205                            cacheEntryName.c_str(), cmCacheManager::STRING,
206                            true);
207     mf->GetCacheManager()->SaveCache(mf->GetHomeOutputDirectory());
208     }
209   else if (envVarValue==0 && cacheValue!=0)
210     {
211     // It is already in the cache, but not in the env, so use it from the cache
212     valueToUse = cacheValue;
213     }
214   else
215     {
216     // It is both in the cache and in the env.
217     // Use the version from the env. except if the value from the env is
218     // completely contained in the value from the cache (for the case that we
219     // now have a PATH without MSVC dirs in the env. but had the full PATH with
220     // all MSVC dirs during the cmake run which stored the var in the cache:
221     valueToUse = cacheValue;
222     if (valueToUse.find(envVarValue) == std::string::npos)
223       {
224       valueToUse = envVarValue;
225       mf->AddCacheDefinition(cacheEntryName.c_str(), valueToUse.c_str(),
226                              cacheEntryName.c_str(), cmCacheManager::STRING,
227                              true);
228       mf->GetCacheManager()->SaveCache(mf->GetHomeOutputDirectory());
229       }
230     }
231
232   if (!valueToUse.empty())
233     {
234     fout << envVar << "=" << valueToUse << "|";
235     }
236 }
237
238
239 //----------------------------------------------------------------------------
240 void cmExtraEclipseCDT4Generator::CreateProjectFile()
241 {
242   cmMakefile* mf
243     = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
244
245   const std::string filename = this->HomeOutputDirectory + "/.project";
246
247   cmGeneratedFileStream fout(filename.c_str());
248   if (!fout)
249     {
250     return;
251     }
252
253   std::string compilerId = mf->GetSafeDefinition("CMAKE_C_COMPILER_ID");
254   if (compilerId.empty())  // no C compiler, try the C++ compiler:
255     {
256     compilerId = mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID");
257     }
258
259   fout <<
260     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
261     "<projectDescription>\n"
262     "\t<name>" <<
263     this->GenerateProjectName(mf->GetProjectName(),
264                               mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
265                               this->GetPathBasename(this->HomeOutputDirectory))
266     << "</name>\n"
267     "\t<comment></comment>\n"
268     "\t<projects>\n"
269     "\t</projects>\n"
270     "\t<buildSpec>\n"
271     "\t\t<buildCommand>\n"
272     "\t\t\t<name>org.eclipse.cdt.make.core.makeBuilder</name>\n"
273     "\t\t\t<triggers>clean,full,incremental,</triggers>\n"
274     "\t\t\t<arguments>\n"
275     ;
276
277   // use clean target
278   fout <<
279     "\t\t\t\t<dictionary>\n"
280     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>\n"
281     "\t\t\t\t\t<value>clean</value>\n"
282     "\t\t\t\t</dictionary>\n"
283     "\t\t\t\t<dictionary>\n"
284     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enableCleanBuild</key>\n"
285     "\t\t\t\t\t<value>true</value>\n"
286     "\t\t\t\t</dictionary>\n"
287     "\t\t\t\t<dictionary>\n"
288     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.append_environment</key>\n"
289     "\t\t\t\t\t<value>true</value>\n"
290     "\t\t\t\t</dictionary>\n"
291     "\t\t\t\t<dictionary>\n"
292     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.stopOnError</key>\n"
293     "\t\t\t\t\t<value>true</value>\n"
294     "\t\t\t\t</dictionary>\n"
295     ;
296
297   // set the make command
298   std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
299   const std::string makeArgs = mf->GetSafeDefinition(
300                                                "CMAKE_ECLIPSE_MAKE_ARGUMENTS");
301
302   fout <<
303     "\t\t\t\t<dictionary>\n"
304     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>\n"
305     "\t\t\t\t\t<value>true</value>\n"
306     "\t\t\t\t</dictionary>\n"
307     "\t\t\t\t<dictionary>\n"
308     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.command</key>\n"
309     "\t\t\t\t\t<value>" << this->GetEclipsePath(make) << "</value>\n"
310     "\t\t\t\t</dictionary>\n"
311     "\t\t\t\t<dictionary>\n"
312     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.contents</key>\n"
313     "\t\t\t\t\t<value>org.eclipse.cdt.make.core.activeConfigSettings</value>\n"
314     "\t\t\t\t</dictionary>\n"
315     "\t\t\t\t<dictionary>\n"
316     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.target.inc</key>\n"
317     "\t\t\t\t\t<value>all</value>\n"
318     "\t\t\t\t</dictionary>\n"
319     "\t\t\t\t<dictionary>\n"
320     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.arguments</key>\n"
321     "\t\t\t\t\t<value>" << makeArgs << "</value>\n"
322     "\t\t\t\t</dictionary>\n"
323     "\t\t\t\t<dictionary>\n"
324     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.buildLocation</key>\n"
325     "\t\t\t\t\t<value>"
326      << this->GetEclipsePath(this->HomeOutputDirectory) << "</value>\n"
327     "\t\t\t\t</dictionary>\n"
328     "\t\t\t\t<dictionary>\n"
329     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>\n"
330     "\t\t\t\t\t<value>false</value>\n"
331     "\t\t\t\t</dictionary>\n"
332     ;
333
334   // set project specific environment
335   fout <<
336     "\t\t\t\t<dictionary>\n"
337     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.environment</key>\n"
338     "\t\t\t\t\t<value>VERBOSE=1|CMAKE_NO_VERBOSE=1|"  //verbose Makefile output
339     ;
340   // set vsvars32.bat environment available at CMake time,
341   //   but not necessarily when eclipse is open
342   if (compilerId == "MSVC")
343     {
344     AddEnvVar(fout, "PATH", mf);
345     AddEnvVar(fout, "INCLUDE", mf);
346     AddEnvVar(fout, "LIB", mf);
347     AddEnvVar(fout, "LIBPATH", mf);
348     }
349   else if (compilerId == "Intel")
350     {
351     // if the env.var is set, use this one and put it in the cache
352     // if the env.var is not set, but the value is in the cache,
353     // use it from the cache:
354     AddEnvVar(fout, "INTEL_LICENSE_FILE", mf);
355     }
356   fout <<
357     "</value>\n"
358     "\t\t\t\t</dictionary>\n"
359     ;
360
361   fout <<
362     "\t\t\t\t<dictionary>\n"
363     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enableFullBuild</key>\n"
364     "\t\t\t\t\t<value>true</value>\n"
365     "\t\t\t\t</dictionary>\n"
366     "\t\t\t\t<dictionary>\n"
367     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.target.auto</key>\n"
368     "\t\t\t\t\t<value>all</value>\n"
369     "\t\t\t\t</dictionary>\n"
370     "\t\t\t\t<dictionary>\n"
371     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enableAutoBuild</key>\n"
372     "\t\t\t\t\t<value>false</value>\n"
373     "\t\t\t\t</dictionary>\n"
374     "\t\t\t\t<dictionary>\n"
375     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.target.clean</key>\n"
376     "\t\t\t\t\t<value>clean</value>\n"
377     "\t\t\t\t</dictionary>\n"
378     "\t\t\t\t<dictionary>\n"
379     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.fullBuildTarget</key>\n"
380     "\t\t\t\t\t<value>all</value>\n"
381     "\t\t\t\t</dictionary>\n"
382     "\t\t\t\t<dictionary>\n"
383     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.buildArguments</key>\n"
384     "\t\t\t\t\t<value></value>\n"
385     "\t\t\t\t</dictionary>\n"
386     "\t\t\t\t<dictionary>\n"
387     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.location</key>\n"
388     "\t\t\t\t\t<value>"
389     << this->GetEclipsePath(this->HomeOutputDirectory) << "</value>\n"
390     "\t\t\t\t</dictionary>\n"
391     "\t\t\t\t<dictionary>\n"
392     "\t\t\t\t\t<key>org.eclipse.cdt.make.core.autoBuildTarget</key>\n"
393     "\t\t\t\t\t<value>all</value>\n"
394     "\t\t\t\t</dictionary>\n"
395     ;
396
397   // set error parsers
398   fout <<
399     "\t\t\t\t<dictionary>\n"
400     "\t\t\t\t\t<key>org.eclipse.cdt.core.errorOutputParser</key>\n"
401     "\t\t\t\t\t<value>"
402     ;
403   if (compilerId == "MSVC")
404     {
405     fout << "org.eclipse.cdt.core.VCErrorParser;";
406     }
407   else if (compilerId == "Intel")
408     {
409     fout << "org.eclipse.cdt.core.ICCErrorParser;";
410     }
411
412   if (this->SupportsGmakeErrorParser)
413     {
414     fout << "org.eclipse.cdt.core.GmakeErrorParser;";
415     }
416   else
417     {
418     fout << "org.eclipse.cdt.core.MakeErrorParser;";
419     }
420
421   fout <<
422     "org.eclipse.cdt.core.GCCErrorParser;"
423     "org.eclipse.cdt.core.GASErrorParser;"
424     "org.eclipse.cdt.core.GLDErrorParser;"
425     "</value>\n"
426     "\t\t\t\t</dictionary>\n"
427     ;
428
429   fout <<
430     "\t\t\t</arguments>\n"
431     "\t\t</buildCommand>\n"
432     "\t\t<buildCommand>\n"
433     "\t\t\t<name>org.eclipse.cdt.make.core.ScannerConfigBuilder</name>\n"
434     "\t\t\t<arguments>\n"
435     "\t\t\t</arguments>\n"
436     "\t\t</buildCommand>\n"
437     "\t</buildSpec>\n"
438     ;
439
440   // set natures for c/c++ projects
441   fout <<
442     "\t<natures>\n"
443     // TODO: ccnature only if it is c++ ???
444     "\t\t<nature>org.eclipse.cdt.core.ccnature</nature>\n"
445     "\t\t<nature>org.eclipse.cdt.make.core.makeNature</nature>\n"
446     "\t\t<nature>org.eclipse.cdt.make.core.ScannerConfigNature</nature>\n"
447     "\t\t<nature>org.eclipse.cdt.core.cnature</nature>\n"
448     "\t</natures>\n"
449     ;
450
451   fout << "\t<linkedResources>\n";
452   // create linked resources
453   if (this->IsOutOfSourceBuild)
454     {
455     // create a linked resource to CMAKE_SOURCE_DIR
456     // (this is not done anymore for each project because of
457     // http://public.kitware.com/Bug/view.php?id=9978 and because I found it
458     // actually quite confusing in bigger projects with many directories and
459     // projects, Alex
460
461     std::string sourceLinkedResourceName = "[Source directory]";
462     std::string linkSourceDirectory = this->GetEclipsePath(
463                                                       mf->GetStartDirectory());
464     // .project dir can't be subdir of a linked resource dir
465     if (!cmSystemTools::IsSubDirectory(this->HomeOutputDirectory.c_str(),
466                                          linkSourceDirectory.c_str()))
467       {
468       this->AppendLinkedResource(fout, sourceLinkedResourceName,
469                                  this->GetEclipsePath(linkSourceDirectory),
470                                  LinkToFolder);
471       this->SrcLinkedResources.push_back(sourceLinkedResourceName);
472       }
473
474     }
475
476   if (this->SupportsVirtualFolders)
477     {
478     this->CreateLinksToSubprojects(fout, this->HomeOutputDirectory);
479
480     this->CreateLinksForTargets(fout);
481     }
482
483   fout << "\t</linkedResources>\n";
484
485   fout << "</projectDescription>\n";
486 }
487
488
489 //----------------------------------------------------------------------------
490 void cmExtraEclipseCDT4Generator::CreateLinksForTargets(
491                                                    cmGeneratedFileStream& fout)
492 {
493   std::string linkName = "[Targets]";
494   this->AppendLinkedResource(fout, linkName, "virtual:/virtual",VirtualFolder);
495
496   for (std::vector<cmLocalGenerator*>::const_iterator
497        lgIt = this->GlobalGenerator->GetLocalGenerators().begin();
498        lgIt != this->GlobalGenerator->GetLocalGenerators().end();
499        ++lgIt)
500     {
501     cmMakefile* makefile = (*lgIt)->GetMakefile();
502     const cmTargets& targets = makefile->GetTargets();
503
504     for(cmTargets::const_iterator ti=targets.begin(); ti!=targets.end();++ti)
505       {
506       std::string linkName2 = linkName;
507       linkName2 += "/";
508       switch(ti->second.GetType())
509         {
510         case cmTarget::EXECUTABLE:
511         case cmTarget::STATIC_LIBRARY:
512         case cmTarget::SHARED_LIBRARY:
513         case cmTarget::MODULE_LIBRARY:
514         case cmTarget::OBJECT_LIBRARY:
515           {
516           const char* prefix = (ti->second.GetType()==cmTarget::EXECUTABLE ?
517                                                           "[exe] " : "[lib] ");
518           linkName2 += prefix;
519           linkName2 += ti->first;
520           this->AppendLinkedResource(fout, linkName2, "virtual:/virtual",
521                                      VirtualFolder);
522           if (!this->GenerateLinkedResources)
523             {
524             break; // skip generating the linked resources to the source files
525             }
526           std::vector<cmSourceGroup> sourceGroups=makefile->GetSourceGroups();
527           // get the files from the source lists then add them to the groups
528           cmTarget* tgt = const_cast<cmTarget*>(&ti->second);
529           std::vector<cmSourceFile*>const & files = tgt->GetSourceFiles();
530           for(std::vector<cmSourceFile*>::const_iterator sfIt = files.begin();
531               sfIt != files.end();
532               sfIt++)
533             {
534             // Add the file to the list of sources.
535             std::string source = (*sfIt)->GetFullPath();
536             cmSourceGroup& sourceGroup =
537                        makefile->FindSourceGroup(source.c_str(), sourceGroups);
538             sourceGroup.AssignSource(*sfIt);
539             }
540
541           for(std::vector<cmSourceGroup>::iterator sgIt = sourceGroups.begin();
542               sgIt != sourceGroups.end();
543               ++sgIt)
544             {
545             std::string linkName3 = linkName2;
546             linkName3 += "/";
547             linkName3 += sgIt->GetFullName();
548             this->AppendLinkedResource(fout, linkName3, "virtual:/virtual",
549                                        VirtualFolder);
550
551             std::vector<const cmSourceFile*> sFiles = sgIt->GetSourceFiles();
552             for(std::vector<const cmSourceFile*>::const_iterator fileIt =
553                                                                 sFiles.begin();
554                 fileIt != sFiles.end();
555                 ++fileIt)
556               {
557               std::string fullPath = (*fileIt)->GetFullPath();
558               if (!cmSystemTools::FileIsDirectory(fullPath.c_str()))
559                 {
560                 std::string linkName4 = linkName3;
561                 linkName4 += "/";
562                 linkName4 += cmSystemTools::GetFilenameName(fullPath);
563                 this->AppendLinkedResource(fout, linkName4,
564                                            fullPath, LinkToFile);
565                 }
566               }
567             }
568           }
569           break;
570         // ignore all others:
571         default:
572           break;
573         }
574       }
575     }
576 }
577
578
579 //----------------------------------------------------------------------------
580 void cmExtraEclipseCDT4Generator::CreateLinksToSubprojects(
581                        cmGeneratedFileStream& fout, const std::string& baseDir)
582 {
583   if (!this->GenerateLinkedResources)
584     {
585     return;
586     }
587
588   // for each sub project create a linked resource to the source dir
589   // - only if it is an out-of-source build
590   this->AppendLinkedResource(fout, "[Subprojects]",
591                              "virtual:/virtual", VirtualFolder);
592
593   for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator
594        it = this->GlobalGenerator->GetProjectMap().begin();
595        it != this->GlobalGenerator->GetProjectMap().end();
596        ++it)
597     {
598     std::string linkSourceDirectory = this->GetEclipsePath(
599                             it->second[0]->GetMakefile()->GetStartDirectory());
600     // a linked resource must not point to a parent directory of .project or
601     // .project itself
602     if ((baseDir != linkSourceDirectory) &&
603         !cmSystemTools::IsSubDirectory(baseDir.c_str(),
604                                        linkSourceDirectory.c_str()))
605       {
606       std::string linkName = "[Subprojects]/";
607       linkName += it->first;
608       this->AppendLinkedResource(fout, linkName,
609                                  this->GetEclipsePath(linkSourceDirectory),
610                                  LinkToFolder
611                                 );
612       // Don't add it to the srcLinkedResources, because listing multiple
613       // directories confuses the Eclipse indexer (#13596).
614       }
615     }
616 }
617
618
619 //----------------------------------------------------------------------------
620 void cmExtraEclipseCDT4Generator::AppendIncludeDirectories(
621                             cmGeneratedFileStream& fout,
622                             const std::vector<std::string>& includeDirs,
623                             std::set<std::string>& emittedDirs)
624 {
625   for(std::vector<std::string>::const_iterator inc = includeDirs.begin();
626       inc != includeDirs.end();
627       ++inc)
628     {
629     if (!inc->empty())
630       {
631       std::string dir = cmSystemTools::CollapseFullPath(inc->c_str());
632
633       // handle framework include dirs on OSX, the remainder after the
634       // Frameworks/ part has to be stripped
635       //   /System/Library/Frameworks/GLUT.framework/Headers
636       cmsys::RegularExpression frameworkRx("(.+/Frameworks)/.+\\.framework/");
637       if(frameworkRx.find(dir.c_str()))
638         {
639         dir = frameworkRx.match(1);
640         }
641
642       if(emittedDirs.find(dir) == emittedDirs.end())
643         {
644         emittedDirs.insert(dir);
645         fout << "<pathentry include=\""
646              << cmExtraEclipseCDT4Generator::EscapeForXML(
647                               cmExtraEclipseCDT4Generator::GetEclipsePath(dir))
648              << "\" kind=\"inc\" path=\"\" system=\"true\"/>\n";
649         }
650       }
651     }
652 }
653
654 //----------------------------------------------------------------------------
655 void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
656 {
657   std::set<std::string> emmited;
658
659   const cmMakefile* mf
660     = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
661
662   const std::string filename = this->HomeOutputDirectory + "/.cproject";
663
664   cmGeneratedFileStream fout(filename.c_str());
665   if (!fout)
666     {
667     return;
668     }
669
670   // add header
671   fout <<
672     "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
673     "<?fileVersion 4.0.0?>\n\n"
674     "<cproject>\n"
675     "<storageModule moduleId=\"org.eclipse.cdt.core.settings\">\n"
676     ;
677
678   fout << "<cconfiguration id=\"org.eclipse.cdt.core.default.config.1\">\n";
679
680   // Configuration settings...
681   fout <<
682     "<storageModule"
683     " buildSystemId=\"org.eclipse.cdt.core.defaultConfigDataProvider\""
684     " id=\"org.eclipse.cdt.core.default.config.1\""
685     " moduleId=\"org.eclipse.cdt.core.settings\" name=\"Configuration\">\n"
686     "<externalSettings/>\n"
687     "<extensions>\n"
688     ;
689   // TODO: refactor this out...
690   std::string executableFormat = mf->GetSafeDefinition(
691                                                     "CMAKE_EXECUTABLE_FORMAT");
692   if (executableFormat == "ELF")
693     {
694     fout << "<extension id=\"org.eclipse.cdt.core.ELF\""
695             " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
696             ;
697     fout << "<extension id=\"org.eclipse.cdt.core.GNU_ELF\""
698             " point=\"org.eclipse.cdt.core.BinaryParser\">\n"
699             "<attribute key=\"addr2line\" value=\"addr2line\"/>\n"
700             "<attribute key=\"c++filt\" value=\"c++filt\"/>\n"
701             "</extension>\n"
702             ;
703     }
704   else
705     {
706     std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
707     if (systemName == "CYGWIN")
708       {
709       fout << "<extension id=\"org.eclipse.cdt.core.Cygwin_PE\""
710               " point=\"org.eclipse.cdt.core.BinaryParser\">\n"
711               "<attribute key=\"addr2line\" value=\"addr2line\"/>\n"
712               "<attribute key=\"c++filt\" value=\"c++filt\"/>\n"
713               "<attribute key=\"cygpath\" value=\"cygpath\"/>\n"
714               "<attribute key=\"nm\" value=\"nm\"/>\n"
715               "</extension>\n"
716               ;
717       }
718     else if (systemName == "Windows")
719       {
720       fout << "<extension id=\"org.eclipse.cdt.core.PE\""
721               " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
722               ;
723       }
724     else if (systemName == "Darwin")
725       {
726       fout << "<extension id=\"org.eclipse.cdt.core.MachO\""
727               " point=\"org.eclipse.cdt.core.BinaryParser\">\n"
728               "<attribute key=\"c++filt\" value=\"c++filt\"/>\n"
729               "</extension>\n"
730               ;
731       }
732     else
733       {
734       // *** Should never get here ***
735       fout << "<error_toolchain_type/>\n";
736       }
737     }
738
739   fout << "</extensions>\n"
740           "</storageModule>\n"
741           ;
742
743   // ???
744   fout <<
745     "<storageModule moduleId=\"org.eclipse.cdt.core.language.mapping\">\n"
746     "<project-mappings/>\n"
747     "</storageModule>\n"
748     ;
749
750   // ???
751   fout<<"<storageModule moduleId=\"org.eclipse.cdt.core.externalSettings\"/>\n"
752           ;
753
754   // set the path entries (includes, libs, source dirs, etc.)
755   fout << "<storageModule moduleId=\"org.eclipse.cdt.core.pathentry\">\n"
756           ;
757   // for each sub project with a linked resource to the source dir:
758   // - make it type 'src'
759   // - and exclude it from type 'out'
760   std::string excludeFromOut;
761 /* I don't know what the pathentry kind="src" are good for, e.g. autocompletion
762  * works also without them. Done wrong, the indexer complains, see #12417
763  * and #12213.
764  * According to #13596, this entry at least limits the directories the
765  * indexer is searching for files. So now the "src" entry contains only
766  * the linked resource to CMAKE_SOURCE_DIR.
767  * The CDT documentation is very terse on that:
768  * "CDT_SOURCE: Entry kind constant describing a path entry identifying a
769  * folder containing source code to be compiled."
770  * Also on the cdt-dev list didn't bring any information:
771  * http://web.archiveorange.com/archive/v/B4NlJDNIpYoOS1SbxFNy
772  * Alex */
773
774   for (std::vector<std::string>::const_iterator
775        it = this->SrcLinkedResources.begin();
776        it != this->SrcLinkedResources.end();
777        ++it)
778     {
779     fout << "<pathentry kind=\"src\" path=\"" << this->EscapeForXML(*it)
780          << "\"/>\n";
781
782     // exlude source directory from output search path
783     // - only if not named the same as an output directory
784     if (!cmSystemTools::FileIsDirectory(
785            std::string(this->HomeOutputDirectory + "/" + *it).c_str()))
786       {
787       excludeFromOut += this->EscapeForXML(*it) + "/|";
788       }
789     }
790
791   excludeFromOut += "**/CMakeFiles/";
792   fout << "<pathentry excluding=\"" << excludeFromOut
793        << "\" kind=\"out\" path=\"\"/>\n";
794
795   // add pre-processor definitions to allow eclipse to gray out sections
796   emmited.clear();
797   for (std::vector<cmLocalGenerator*>::const_iterator
798         it = this->GlobalGenerator->GetLocalGenerators().begin();
799        it != this->GlobalGenerator->GetLocalGenerators().end();
800        ++it)
801     {
802
803     if(const char* cdefs = (*it)->GetMakefile()->GetProperty(
804                                                         "COMPILE_DEFINITIONS"))
805       {
806       // Expand the list.
807       std::vector<std::string> defs;
808       cmSystemTools::ExpandListArgument(cdefs, defs);
809
810       for(std::vector<std::string>::const_iterator di = defs.begin();
811           di != defs.end(); ++di)
812         {
813         std::string::size_type equals = di->find('=', 0);
814         std::string::size_type enddef = di->length();
815
816         std::string def;
817         std::string val;
818         if (equals != std::string::npos && equals < enddef)
819           {
820           // we have -DFOO=BAR
821           def = di->substr(0, equals);
822           val = di->substr(equals + 1, enddef - equals + 1);
823           }
824         else
825           {
826           // we have -DFOO
827           def = *di;
828           }
829
830         // insert the definition if not already added.
831         if(emmited.find(def) == emmited.end())
832           {
833           emmited.insert(def);
834           fout << "<pathentry kind=\"mac\" name=\"" << def
835                << "\" path=\"\" value=\"" << this->EscapeForXML(val)
836                << "\"/>\n";
837           }
838         }
839       }
840     }
841   // add system defined c macros
842   const char* cDefs=mf->GetDefinition(
843                               "CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS");
844   if(cDefs)
845     {
846     // Expand the list.
847     std::vector<std::string> defs;
848     cmSystemTools::ExpandListArgument(cDefs, defs, true);
849
850     // the list must contain only definition-value pairs:
851     if ((defs.size() % 2) == 0)
852       {
853       std::vector<std::string>::const_iterator di = defs.begin();
854       while (di != defs.end())
855         {
856         std::string def = *di;
857         ++di;
858         std::string val;
859         if (di != defs.end())
860           {
861           val = *di;
862           ++di;
863           }
864
865         // insert the definition if not already added.
866         if(emmited.find(def) == emmited.end())
867           {
868           emmited.insert(def);
869           fout << "<pathentry kind=\"mac\" name=\"" << def
870                << "\" path=\"\" value=\"" << this->EscapeForXML(val)
871                << "\"/>\n";
872           }
873         }
874       }
875     }
876   // add system defined c++ macros
877   const char* cxxDefs = mf->GetDefinition(
878                             "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS");
879   if(cxxDefs)
880     {
881     // Expand the list.
882     std::vector<std::string> defs;
883     cmSystemTools::ExpandListArgument(cxxDefs, defs, true);
884
885     // the list must contain only definition-value pairs:
886     if ((defs.size() % 2) == 0)
887       {
888       std::vector<std::string>::const_iterator di = defs.begin();
889       while (di != defs.end())
890         {
891         std::string def = *di;
892         ++di;
893         std::string val;
894         if (di != defs.end())
895           {
896           val = *di;
897           ++di;
898           }
899
900         // insert the definition if not already added.
901         if(emmited.find(def) == emmited.end())
902           {
903           emmited.insert(def);
904           fout << "<pathentry kind=\"mac\" name=\"" << def
905                << "\" path=\"\" value=\"" << this->EscapeForXML(val)
906                << "\"/>\n";
907           }
908         }
909       }
910     }
911
912   // include dirs
913   emmited.clear();
914   for (std::vector<cmLocalGenerator*>::const_iterator
915         it = this->GlobalGenerator->GetLocalGenerators().begin();
916        it != this->GlobalGenerator->GetLocalGenerators().end();
917        ++it)
918     {
919     cmGeneratorTargetsType targets = (*it)->GetMakefile()
920                                         ->GetGeneratorTargets();
921     for (cmGeneratorTargetsType::iterator l = targets.begin();
922          l != targets.end(); ++l)
923       {
924       if (l->first->IsImported())
925         {
926         continue;
927         }
928       std::vector<std::string> includeDirs;
929       const char *config = mf->GetDefinition("CMAKE_BUILD_TYPE");
930       (*it)->GetIncludeDirectories(includeDirs, l->second, "C", config);
931       this->AppendIncludeDirectories(fout, includeDirs, emmited);
932       }
933     }
934   // now also the system include directories, in case we found them in
935   // CMakeSystemSpecificInformation.cmake. This makes Eclipse find the
936   // standard headers.
937   std::string compiler = mf->GetSafeDefinition("CMAKE_C_COMPILER");
938   if (!compiler.empty())
939     {
940     std::string systemIncludeDirs = mf->GetSafeDefinition(
941                                 "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
942     std::vector<std::string> dirs;
943     cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
944     this->AppendIncludeDirectories(fout, dirs, emmited);
945     }
946   compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
947   if (!compiler.empty())
948     {
949     std::string systemIncludeDirs = mf->GetSafeDefinition(
950                               "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
951     std::vector<std::string> dirs;
952     cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
953     this->AppendIncludeDirectories(fout, dirs, emmited);
954     }
955
956   fout << "</storageModule>\n";
957
958   // add build targets
959   fout <<
960     "<storageModule moduleId=\"org.eclipse.cdt.make.core.buildtargets\">\n"
961     "<buildTargets>\n"
962     ;
963   emmited.clear();
964   const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
965   const std::string makeArgs = mf->GetSafeDefinition(
966                                                "CMAKE_ECLIPSE_MAKE_ARGUMENTS");
967   const std::string cmake = mf->GetRequiredDefinition("CMAKE_COMMAND");
968
969   cmGlobalGenerator* generator
970     = const_cast<cmGlobalGenerator*>(this->GlobalGenerator);
971
972   std::string allTarget;
973   std::string cleanTarget;
974   if (generator->GetAllTargetName())
975     {
976     allTarget = generator->GetAllTargetName();
977     }
978   if (generator->GetCleanTargetName())
979     {
980     cleanTarget = generator->GetCleanTargetName();
981     }
982
983   // add all executable and library targets and some of the GLOBAL
984   // and UTILITY targets
985   for (std::vector<cmLocalGenerator*>::const_iterator
986         it = this->GlobalGenerator->GetLocalGenerators().begin();
987        it != this->GlobalGenerator->GetLocalGenerators().end();
988        ++it)
989     {
990     const cmTargets& targets = (*it)->GetMakefile()->GetTargets();
991     cmMakefile* makefile=(*it)->GetMakefile();
992     std::string subdir = (*it)->Convert(makefile->GetCurrentOutputDirectory(),
993                            cmLocalGenerator::HOME_OUTPUT);
994     if (subdir == ".")
995       {
996       subdir = "";
997       }
998
999     for(cmTargets::const_iterator ti=targets.begin(); ti!=targets.end(); ++ti)
1000       {
1001       switch(ti->second.GetType())
1002         {
1003         case cmTarget::GLOBAL_TARGET:
1004           {
1005           bool insertTarget = false;
1006           // Only add the global targets from CMAKE_BINARY_DIR,
1007           // not from the subdirs
1008           if (subdir.empty())
1009            {
1010            insertTarget = true;
1011            // only add the "edit_cache" target if it's not ccmake, because
1012            // this will not work within the IDE
1013            if (ti->first == "edit_cache")
1014              {
1015              const char* editCommand = makefile->GetDefinition
1016                                                         ("CMAKE_EDIT_COMMAND");
1017              if (editCommand == 0)
1018                {
1019                insertTarget = false;
1020                }
1021              else if (strstr(editCommand, "ccmake")!=NULL)
1022                {
1023                insertTarget = false;
1024                }
1025              }
1026            }
1027          if (insertTarget)
1028            {
1029            this->AppendTarget(fout, ti->first, make, makeArgs, subdir, ": ");
1030            }
1031          }
1032          break;
1033        case cmTarget::UTILITY:
1034          // Add all utility targets, except the Nightly/Continuous/
1035          // Experimental-"sub"targets as e.g. NightlyStart
1036          if (((ti->first.find("Nightly")==0)   &&(ti->first!="Nightly"))
1037           || ((ti->first.find("Continuous")==0)&&(ti->first!="Continuous"))
1038           || ((ti->first.find("Experimental")==0)
1039                                             && (ti->first!="Experimental")))
1040            {
1041            break;
1042            }
1043
1044          this->AppendTarget(fout, ti->first, make, makeArgs, subdir, ": ");
1045          break;
1046        case cmTarget::EXECUTABLE:
1047        case cmTarget::STATIC_LIBRARY:
1048        case cmTarget::SHARED_LIBRARY:
1049        case cmTarget::MODULE_LIBRARY:
1050        case cmTarget::OBJECT_LIBRARY:
1051          {
1052          const char* prefix = (ti->second.GetType()==cmTarget::EXECUTABLE ?
1053                                                           "[exe] " : "[lib] ");
1054          this->AppendTarget(fout, ti->first, make, makeArgs, subdir, prefix);
1055          std::string fastTarget = ti->first;
1056          fastTarget += "/fast";
1057          this->AppendTarget(fout, fastTarget, make, makeArgs, subdir, prefix);
1058
1059          // Add Build and Clean targets in the virtual folder of targets:
1060          if (this->SupportsVirtualFolders)
1061           {
1062           std::string virtDir = "[Targets]/";
1063           virtDir += prefix;
1064           virtDir += ti->first;
1065           std::string buildArgs = "-C \"";
1066           buildArgs += makefile->GetHomeOutputDirectory();
1067           buildArgs += "\" ";
1068           buildArgs += makeArgs;
1069           this->AppendTarget(fout, "Build", make, buildArgs, virtDir, "",
1070                              ti->first.c_str());
1071
1072           std::string cleanArgs = "-E chdir \"";
1073           cleanArgs += makefile->GetCurrentOutputDirectory();
1074           cleanArgs += "\" \"";
1075           cleanArgs += cmake;
1076           cleanArgs += "\" -P \"";
1077           cleanArgs += (*it)->GetTargetDirectory(ti->second);
1078           cleanArgs += "/cmake_clean.cmake\"";
1079           this->AppendTarget(fout, "Clean", cmake, cleanArgs, virtDir, "", "");
1080           }
1081          }
1082          break;
1083         default:
1084           break;
1085         }
1086       }
1087
1088     // insert the all and clean targets in every subdir
1089     if (!allTarget.empty())
1090       {
1091       this->AppendTarget(fout, allTarget, make, makeArgs, subdir, ": ");
1092       }
1093     if (!cleanTarget.empty())
1094       {
1095       this->AppendTarget(fout, cleanTarget, make, makeArgs, subdir, ": ");
1096       }
1097
1098     //insert rules for compiling, preprocessing and assembling individual files
1099     std::vector<std::string> objectFileTargets;
1100     (*it)->GetIndividualFileTargets(objectFileTargets);
1101     for(std::vector<std::string>::const_iterator fit=objectFileTargets.begin();
1102         fit != objectFileTargets.end();
1103         ++fit)
1104       {
1105       const char* prefix = "[obj] ";
1106       if ((*fit)[fit->length()-1] == 's')
1107         {
1108         prefix = "[to asm] ";
1109         }
1110       else if ((*fit)[fit->length()-1] == 'i')
1111         {
1112         prefix = "[pre] ";
1113         }
1114       this->AppendTarget(fout, *fit, make, makeArgs, subdir, prefix);
1115       }
1116     }
1117
1118   fout << "</buildTargets>\n"
1119           "</storageModule>\n"
1120           ;
1121
1122   this->AppendStorageScanners(fout, *mf);
1123
1124   fout << "</cconfiguration>\n"
1125           "</storageModule>\n"
1126           "<storageModule moduleId=\"cdtBuildSystem\" version=\"4.0.0\">\n"
1127           "<project id=\"" << this->EscapeForXML(mf->GetProjectName())
1128        << ".null.1\" name=\"" << this->EscapeForXML(mf->GetProjectName())
1129        << "\"/>\n"
1130           "</storageModule>\n"
1131           "</cproject>\n"
1132           ;
1133 }
1134
1135 //----------------------------------------------------------------------------
1136 std::string
1137 cmExtraEclipseCDT4Generator::GetEclipsePath(const std::string& path)
1138 {
1139 #if defined(__CYGWIN__)
1140   std::string cmd = "cygpath -m " + path;
1141   std::string out;
1142   if (!cmSystemTools::RunCommand(cmd.c_str(), out, 0, false))
1143     {
1144     return path;
1145     }
1146   else
1147     {
1148     out.erase(out.find_last_of('\n'));
1149     return out;
1150     }
1151 #else
1152   return path;
1153 #endif
1154 }
1155
1156 std::string
1157 cmExtraEclipseCDT4Generator::GetPathBasename(const std::string& path)
1158 {
1159   std::string outputBasename = path;
1160   while (outputBasename.size() > 0 &&
1161          (outputBasename[outputBasename.size() - 1] == '/' ||
1162           outputBasename[outputBasename.size() - 1] == '\\'))
1163     {
1164     outputBasename.resize(outputBasename.size() - 1);
1165     }
1166   std::string::size_type loc = outputBasename.find_last_of("/\\");
1167   if (loc != std::string::npos)
1168     {
1169     outputBasename = outputBasename.substr(loc + 1);
1170     }
1171
1172   return outputBasename;
1173 }
1174
1175 std::string
1176 cmExtraEclipseCDT4Generator::GenerateProjectName(const std::string& name,
1177                                                  const std::string& type,
1178                                                  const std::string& path)
1179 {
1180   return cmExtraEclipseCDT4Generator::EscapeForXML(name)
1181                                 +(type.empty() ? "" : "-") + type + "@" + path;
1182 }
1183
1184 std::string cmExtraEclipseCDT4Generator::EscapeForXML(const std::string& value)
1185 {
1186   std::string str = value;
1187   cmSystemTools::ReplaceString(str, "&", "&amp;");
1188   cmSystemTools::ReplaceString(str, "<", "&lt;");
1189   cmSystemTools::ReplaceString(str, ">", "&gt;");
1190   cmSystemTools::ReplaceString(str, "\"", "&quot;");
1191   // NOTE: This one is not necessary, since as of Eclipse CDT4 it will
1192   //       automatically change this to the original value (').
1193   //cmSystemTools::ReplaceString(str, "'", "&apos;");
1194   return str;
1195 }
1196
1197 //----------------------------------------------------------------------------
1198 // Helper functions
1199 //----------------------------------------------------------------------------
1200 void cmExtraEclipseCDT4Generator
1201 ::AppendStorageScanners(cmGeneratedFileStream& fout,
1202                         const cmMakefile& makefile)
1203 {
1204   // we need the "make" and the C (or C++) compiler which are used, Alex
1205   std::string make = makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
1206   std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
1207   std::string arg1 = makefile.GetSafeDefinition("CMAKE_C_COMPILER_ARG1");
1208   if (compiler.empty())
1209     {
1210     compiler = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER");
1211     arg1 = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER_ARG1");
1212     }
1213   if (compiler.empty())  //Hmm, what to do now ?
1214     {
1215     compiler = "gcc";
1216     }
1217
1218   // the following right now hardcodes gcc behaviour :-/
1219   std::string compilerArgs =
1220                          "-E -P -v -dD ${plugin_state_location}/${specs_file}";
1221   if (!arg1.empty())
1222     {
1223     arg1 += " ";
1224     compilerArgs = arg1 + compilerArgs;
1225     }
1226
1227   fout <<
1228     "<storageModule moduleId=\"scannerConfiguration\">\n"
1229     "<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\""
1230     " selectedProfileId="
1231     "\"org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile\"/>\n"
1232     ;
1233   cmExtraEclipseCDT4Generator::AppendScannerProfile(fout,
1234     "org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile",
1235     true, "", true, "specsFile",
1236     compilerArgs,
1237     compiler, true, true);
1238   cmExtraEclipseCDT4Generator::AppendScannerProfile(fout,
1239     "org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile",
1240     true, "", true, "makefileGenerator",
1241     "-f ${project_name}_scd.mk",
1242     make, true, true);
1243
1244   fout << "</storageModule>\n";
1245 }
1246
1247 // The prefix is prepended before the actual name of the target. The purpose
1248 // of that is to sort the targets in the view of Eclipse, so that at first
1249 // the global/utility/all/clean targets appear ": ", then the executable
1250 // targets "[exe] ", then the libraries "[lib]", then the rules for the
1251 // object files "[obj]", then for preprocessing only "[pre] " and
1252 // finally the assembly files "[to asm] ". Note the "to" in "to asm",
1253 // without it, "asm" would be the first targets in the list, with the "to"
1254 // they are the last targets, which makes more sense.
1255 void cmExtraEclipseCDT4Generator::AppendTarget(cmGeneratedFileStream& fout,
1256                                                const std::string&     target,
1257                                                const std::string&     make,
1258                                                const std::string&     makeArgs,
1259                                                const std::string&     path,
1260                                                const char* prefix,
1261                                                const char* makeTarget
1262                                               )
1263 {
1264   std::string targetXml = cmExtraEclipseCDT4Generator::EscapeForXML(target);
1265   std::string makeTargetXml = targetXml;
1266   if (makeTarget != NULL)
1267     {
1268     makeTargetXml = cmExtraEclipseCDT4Generator::EscapeForXML(makeTarget);
1269     }
1270   cmExtraEclipseCDT4Generator::EscapeForXML(target);
1271   std::string pathXml = cmExtraEclipseCDT4Generator::EscapeForXML(path);
1272   fout <<
1273     "<target name=\"" << prefix << targetXml << "\""
1274     " path=\"" << pathXml.c_str() << "\""
1275     " targetID=\"org.eclipse.cdt.make.MakeTargetBuilder\">\n"
1276     "<buildCommand>"
1277     << cmExtraEclipseCDT4Generator::GetEclipsePath(make)
1278     << "</buildCommand>\n"
1279     "<buildArguments>"  << makeArgs << "</buildArguments>\n"
1280     "<buildTarget>" << makeTargetXml << "</buildTarget>\n"
1281     "<stopOnError>true</stopOnError>\n"
1282     "<useDefaultCommand>false</useDefaultCommand>\n"
1283     "</target>\n"
1284     ;
1285 }
1286
1287 void cmExtraEclipseCDT4Generator
1288 ::AppendScannerProfile(cmGeneratedFileStream& fout,
1289                        const std::string&     profileID,
1290                        bool                   openActionEnabled,
1291                        const std::string&     openActionFilePath,
1292                        bool                   pParserEnabled,
1293                        const std::string&     scannerInfoProviderID,
1294                        const std::string&     runActionArguments,
1295                        const std::string&     runActionCommand,
1296                        bool                   runActionUseDefault,
1297                        bool                   sipParserEnabled)
1298 {
1299   fout <<
1300     "<profile id=\"" << profileID << "\">\n"
1301     "<buildOutputProvider>\n"
1302     "<openAction enabled=\"" << (openActionEnabled ? "true" : "false")
1303     << "\" filePath=\"" << openActionFilePath << "\"/>\n"
1304     "<parser enabled=\"" << (pParserEnabled ? "true" : "false") << "\"/>\n"
1305     "</buildOutputProvider>\n"
1306     "<scannerInfoProvider id=\"" << scannerInfoProviderID << "\">\n"
1307     "<runAction arguments=\"" << runActionArguments << "\""
1308     " command=\"" << runActionCommand
1309     << "\" useDefault=\"" << (runActionUseDefault ? "true":"false") << "\"/>\n"
1310     "<parser enabled=\"" << (sipParserEnabled ? "true" : "false") << "\"/>\n"
1311     "</scannerInfoProvider>\n"
1312     "</profile>\n"
1313     ;
1314 }
1315
1316 void cmExtraEclipseCDT4Generator
1317 ::AppendLinkedResource (cmGeneratedFileStream& fout,
1318                         const std::string&     name,
1319                         const std::string&     path,
1320                         LinkType linkType)
1321 {
1322   const char* locationTag = "location";
1323   const char* typeTag = "2";
1324   if (linkType == VirtualFolder) // ... and not a linked folder
1325     {
1326     locationTag = "locationURI";
1327     }
1328   if (linkType == LinkToFile)
1329     {
1330     typeTag = "1";
1331     }
1332
1333   fout <<
1334     "\t\t<link>\n"
1335     "\t\t\t<name>"
1336     << cmExtraEclipseCDT4Generator::EscapeForXML(name)
1337     << "</name>\n"
1338     "\t\t\t<type>" << typeTag << "</type>\n"
1339     "\t\t\t<" << locationTag << ">"
1340     << cmExtraEclipseCDT4Generator::EscapeForXML(path)
1341     << "</" << locationTag << ">\n"
1342     "\t\t</link>\n"
1343     ;
1344 }