in Source/cmExtraEclipseCDT4Generator.cxx [606:1044]
void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
{
std::set<std::string> emitted;
auto const& lg = this->GlobalGenerator->GetLocalGenerators()[0];
cmMakefile const* mf = lg->GetMakefile();
std::string const filename = this->HomeOutputDirectory + "/.cproject";
cmGeneratedFileStream fout(filename);
if (!fout) {
return;
}
cmXMLWriter xml(fout);
// add header
xml.StartDocument("UTF-8");
xml.ProcessingInstruction("fileVersion", "4.0.0");
xml.StartElement("cproject");
xml.StartElement("storageModule");
xml.Attribute("moduleId", "org.eclipse.cdt.core.settings");
xml.StartElement("cconfiguration"); // noqa: spellcheck disable-line
xml.Attribute("id", "org.eclipse.cdt.core.default.config.1");
// Configuration settings...
xml.StartElement("storageModule");
xml.Attribute("buildSystemId",
"org.eclipse.cdt.core.defaultConfigDataProvider");
xml.Attribute("id", "org.eclipse.cdt.core.default.config.1");
xml.Attribute("moduleId", "org.eclipse.cdt.core.settings");
xml.Attribute("name", "Configuration");
xml.Element("externalSettings");
xml.StartElement("extensions");
// TODO: refactor this out...
std::string executableFormat =
mf->GetSafeDefinition("CMAKE_EXECUTABLE_FORMAT");
if (executableFormat == "ELF") {
xml.StartElement("extension");
xml.Attribute("id", "org.eclipse.cdt.core.ELF");
xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
xml.EndElement(); // extension
xml.StartElement("extension");
xml.Attribute("id", "org.eclipse.cdt.core.GNU_ELF");
xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
AppendAttribute(xml, "addr2line");
AppendAttribute(xml, "c++filt");
xml.EndElement(); // extension
} else {
std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
if (systemName == "CYGWIN" || systemName == "MSYS") {
xml.StartElement("extension");
xml.Attribute("id", "org.eclipse.cdt.core.Cygwin_PE");
xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
AppendAttribute(xml, "addr2line");
AppendAttribute(xml, "c++filt");
AppendAttribute(xml, "cygpath");
AppendAttribute(xml, "nm");
xml.EndElement(); // extension
} else if (systemName == "Windows") {
xml.StartElement("extension");
xml.Attribute("id", "org.eclipse.cdt.core.PE");
xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
xml.EndElement(); // extension
} else if (systemName == "Darwin") {
xml.StartElement("extension");
xml.Attribute("id",
this->SupportsMachO64Parser
? "org.eclipse.cdt.core.MachO64"
: "org.eclipse.cdt.core.MachO");
xml.Attribute("point", "org.eclipse.cdt.core.BinaryParser");
AppendAttribute(xml, "c++filt");
xml.EndElement(); // extension
} else {
// *** Should never get here ***
xml.Element("error_toolchain_type");
}
}
xml.EndElement(); // extensions
xml.EndElement(); // storageModule
// ???
xml.StartElement("storageModule");
xml.Attribute("moduleId", "org.eclipse.cdt.core.language.mapping");
xml.Element("project-mappings");
xml.EndElement(); // storageModule
// ???
xml.StartElement("storageModule");
xml.Attribute("moduleId", "org.eclipse.cdt.core.externalSettings");
xml.EndElement(); // storageModule
// set the path entries (includes, libs, source dirs, etc.)
xml.StartElement("storageModule");
xml.Attribute("moduleId", "org.eclipse.cdt.core.pathentry");
// for each sub project with a linked resource to the source dir:
// - make it type 'src'
// - and exclude it from type 'out'
std::string excludeFromOut;
/* I don't know what the pathentry kind="src" are good for, e.g.
* autocompletion
* works also without them. Done wrong, the indexer complains, see #12417
* and #12213.
* According to #13596, this entry at least limits the directories the
* indexer is searching for files. So now the "src" entry contains only
* the linked resource to CMAKE_SOURCE_DIR.
* The CDT documentation is very terse on that:
* "CDT_SOURCE: Entry kind constant describing a path entry identifying a
* folder containing source code to be compiled."
* Also on the cdt-dev list didn't bring any information:
* http://web.archiveorange.com/archive/v/B4NlJDNIpYoOS1SbxFNy
* Alex */
// include subprojects directory to the src pathentry
// eclipse cdt indexer uses this entries as reference to index source files
if (this->GenerateLinkedResources) {
xml.StartElement("pathentry");
xml.Attribute("kind", "src");
xml.Attribute("path", "[Subprojects]");
xml.EndElement();
}
for (std::string const& p : this->SrcLinkedResources) {
xml.StartElement("pathentry");
xml.Attribute("kind", "src");
xml.Attribute("path", p);
xml.EndElement();
// exclude source directory from output search path
// - only if not named the same as an output directory
if (!cmSystemTools::FileIsDirectory(
cmStrCat(this->HomeOutputDirectory, '/', p))) {
excludeFromOut += p + "/|";
}
}
excludeFromOut += "**/CMakeFiles/";
xml.StartElement("pathentry");
xml.Attribute("excluding", excludeFromOut);
xml.Attribute("kind", "out");
xml.Attribute("path", "");
xml.EndElement();
// add pre-processor definitions to allow eclipse to gray out sections
emitted.clear();
for (auto const& lgen : this->GlobalGenerator->GetLocalGenerators()) {
if (cmValue cdefs =
lgen->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) {
// Expand the list.
std::vector<std::string> defs;
cmGeneratorExpression::Split(*cdefs, defs);
for (std::string const& d : defs) {
if (cmGeneratorExpression::Find(d) != std::string::npos) {
continue;
}
std::string::size_type equals = d.find('=', 0);
std::string::size_type enddef = d.length();
std::string def;
std::string val;
if (equals != std::string::npos && equals < enddef) {
// we have -DFOO=BAR
def = d.substr(0, equals);
val = d.substr(equals + 1, enddef - equals + 1);
} else {
// we have -DFOO
def = d;
}
// insert the definition if not already added.
if (emitted.find(def) == emitted.end()) {
emitted.insert(def);
xml.StartElement("pathentry");
xml.Attribute("kind", "mac");
xml.Attribute("name", def);
xml.Attribute("path", "");
xml.Attribute("value", val);
xml.EndElement();
}
}
}
}
// add system defined c macros
cmValue cDefs =
mf->GetDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS");
if (this->CEnabled && cDefs) {
// Expand the list.
cmList defs{ *cDefs, cmList::EmptyElements::Yes };
// the list must contain only definition-value pairs:
if ((defs.size() % 2) == 0) {
auto di = defs.begin();
while (di != defs.end()) {
std::string def = *di;
++di;
std::string val;
if (di != defs.end()) {
val = *di;
++di;
}
// insert the definition if not already added.
if (emitted.find(def) == emitted.end()) {
emitted.insert(def);
xml.StartElement("pathentry");
xml.Attribute("kind", "mac");
xml.Attribute("name", def);
xml.Attribute("path", "");
xml.Attribute("value", val);
xml.EndElement();
}
}
}
}
// add system defined c++ macros
cmValue cxxDefs =
mf->GetDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS");
if (this->CXXEnabled && cxxDefs) {
// Expand the list.
cmList defs{ *cxxDefs, cmList::EmptyElements::Yes };
// the list must contain only definition-value pairs:
if ((defs.size() % 2) == 0) {
auto di = defs.begin();
while (di != defs.end()) {
std::string def = *di;
++di;
std::string val;
if (di != defs.end()) {
val = *di;
++di;
}
// insert the definition if not already added.
if (emitted.find(def) == emitted.end()) {
emitted.insert(def);
xml.StartElement("pathentry");
xml.Attribute("kind", "mac");
xml.Attribute("name", def);
xml.Attribute("path", "");
xml.Attribute("value", val);
xml.EndElement();
}
}
}
}
// include dirs
emitted.clear();
for (auto const& lgen : this->GlobalGenerator->GetLocalGenerators()) {
auto const& targets = lgen->GetGeneratorTargets();
for (auto const& target : targets) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
std::vector<std::string> includeDirs;
std::string config = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
lgen->GetIncludeDirectories(includeDirs, target.get(), "C", config);
this->AppendIncludeDirectories(xml, includeDirs, emitted);
}
}
// now also the system include directories, in case we found them in
// CMakeSystemSpecificInformation.cmake. This makes Eclipse find the
// standard headers.
std::string compiler = mf->GetSafeDefinition("CMAKE_C_COMPILER");
if (this->CEnabled && !compiler.empty()) {
std::string systemIncludeDirs =
mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
cmList dirs{ systemIncludeDirs };
this->AppendIncludeDirectories(xml, dirs, emitted);
}
compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
if (this->CXXEnabled && !compiler.empty()) {
std::string systemIncludeDirs =
mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
cmList dirs{ systemIncludeDirs };
this->AppendIncludeDirectories(xml, dirs, emitted);
}
xml.EndElement(); // storageModule
// add build targets
xml.StartElement("storageModule");
xml.Attribute("moduleId", "org.eclipse.cdt.make.core.buildtargets");
xml.StartElement("buildTargets");
emitted.clear();
std::string const& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string const& makeArgs =
mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS");
cmGlobalGenerator* generator =
const_cast<cmGlobalGenerator*>(this->GlobalGenerator);
std::string allTarget;
std::string cleanTarget;
if (generator->GetAllTargetName()) {
allTarget = generator->GetAllTargetName();
}
if (generator->GetCleanTargetName()) {
cleanTarget = generator->GetCleanTargetName();
}
// add all executable and library targets and some of the GLOBAL
// and UTILITY targets
for (auto const& lgen : this->GlobalGenerator->GetLocalGenerators()) {
auto const& targets = lgen->GetGeneratorTargets();
std::string subdir =
lgen->MaybeRelativeToTopBinDir(lgen->GetCurrentBinaryDirectory());
if (subdir == ".") {
subdir.clear();
}
for (auto const& target : targets) {
std::string targetName = target->GetName();
switch (target->GetType()) {
case cmStateEnums::GLOBAL_TARGET: {
// Only add the global targets from CMAKE_BINARY_DIR,
// not from the subdirs
if (subdir.empty()) {
cmExtraEclipseCDT4Generator::AppendTarget(xml, targetName, make,
makeArgs, subdir, ": ");
}
} break;
case cmStateEnums::UTILITY:
// Add all utility targets, except the Nightly/Continuous/
// Experimental-"sub"targets as e.g. NightlyStart
if ((cmHasLiteralPrefix(targetName, "Nightly") &&
(targetName != "Nightly")) ||
(cmHasLiteralPrefix(targetName, "Continuous") &&
(targetName != "Continuous")) ||
(cmHasLiteralPrefix(targetName, "Experimental") &&
(targetName != "Experimental"))) {
break;
}
cmExtraEclipseCDT4Generator::AppendTarget(xml, targetName, make,
makeArgs, subdir, ": ");
break;
case cmStateEnums::EXECUTABLE:
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY: {
char const* prefix =
(target->GetType() == cmStateEnums::EXECUTABLE ? "[exe] "
: "[lib] ");
cmExtraEclipseCDT4Generator::AppendTarget(xml, targetName, make,
makeArgs, subdir, prefix);
std::string fastTarget = cmStrCat(targetName, "/fast");
cmExtraEclipseCDT4Generator::AppendTarget(xml, fastTarget, make,
makeArgs, subdir, prefix);
// Add Build and Clean targets in the virtual folder of targets:
if (this->SupportsVirtualFolders) {
std::string virtDir = cmStrCat("[Targets]/", prefix, targetName);
std::string buildArgs =
cmStrCat("-C \"", lgen->GetBinaryDirectory(), "\" ", makeArgs);
cmExtraEclipseCDT4Generator::AppendTarget(
xml, "Build", make, buildArgs, virtDir, "", targetName.c_str());
std::string cleanArgs =
cmStrCat("-E chdir \"", lgen->GetCurrentBinaryDirectory(),
"\" \"", cmSystemTools::GetCMakeCommand(), "\" -P \"");
cleanArgs += lgen->GetTargetDirectory(target.get());
cleanArgs += "/cmake_clean.cmake\"";
cmExtraEclipseCDT4Generator::AppendTarget(
xml, "Clean", cmSystemTools::GetCMakeCommand(), cleanArgs,
virtDir, "", "");
}
} break;
case cmStateEnums::INTERFACE_LIBRARY:
default:
break;
}
}
// insert the all and clean targets in every subdir
if (!allTarget.empty()) {
cmExtraEclipseCDT4Generator::AppendTarget(xml, allTarget, make, makeArgs,
subdir, ": ");
}
if (!cleanTarget.empty()) {
cmExtraEclipseCDT4Generator::AppendTarget(xml, cleanTarget, make,
makeArgs, subdir, ": ");
}
// insert rules for compiling, preprocessing and assembling individual
// files
std::vector<std::string> objectFileTargets;
lg->GetIndividualFileTargets(objectFileTargets);
for (std::string const& f : objectFileTargets) {
char const* prefix = "[obj] ";
if (f.back() == 's') {
prefix = "[to asm] ";
} else if (f.back() == 'i') {
prefix = "[pre] ";
}
cmExtraEclipseCDT4Generator::AppendTarget(xml, f, make, makeArgs, subdir,
prefix);
}
}
xml.EndElement(); // buildTargets
xml.EndElement(); // storageModule
cmExtraEclipseCDT4Generator::AppendStorageScanners(xml, *mf);
// noqa: spellcheck off
xml.EndElement(); // cconfiguration
// noqa: spellcheck on
xml.EndElement(); // storageModule
xml.StartElement("storageModule");
xml.Attribute("moduleId", "cdtBuildSystem");
xml.Attribute("version", "4.0.0");
xml.StartElement("project");
xml.Attribute("id", std::string(lg->GetProjectName()) + ".null.1");
xml.Attribute("name", lg->GetProjectName());
xml.EndElement(); // project
xml.EndElement(); // storageModule
// Append additional cproject contents without applying any XML formatting
if (cmValue extraCProjectContents =
mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_CPROJECT_CONTENTS")) {
fout << *extraCProjectContents;
}
xml.EndElement(); // cproject
}