Fix Xcode project references to the source tree
[cmake.git] / Source / cmExtraEclipseCDT4Generator.cxx
blob524592d2461f0bf12de4d765f65f6dcff730f2c2
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmExtraEclipseCDT4Generator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-16 22:01:23 $
7 Version: $Revision: 1.27 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 Copyright (c) 2004 Alexander Neundorf neundorf@kde.org, All rights reserved.
11 Copyright (c) 2007 Miguel A. Figueroa-Villanueva. All rights reserved.
12 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
14 This software is distributed WITHOUT ANY WARRANTY; without even
15 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 PURPOSE. See the above copyright notices for more information.
18 =========================================================================*/
20 #include "cmExtraEclipseCDT4Generator.h"
21 #include "cmGlobalUnixMakefileGenerator3.h"
22 #include "cmLocalUnixMakefileGenerator3.h"
23 #include "cmMakefile.h"
24 #include "cmGeneratedFileStream.h"
25 #include "cmTarget.h"
27 #include "cmSystemTools.h"
28 #include <stdlib.h>
29 #include <assert.h>
31 //----------------------------------------------------------------------------
32 cmExtraEclipseCDT4Generator
33 ::cmExtraEclipseCDT4Generator() : cmExternalMakefileProjectGenerator()
35 // TODO: Verify if __CYGWIN__ should be checked.
36 //#if defined(_WIN32) && !defined(__CYGWIN__)
37 #if defined(_WIN32)
38 this->SupportedGlobalGenerators.push_back("NMake Makefiles");
39 this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
40 // this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
41 #endif
42 this->SupportedGlobalGenerators.push_back("Unix Makefiles");
45 //----------------------------------------------------------------------------
46 void cmExtraEclipseCDT4Generator
47 ::GetDocumentation(cmDocumentationEntry& entry, const char*) const
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 "and will have a linked resource to every subdirectory which "
54 "features a CMakeLists.txt file containing a PROJECT() call."
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.";
60 //----------------------------------------------------------------------------
61 void cmExtraEclipseCDT4Generator
62 ::SetGlobalGenerator(cmGlobalGenerator* generator)
64 cmExternalMakefileProjectGenerator::SetGlobalGenerator(generator);
65 cmGlobalUnixMakefileGenerator3* mf
66 = static_cast<cmGlobalUnixMakefileGenerator3*>(generator);
67 mf->SetToolSupportsColor(true);
70 //----------------------------------------------------------------------------
71 void cmExtraEclipseCDT4Generator::Generate()
73 const cmMakefile* mf
74 = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
76 // TODO: Decide if these are local or member variables
77 this->HomeDirectory = mf->GetHomeDirectory();
78 this->HomeOutputDirectory = mf->GetHomeOutputDirectory();
80 this->IsOutOfSourceBuild = (this->HomeDirectory!=this->HomeOutputDirectory);
82 this->GenerateSourceProject = (this->IsOutOfSourceBuild &&
83 mf->IsOn("ECLIPSE_CDT4_GENERATE_SOURCE_PROJECT"));
85 // NOTE: This is not good, since it pollutes the source tree. However,
86 // Eclipse doesn't allow CVS/SVN to work when the .project is not in
87 // the cvs/svn root directory. Hence, this is provided as an option.
88 if (this->GenerateSourceProject)
90 // create .project file in the source tree
91 this->CreateSourceProjectFile();
94 // create a .project file
95 this->CreateProjectFile();
97 // create a .cproject file
98 this->CreateCProjectFile();
101 void cmExtraEclipseCDT4Generator::CreateSourceProjectFile() const
103 assert(this->HomeDirectory != this->HomeOutputDirectory);
105 // set up the project name: <project>-Source@<baseSourcePathName>
106 const cmMakefile* mf
107 = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
108 std::string name = this->GenerateProjectName(mf->GetProjectName(), "Source",
109 this->GetPathBasename(this->HomeDirectory));
111 const std::string filename = this->HomeDirectory + "/.project";
112 cmGeneratedFileStream fout(filename.c_str());
113 if (!fout)
115 return;
118 fout <<
119 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
120 "<projectDescription>\n"
121 "\t<name>" << name << "</name>\n"
122 "\t<comment></comment>\n"
123 "\t<projects>\n"
124 "\t</projects>\n"
125 "\t<buildSpec>\n"
126 "\t</buildSpec>\n"
127 "\t<natures>\n"
128 "\t</natures>\n"
129 "</projectDescription>\n"
133 //----------------------------------------------------------------------------
134 void cmExtraEclipseCDT4Generator::CreateProjectFile()
136 const cmMakefile* mf
137 = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
139 const std::string filename = this->HomeOutputDirectory + "/.project";
141 cmGeneratedFileStream fout(filename.c_str());
142 if (!fout)
144 return;
147 fout <<
148 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
149 "<projectDescription>\n"
150 "\t<name>" <<
151 this->GenerateProjectName(mf->GetProjectName(),
152 mf->GetDefinition("CMAKE_BUILD_TYPE"),
153 this->GetPathBasename(this->HomeOutputDirectory))
154 << "</name>\n"
155 "\t<comment></comment>\n"
156 "\t<projects>\n"
157 "\t</projects>\n"
158 "\t<buildSpec>\n"
159 "\t\t<buildCommand>\n"
160 "\t\t\t<name>org.eclipse.cdt.make.core.makeBuilder</name>\n"
161 "\t\t\t<triggers>clean,full,incremental,</triggers>\n"
162 "\t\t\t<arguments>\n"
165 // use clean target
166 fout <<
167 "\t\t\t\t<dictionary>\n"
168 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>\n"
169 "\t\t\t\t\t<value>clean</value>\n"
170 "\t\t\t\t</dictionary>\n"
171 "\t\t\t\t<dictionary>\n"
172 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enableCleanBuild</key>\n"
173 "\t\t\t\t\t<value>true</value>\n"
174 "\t\t\t\t</dictionary>\n"
175 "\t\t\t\t<dictionary>\n"
176 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.append_environment</key>\n"
177 "\t\t\t\t\t<value>true</value>\n"
178 "\t\t\t\t</dictionary>\n"
179 "\t\t\t\t<dictionary>\n"
180 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.stopOnError</key>\n"
181 "\t\t\t\t\t<value>true</value>\n"
182 "\t\t\t\t</dictionary>\n"
185 // set the make command
186 std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
187 fout <<
188 "\t\t\t\t<dictionary>\n"
189 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>\n"
190 "\t\t\t\t\t<value>true</value>\n"
191 "\t\t\t\t</dictionary>\n"
192 "\t\t\t\t<dictionary>\n"
193 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.command</key>\n"
194 "\t\t\t\t\t<value>" + this->GetEclipsePath(make) + "</value>\n"
195 "\t\t\t\t</dictionary>\n"
196 "\t\t\t\t<dictionary>\n"
197 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.contents</key>\n"
198 "\t\t\t\t\t<value>org.eclipse.cdt.make.core.activeConfigSettings</value>\n"
199 "\t\t\t\t</dictionary>\n"
200 "\t\t\t\t<dictionary>\n"
201 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.target.inc</key>\n"
202 "\t\t\t\t\t<value>all</value>\n"
203 "\t\t\t\t</dictionary>\n"
204 "\t\t\t\t<dictionary>\n"
205 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.arguments</key>\n"
206 "\t\t\t\t\t<value></value>\n"
207 "\t\t\t\t</dictionary>\n"
208 "\t\t\t\t<dictionary>\n"
209 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.buildLocation</key>\n"
210 "\t\t\t\t\t<value>"
211 << this->GetEclipsePath(this->HomeOutputDirectory) << "</value>\n"
212 "\t\t\t\t</dictionary>\n"
213 "\t\t\t\t<dictionary>\n"
214 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>\n"
215 "\t\t\t\t\t<value>false</value>\n"
216 "\t\t\t\t</dictionary>\n"
219 // set project specific environment
220 fout <<
221 "\t\t\t\t<dictionary>\n"
222 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.environment</key>\n"
223 "\t\t\t\t\t<value>VERBOSE=1|</value>\n" // enforce VERBOSE Makefile output
224 "\t\t\t\t\t<value>"
226 // set vsvars32.bat environment available at CMake time,
227 // but not necessarily when eclipse is open
228 if (make.find("nmake") != std::string::npos)
230 if (getenv("PATH"))
232 fout << "PATH=" << getenv("PATH") << "|";
234 if (getenv("INCLUDE"))
236 fout << "INCLUDE=" << getenv("INCLUDE") << "|";
238 if (getenv("LIB"))
240 fout << "LIB=" << getenv("LIB") << "|";
242 if (getenv("LIBPATH"))
244 fout << "LIBPATH=" << getenv("LIBPATH") << "|";
247 fout <<
248 "</value>\n"
249 "\t\t\t\t</dictionary>\n"
252 fout <<
253 "\t\t\t\t<dictionary>\n"
254 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enableFullBuild</key>\n"
255 "\t\t\t\t\t<value>true</value>\n"
256 "\t\t\t\t</dictionary>\n"
257 "\t\t\t\t<dictionary>\n"
258 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.target.auto</key>\n"
259 "\t\t\t\t\t<value>all</value>\n"
260 "\t\t\t\t</dictionary>\n"
261 "\t\t\t\t<dictionary>\n"
262 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.enableAutoBuild</key>\n"
263 "\t\t\t\t\t<value>false</value>\n"
264 "\t\t\t\t</dictionary>\n"
265 "\t\t\t\t<dictionary>\n"
266 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.target.clean</key>\n"
267 "\t\t\t\t\t<value>clean</value>\n"
268 "\t\t\t\t</dictionary>\n"
269 "\t\t\t\t<dictionary>\n"
270 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.fullBuildTarget</key>\n"
271 "\t\t\t\t\t<value>all</value>\n"
272 "\t\t\t\t</dictionary>\n"
273 "\t\t\t\t<dictionary>\n"
274 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.buildArguments</key>\n"
275 "\t\t\t\t\t<value></value>\n"
276 "\t\t\t\t</dictionary>\n"
277 "\t\t\t\t<dictionary>\n"
278 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.build.location</key>\n"
279 "\t\t\t\t\t<value>"
280 << this->GetEclipsePath(this->HomeOutputDirectory) << "</value>\n"
281 "\t\t\t\t</dictionary>\n"
282 "\t\t\t\t<dictionary>\n"
283 "\t\t\t\t\t<key>org.eclipse.cdt.make.core.autoBuildTarget</key>\n"
284 "\t\t\t\t\t<value>all</value>\n"
285 "\t\t\t\t</dictionary>\n"
288 // set error parsers
289 fout <<
290 "\t\t\t\t<dictionary>\n"
291 "\t\t\t\t\t<key>org.eclipse.cdt.core.errorOutputParser</key>\n"
292 "\t\t\t\t\t<value>"
294 if (this->GetToolChainType(*mf) == EclipseToolchainOther)
296 fout << "org.eclipse.cdt.core.VCErrorParser;";
298 fout <<
299 "org.eclipse.cdt.core.MakeErrorParser;"
300 "org.eclipse.cdt.core.GCCErrorParser;"
301 "org.eclipse.cdt.core.GASErrorParser;"
302 "org.eclipse.cdt.core.GLDErrorParser;"
303 "</value>\n"
304 "\t\t\t\t</dictionary>\n"
307 fout <<
308 "\t\t\t</arguments>\n"
309 "\t\t</buildCommand>\n"
310 "\t\t<buildCommand>\n"
311 "\t\t\t<name>org.eclipse.cdt.make.core.ScannerConfigBuilder</name>\n"
312 "\t\t\t<arguments>\n"
313 "\t\t\t</arguments>\n"
314 "\t\t</buildCommand>\n"
315 "\t</buildSpec>\n"
318 // set natures for c/c++ projects
319 fout <<
320 "\t<natures>\n"
321 // TODO: ccnature only if it is c++ ???
322 "\t\t<nature>org.eclipse.cdt.core.ccnature</nature>\n"
323 "\t\t<nature>org.eclipse.cdt.make.core.makeNature</nature>\n"
324 "\t\t<nature>org.eclipse.cdt.make.core.ScannerConfigNature</nature>\n"
325 "\t\t<nature>org.eclipse.cdt.core.cnature</nature>\n"
326 "\t</natures>\n"
329 // TODO: refactor this
330 // create linked resources
331 if (this->IsOutOfSourceBuild)
333 fout << "\t<linkedResources>\n";
334 // for each sub project create a linked resource to the source dir
335 // - only if it is an out-of-source build
336 for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator
337 it = this->GlobalGenerator->GetProjectMap().begin();
338 it != this->GlobalGenerator->GetProjectMap().end();
339 ++it)
341 std::string linkSourceDirectory = this->GetEclipsePath(
342 it->second[0]->GetMakefile()->GetStartDirectory());
343 // .project dir can't be subdir of a linked resource dir
344 if (!cmSystemTools::IsSubDirectory(this->HomeOutputDirectory.c_str(),
345 linkSourceDirectory.c_str()))
347 this->AppendLinkedResource(fout, it->first,
348 this->GetEclipsePath(linkSourceDirectory));
349 this->SrcLinkedResources.push_back(it->first);
352 // for EXECUTABLE_OUTPUT_PATH when not in binary dir
353 this->AppendOutLinkedResource(fout,
354 mf->GetSafeDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY"),
355 mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"));
356 // for LIBRARY_OUTPUT_PATH when not in binary dir
357 this->AppendOutLinkedResource(fout,
358 mf->GetSafeDefinition("CMAKE_LIBRARY_OUTPUT_DIRECTORY"),
359 mf->GetSafeDefinition("LIBRARY_OUTPUT_PATH"));
361 fout << "\t</linkedResources>\n";
364 fout << "</projectDescription>\n";
367 //----------------------------------------------------------------------------
368 void cmExtraEclipseCDT4Generator::AppendIncludeDirectories(
369 cmGeneratedFileStream& fout,
370 const std::vector<std::string>& includeDirs,
371 std::set<std::string>& emittedDirs)
373 for(std::vector<std::string>::const_iterator inc = includeDirs.begin();
374 inc != includeDirs.end();
375 ++inc)
377 if (!inc->empty())
379 std::string dir = cmSystemTools::CollapseFullPath(inc->c_str());
380 if(emittedDirs.find(dir) == emittedDirs.end())
382 emittedDirs.insert(dir);
383 fout << "<pathentry include=\""
384 << cmExtraEclipseCDT4Generator::GetEclipsePath(dir)
385 << "\" kind=\"inc\" path=\"\" system=\"true\"/>\n";
391 //----------------------------------------------------------------------------
392 void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
394 std::set<std::string> emmited;
396 const cmMakefile* mf
397 = this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
399 const std::string filename = this->HomeOutputDirectory + "/.cproject";
401 cmGeneratedFileStream fout(filename.c_str());
402 if (!fout)
404 return;
407 // add header
408 fout <<
409 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
410 "<?fileVersion 4.0.0?>\n\n"
411 "<cproject>\n"
412 "<storageModule moduleId=\"org.eclipse.cdt.core.settings\">\n"
415 fout << "<cconfiguration id=\"org.eclipse.cdt.core.default.config.1\">\n";
417 // Configuration settings...
418 fout <<
419 "<storageModule"
420 " buildSystemId=\"org.eclipse.cdt.core.defaultConfigDataProvider\""
421 " id=\"org.eclipse.cdt.core.default.config.1\""
422 " moduleId=\"org.eclipse.cdt.core.settings\" name=\"Configuration\">\n"
423 "<externalSettings/>\n"
424 "<extensions>\n"
426 // TODO: refactor this out...
427 switch (this->GetToolChainType(*mf))
429 case EclipseToolchainLinux :
430 fout << "<extension id=\"org.eclipse.cdt.core.ELF\""
431 " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
433 fout << "<extension id=\"org.eclipse.cdt.core.GNU_ELF\""
434 " point=\"org.eclipse.cdt.core.BinaryParser\">\n"
435 "<attribute key=\"addr2line\" value=\"addr2line\"/>\n"
436 "<attribute key=\"c++filt\" value=\"c++filt\"/>\n"
437 "</extension>\n"
439 break;
440 case EclipseToolchainCygwin :
441 fout << "<extension id=\"org.eclipse.cdt.core.Cygwin_PE\""
442 " point=\"org.eclipse.cdt.core.BinaryParser\">\n"
443 "<attribute key=\"addr2line\" value=\"addr2line\"/>\n"
444 "<attribute key=\"c++filt\" value=\"c++filt\"/>\n"
445 "<attribute key=\"cygpath\" value=\"cygpath\"/>\n"
446 "<attribute key=\"nm\" value=\"nm\"/>\n"
447 "</extension>\n"
449 break;
450 case EclipseToolchainMinGW :
451 fout << "<extension id=\"org.eclipse.cdt.core.PE\""
452 " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
454 break;
455 case EclipseToolchainSolaris :
456 fout << "<extension id=\"org.eclipse.cdt.core.ELF\""
457 " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
459 break;
460 case EclipseToolchainMacOSX :
461 fout << "<extension id=\"org.eclipse.cdt.core.MachO\""
462 " point=\"org.eclipse.cdt.core.BinaryParser\">\n"
463 "<attribute key=\"c++filt\" value=\"c++filt\"/>\n"
464 "</extension>\n"
466 break;
467 case EclipseToolchainOther :
468 fout << "<extension id=\"org.eclipse.cdt.core.PE\""
469 " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
471 fout << "<extension id=\"org.eclipse.cdt.core.ELF\""
472 " point=\"org.eclipse.cdt.core.BinaryParser\"/>\n"
474 break;
475 default :
476 // *** Should never get here ***
477 fout << "<error_toolchain_type/>\n";
479 fout << "</extensions>\n"
480 "</storageModule>\n"
483 // ???
484 fout <<
485 "<storageModule moduleId=\"org.eclipse.cdt.core.language.mapping\">\n"
486 "<project-mappings/>\n"
487 "</storageModule>\n"
490 // ???
491 fout<<"<storageModule moduleId=\"org.eclipse.cdt.core.externalSettings\"/>\n"
494 // set the path entries (includes, libs, source dirs, etc.)
495 fout << "<storageModule moduleId=\"org.eclipse.cdt.core.pathentry\">\n"
497 // for each sub project with a linked resource to the source dir:
498 // - make it type 'src'
499 // - and exclude it from type 'out'
500 std::string excludeFromOut;
501 for (std::vector<std::string>::const_iterator
502 it = this->SrcLinkedResources.begin();
503 it != this->SrcLinkedResources.end();
504 ++it)
506 fout << "<pathentry kind=\"src\" path=\"" << *it << "\"/>\n";
508 // exlude source directory from output search path
509 // - only if not named the same as an output directory
510 if (!cmSystemTools::FileIsDirectory(
511 std::string(this->HomeOutputDirectory + "/" + *it).c_str()))
513 excludeFromOut += *it + "/|";
516 excludeFromOut += "**/CMakeFiles/";
517 fout << "<pathentry excluding=\"" << excludeFromOut
518 << "\" kind=\"out\" path=\"\"/>\n";
519 // add output entry for EXECUTABLE_OUTPUT_PATH and LIBRARY_OUTPUT_PATH
520 // - if it is a subdir of homeOutputDirectory, there is no need to add it
521 // - if it is not then create a linked resource and add the linked name
522 // but check it doesn't conflict with other linked resources names
523 for (std::vector<std::string>::const_iterator
524 it = this->OutLinkedResources.begin();
525 it != this->OutLinkedResources.end();
526 ++it)
528 fout << "<pathentry kind=\"out\" path=\"" << *it << "\"/>\n";
531 // add pre-processor definitions to allow eclipse to gray out sections
532 emmited.clear();
533 for (std::vector<cmLocalGenerator*>::const_iterator
534 it = this->GlobalGenerator->GetLocalGenerators().begin();
535 it != this->GlobalGenerator->GetLocalGenerators().end();
536 ++it)
539 if(const char* cdefs = (*it)->GetMakefile()->GetProperty(
540 "COMPILE_DEFINITIONS"))
542 // Expand the list.
543 std::vector<std::string> defs;
544 cmSystemTools::ExpandListArgument(cdefs, defs);
546 for(std::vector<std::string>::const_iterator di = defs.begin();
547 di != defs.end(); ++di)
549 std::string::size_type equals = di->find('=', 0);
550 std::string::size_type enddef = di->length();
552 std::string def;
553 std::string val;
554 if (equals != std::string::npos && equals < enddef)
556 // we have -DFOO=BAR
557 def = di->substr(0, equals);
558 val = di->substr(equals + 1, enddef - equals + 1);
560 else
562 // we have -DFOO
563 def = *di;
566 // insert the definition if not already added.
567 if(emmited.find(def) == emmited.end())
569 emmited.insert(def);
570 fout << "<pathentry kind=\"mac\" name=\"" << def
571 << "\" path=\"\" value=\"" << this->EscapeForXML(val)
572 << "\"/>\n";
577 // add system defined c macros
578 const char* cDefs=mf->GetDefinition("CMAKE_ECLIPSE_C_SYSTEM_DEFINED_MACROS");
579 if(cDefs)
581 // Expand the list.
582 std::vector<std::string> defs;
583 cmSystemTools::ExpandListArgument(cDefs, defs, true);
585 // the list must contain only definition-value pairs:
586 if ((defs.size() % 2) == 0)
588 std::vector<std::string>::const_iterator di = defs.begin();
589 while (di != defs.end())
591 std::string def = *di;
592 ++di;
593 std::string val;
594 if (di != defs.end())
596 val = *di;
597 ++di;
600 // insert the definition if not already added.
601 if(emmited.find(def) == emmited.end())
603 emmited.insert(def);
604 fout << "<pathentry kind=\"mac\" name=\"" << def
605 << "\" path=\"\" value=\"" << this->EscapeForXML(val)
606 << "\"/>\n";
611 // add system defined c++ macros
612 const char* cxxDefs = mf->GetDefinition(
613 "CMAKE_ECLIPSE_CXX_SYSTEM_DEFINED_MACROS");
614 if(cxxDefs)
616 // Expand the list.
617 std::vector<std::string> defs;
618 cmSystemTools::ExpandListArgument(cxxDefs, defs, true);
620 // the list must contain only definition-value pairs:
621 if ((defs.size() % 2) == 0)
623 std::vector<std::string>::const_iterator di = defs.begin();
624 while (di != defs.end())
626 std::string def = *di;
627 ++di;
628 std::string val;
629 if (di != defs.end())
631 val = *di;
632 ++di;
635 // insert the definition if not already added.
636 if(emmited.find(def) == emmited.end())
638 emmited.insert(def);
639 fout << "<pathentry kind=\"mac\" name=\"" << def
640 << "\" path=\"\" value=\"" << this->EscapeForXML(val)
641 << "\"/>\n";
647 // include dirs
648 emmited.clear();
649 for (std::vector<cmLocalGenerator*>::const_iterator
650 it = this->GlobalGenerator->GetLocalGenerators().begin();
651 it != this->GlobalGenerator->GetLocalGenerators().end();
652 ++it)
654 const std::vector<std::string>& includeDirs
655 = (*it)->GetMakefile()->GetIncludeDirectories();
656 this->AppendIncludeDirectories(fout, includeDirs, emmited);
658 // now also the system include directories, in case we found them in
659 // CMakeSystemSpecificInformation.cmake. This makes Eclipse find the
660 // standard headers.
661 mf->GetDefinition("CMAKE_ECLIPSE_C_SYSTEM_INCLUDE_DIRS");
662 std::string compiler = mf->GetSafeDefinition("CMAKE_C_COMPILER");
663 if (!compiler.empty())
665 std::string systemIncludeDirs = mf->GetSafeDefinition(
666 "CMAKE_ECLIPSE_C_SYSTEM_INCLUDE_DIRS");
667 std::vector<std::string> dirs;
668 cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
669 this->AppendIncludeDirectories(fout, dirs, emmited);
671 compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
672 if (!compiler.empty())
674 std::string systemIncludeDirs = mf->GetSafeDefinition(
675 "CMAKE_ECLIPSE_CXX_SYSTEM_INCLUDE_DIRS");
676 std::vector<std::string> dirs;
677 cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
678 this->AppendIncludeDirectories(fout, dirs, emmited);
681 fout << "</storageModule>\n";
683 // add build targets
684 fout <<
685 "<storageModule moduleId=\"org.eclipse.cdt.make.core.buildtargets\">\n"
686 "<buildTargets>\n"
688 emmited.clear();
689 const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
690 cmGlobalGenerator* generator
691 = const_cast<cmGlobalGenerator*>(this->GlobalGenerator);
693 std::string allTarget;
694 std::string cleanTarget;
695 if (generator->GetAllTargetName())
697 allTarget = generator->GetAllTargetName();
699 if (generator->GetCleanTargetName())
701 cleanTarget = generator->GetCleanTargetName();
704 // add all executable and library targets and some of the GLOBAL
705 // and UTILITY targets
706 for (std::vector<cmLocalGenerator*>::const_iterator
707 it = this->GlobalGenerator->GetLocalGenerators().begin();
708 it != this->GlobalGenerator->GetLocalGenerators().end();
709 ++it)
711 const cmTargets& targets = (*it)->GetMakefile()->GetTargets();
712 cmMakefile* makefile=(*it)->GetMakefile();
713 std::string subdir = (*it)->Convert(makefile->GetCurrentOutputDirectory(),
714 cmLocalGenerator::HOME_OUTPUT);
715 if (subdir == ".")
717 subdir = "";
720 for(cmTargets::const_iterator ti=targets.begin(); ti!=targets.end(); ++ti)
722 switch(ti->second.GetType())
724 case cmTarget::GLOBAL_TARGET:
726 bool insertTarget = false;
727 // Only add the global targets from CMAKE_BINARY_DIR,
728 // not from the subdirs
729 if (subdir.empty())
731 insertTarget = true;
732 // only add the "edit_cache" target if it's not ccmake, because
733 // this will not work within the IDE
734 if (ti->first == "edit_cache")
736 if (strstr(makefile->GetRequiredDefinition
737 ("CMAKE_EDIT_COMMAND"), "ccmake")!=NULL)
739 insertTarget = false;
743 if (insertTarget)
745 this->AppendTarget(fout, ti->first, make, subdir, ": ");
748 break;
749 case cmTarget::UTILITY:
750 // Add all utility targets, except the Nightly/Continuous/
751 // Experimental-"sub"targets as e.g. NightlyStart
752 if (((ti->first.find("Nightly")==0) &&(ti->first!="Nightly"))
753 || ((ti->first.find("Continuous")==0)&&(ti->first!="Continuous"))
754 || ((ti->first.find("Experimental")==0)
755 && (ti->first!="Experimental")))
757 break;
760 this->AppendTarget(fout, ti->first, make, subdir, ": ");
761 break;
762 case cmTarget::EXECUTABLE:
763 case cmTarget::STATIC_LIBRARY:
764 case cmTarget::SHARED_LIBRARY:
765 case cmTarget::MODULE_LIBRARY:
767 const char* prefix = (ti->second.GetType()==cmTarget::EXECUTABLE ?
768 "[exe] " : "[lib] ");
769 this->AppendTarget(fout, ti->first, make, subdir, prefix);
770 std::string fastTarget = ti->first;
771 fastTarget += "/fast";
772 this->AppendTarget(fout, fastTarget, make, subdir, prefix);
774 break;
775 // ignore these:
776 case cmTarget::INSTALL_FILES:
777 case cmTarget::INSTALL_PROGRAMS:
778 case cmTarget::INSTALL_DIRECTORY:
779 default:
780 break;
784 // insert the all and clean targets in every subdir
785 if (!allTarget.empty())
787 this->AppendTarget(fout, allTarget, make, subdir, ": ");
789 if (!cleanTarget.empty())
791 this->AppendTarget(fout, cleanTarget, make, subdir, ": ");
794 //insert rules for compiling, preprocessing and assembling individual files
795 cmLocalUnixMakefileGenerator3* lumg=(cmLocalUnixMakefileGenerator3*)*it;
796 std::vector<std::string> objectFileTargets;
797 lumg->GetIndividualFileTargets(objectFileTargets);
798 for(std::vector<std::string>::const_iterator fit=objectFileTargets.begin();
799 fit != objectFileTargets.end();
800 ++fit)
802 const char* prefix = "[obj] ";
803 if ((*fit)[fit->length()-1] == 's')
805 prefix = "[to asm] ";
807 else if ((*fit)[fit->length()-1] == 'i')
809 prefix = "[pre] ";
811 this->AppendTarget(fout, *fit, make, subdir, prefix);
815 fout << "</buildTargets>\n"
816 "</storageModule>\n"
819 this->AppendStorageScanners(fout, *mf);
821 fout << "</cconfiguration>\n"
822 "</storageModule>\n"
823 "<storageModule moduleId=\"cdtBuildSystem\" version=\"4.0.0\">\n"
824 "<project id=\"" << mf->GetProjectName() << ".null.1\""
825 " name=\"" << mf->GetProjectName() << "\"/>\n"
826 "</storageModule>\n"
827 "</cproject>\n"
831 //----------------------------------------------------------------------------
832 cmExtraEclipseCDT4Generator::EclipseToolchainType
833 cmExtraEclipseCDT4Generator::GetToolChainType(const cmMakefile& makefile)
835 if (makefile.IsSet("UNIX"))
837 if (makefile.IsSet("CYGWIN"))
839 return EclipseToolchainCygwin;
841 if (makefile.IsSet("APPLE" ))
843 return EclipseToolchainMacOSX;
845 // *** how do I determine if it is Solaris ???
846 return EclipseToolchainLinux;
848 else if (makefile.IsSet("WIN32"))
850 if (makefile.IsSet("MINGW"))
852 return EclipseToolchainMinGW;
854 if (makefile.IsSet("MSYS" ))
856 return EclipseToolchainMinGW;
858 return EclipseToolchainOther;
860 else
862 return EclipseToolchainOther;
866 std::string
867 cmExtraEclipseCDT4Generator::GetEclipsePath(const std::string& path)
869 #if defined(__CYGWIN__)
870 std::string cmd = "cygpath -m " + path;
871 std::string out;
872 if (!cmSystemTools::RunCommand(cmd.c_str(), out, 0, false))
874 return path;
876 else
878 out.erase(out.find_last_of('\n'));
879 return out;
881 #else
882 return path;
883 #endif
886 std::string
887 cmExtraEclipseCDT4Generator::GetPathBasename(const std::string& path)
889 std::string outputBasename = path;
890 while (outputBasename.size() > 0 &&
891 (outputBasename[outputBasename.size() - 1] == '/' ||
892 outputBasename[outputBasename.size() - 1] == '\\'))
894 outputBasename.resize(outputBasename.size() - 1);
896 std::string::size_type loc = outputBasename.find_last_of("/\\");
897 if (loc != std::string::npos)
899 outputBasename = outputBasename.substr(loc + 1);
902 return outputBasename;
905 std::string
906 cmExtraEclipseCDT4Generator::GenerateProjectName(const std::string& name,
907 const std::string& type,
908 const std::string& path)
910 return name + (type.empty() ? "" : "-") + type + "@" + path;
913 std::string cmExtraEclipseCDT4Generator::EscapeForXML(const std::string& value)
915 std::string str = value;
916 cmSystemTools::ReplaceString(str, "&", "&amp;");
917 cmSystemTools::ReplaceString(str, "<", "&lt;");
918 cmSystemTools::ReplaceString(str, ">", "&gt;");
919 cmSystemTools::ReplaceString(str, "\"", "&quot;");
920 // NOTE: This one is not necessary, since as of Eclipse CDT4 it will
921 // automatically change this to the original value (').
922 //cmSystemTools::ReplaceString(str, "'", "&apos;");
923 return str;
926 //----------------------------------------------------------------------------
927 // Helper functions
928 //----------------------------------------------------------------------------
929 void cmExtraEclipseCDT4Generator
930 ::AppendStorageScanners(cmGeneratedFileStream& fout,
931 const cmMakefile& makefile)
933 // we need the "make" and the C (or C++) compiler which are used, Alex
934 std::string make = makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
935 std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
936 if (compiler.empty())
938 compiler = makefile.GetSafeDefinition("CMAKE_CXX_COMPILER");
940 if (compiler.empty()) //Hmm, what to do now ?
942 compiler = "gcc";
946 // the following right now hardcodes gcc behaviour :-/
947 fout <<
948 "<storageModule moduleId=\"scannerConfiguration\">\n"
949 "<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\""
950 " selectedProfileId="
951 "\"org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile\"/>\n"
953 cmExtraEclipseCDT4Generator::AppendScannerProfile(fout,
954 "org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile",
955 true, "", true, "specsFile",
956 "-E -P -v -dD ${plugin_state_location}/${specs_file}",
957 compiler, true, true);
958 cmExtraEclipseCDT4Generator::AppendScannerProfile(fout,
959 "org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile",
960 true, "", true, "makefileGenerator",
961 "-f ${project_name}_scd.mk",
962 make, true, true);
964 fout << "</storageModule>\n";
967 // The prefix is prepended before the actual name of the target. The purpose
968 // of that is to sort the targets in the view of Eclipse, so that at first
969 // the global/utility/all/clean targets appear ": ", then the executable
970 // targets "[exe] ", then the libraries "[lib]", then the rules for the
971 // object files "[obj]", then for preprocessing only "[pre] " and
972 // finally the assembly files "[to asm] ". Note the "to" in "to asm",
973 // without it, "asm" would be the first targets in the list, with the "to"
974 // they are the last targets, which makes more sense.
975 void cmExtraEclipseCDT4Generator::AppendTarget(cmGeneratedFileStream& fout,
976 const std::string& target,
977 const std::string& make,
978 const std::string& path,
979 const char* prefix)
981 fout <<
982 "<target name=\"" << prefix << target << "\""
983 " path=\"" << path.c_str() << "\""
984 " targetID=\"org.eclipse.cdt.make.MakeTargetBuilder\">\n"
985 "<buildCommand>"
986 << cmExtraEclipseCDT4Generator::GetEclipsePath(make)
987 << "</buildCommand>\n"
988 "<buildArguments/>\n"
989 "<buildTarget>" << target << "</buildTarget>\n"
990 "<stopOnError>true</stopOnError>\n"
991 "<useDefaultCommand>false</useDefaultCommand>\n"
992 "</target>\n"
996 void cmExtraEclipseCDT4Generator
997 ::AppendScannerProfile(cmGeneratedFileStream& fout,
998 const std::string& profileID,
999 bool openActionEnabled,
1000 const std::string& openActionFilePath,
1001 bool pParserEnabled,
1002 const std::string& scannerInfoProviderID,
1003 const std::string& runActionArguments,
1004 const std::string& runActionCommand,
1005 bool runActionUseDefault,
1006 bool sipParserEnabled)
1008 fout <<
1009 "<profile id=\"" << profileID << "\">\n"
1010 "<buildOutputProvider>\n"
1011 "<openAction enabled=\"" << (openActionEnabled ? "true" : "false")
1012 << "\" filePath=\"" << openActionFilePath << "\"/>\n"
1013 "<parser enabled=\"" << (pParserEnabled ? "true" : "false") << "\"/>\n"
1014 "</buildOutputProvider>\n"
1015 "<scannerInfoProvider id=\"" << scannerInfoProviderID << "\">\n"
1016 "<runAction arguments=\"" << runActionArguments << "\""
1017 " command=\"" << runActionCommand
1018 << "\" useDefault=\"" << (runActionUseDefault ? "true":"false") << "\"/>\n"
1019 "<parser enabled=\"" << (sipParserEnabled ? "true" : "false") << "\"/>\n"
1020 "</scannerInfoProvider>\n"
1021 "</profile>\n"
1025 void cmExtraEclipseCDT4Generator
1026 ::AppendLinkedResource (cmGeneratedFileStream& fout,
1027 const std::string& name,
1028 const std::string& path)
1030 fout <<
1031 "\t\t<link>\n"
1032 "\t\t\t<name>" << name << "</name>\n"
1033 "\t\t\t<type>2</type>\n"
1034 "\t\t\t<location>"
1035 << path
1036 << "</location>\n"
1037 "\t\t</link>\n"
1041 bool cmExtraEclipseCDT4Generator
1042 ::AppendOutLinkedResource(cmGeneratedFileStream& fout,
1043 const std::string& defname,
1044 const std::string& altdefname)
1046 if (defname.empty() && altdefname.empty())
1048 return false;
1051 std::string outputPath = (defname.empty() ? altdefname : defname);
1053 if (!cmSystemTools::FileIsFullPath(outputPath.c_str()))
1055 outputPath = this->HomeOutputDirectory + "/" + outputPath;
1057 if (cmSystemTools::IsSubDirectory(outputPath.c_str(),
1058 this->HomeOutputDirectory.c_str()))
1060 return false;
1063 std::string name = this->GetPathBasename(outputPath);
1065 // make sure linked resource name is unique
1066 while (this->GlobalGenerator->GetProjectMap().find(name)
1067 != this->GlobalGenerator->GetProjectMap().end())
1069 name += "_";
1072 if (std::find(this->OutLinkedResources.begin(),
1073 this->OutLinkedResources.end(),
1074 name)
1075 != this->OutLinkedResources.end())
1077 return false;
1079 else
1081 this->AppendLinkedResource(fout, name,
1082 this->GetEclipsePath(outputPath));
1083 this->OutLinkedResources.push_back(name);
1084 return true;