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