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