Merge topic 'codelite-organize-by-target'

cbe48879 CodeLite: Optionally use targets to create (sub)project files
This commit is contained in:
Brad King 2016-09-27 08:22:53 -04:00 committed by CMake Topic Stage
commit ded15f26b8
6 changed files with 284 additions and 99 deletions

View File

@ -5,7 +5,11 @@ Generates CodeLite project files.
Project files for CodeLite will be created in the top directory and
in every subdirectory which features a CMakeLists.txt file containing
a PROJECT() call. The appropriate make program can build the
a :command:`project` call.
The :variable:`CMAKE_CODELITE_USE_TARGETS` variable may be set to ``ON``
to change the default behaviour from projects to targets as the basis
for project files.
The appropriate make program can build the
project through the default make target. A "make install" target is
also provided.

View File

@ -112,6 +112,7 @@ Variables that Change Behavior
/variable/CMAKE_AUTOMOC_RELAXED_MODE
/variable/CMAKE_BACKWARDS_COMPATIBILITY
/variable/CMAKE_BUILD_TYPE
/variable/CMAKE_CODELITE_USE_TARGETS
/variable/CMAKE_COLOR_MAKEFILE
/variable/CMAKE_CONFIGURATION_TYPES
/variable/CMAKE_DEBUG_TARGET_PROPERTIES

View File

@ -0,0 +1,6 @@
codelite-organize-by-target
---------------------------
* The :generator:`CodeLite` generator gained a new
:variable:`CMAKE_CODELITE_USE_TARGETS` option
to change project creation from projects to targets.

View File

@ -0,0 +1,7 @@
CMAKE_CODELITE_USE_TARGETS
--------------------------
Change the way the CodeLite generator creates projectfiles.
If this variable is set to ``ON`` the generator creates projectfiles
based on targets rather than projects.

View File

@ -70,6 +70,8 @@ void cmExtraCodeLiteGenerator::Generate()
// loop projects and locate the root project.
// and extract the information for creating the worspace
// root makefile
const cmMakefile* rmf = CM_NULLPTR;
for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
it = projectMap.begin();
it != projectMap.end(); ++it) {
@ -84,6 +86,7 @@ void cmExtraCodeLiteGenerator::Generate()
workspaceFileName = workspaceOutputDir + "/";
workspaceFileName += workspaceProjectName + ".workspace";
this->WorkspacePath = it->second[0]->GetCurrentBinaryDirectory();
rmf = it->second[0]->GetMakefile();
;
break;
}
@ -96,13 +99,90 @@ void cmExtraCodeLiteGenerator::Generate()
xml.StartElement("CodeLite_Workspace");
xml.Attribute("Name", workspaceProjectName);
bool const targetsAreProjects =
rmf && rmf->IsOn("CMAKE_CODELITE_USE_TARGETS");
std::vector<std::string> ProjectNames;
if (targetsAreProjects) {
ProjectNames = CreateProjectsByTarget(&xml);
} else {
ProjectNames = CreateProjectsByProjectMaps(&xml);
}
xml.StartElement("BuildMatrix");
xml.StartElement("WorkspaceConfiguration");
xml.Attribute("Name", this->ConfigName);
xml.Attribute("Selected", "yes");
for (std::vector<std::string>::iterator it(ProjectNames.begin());
it != ProjectNames.end(); it++) {
xml.StartElement("Project");
xml.Attribute("Name", *it);
xml.Attribute("ConfigName", this->ConfigName);
xml.EndElement();
}
xml.EndElement(); // WorkspaceConfiguration
xml.EndElement(); // BuildMatrix
xml.EndElement(); // CodeLite_Workspace
}
// Create projects where targets are the projects
std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget(
cmXMLWriter* xml)
{
std::vector<std::string> retval;
// for each target in the workspace create a codelite project
const std::vector<cmLocalGenerator*>& lgs =
this->GlobalGenerator->GetLocalGenerators();
for (std::vector<cmLocalGenerator*>::const_iterator lg(lgs.begin());
lg != lgs.end(); lg++) {
for (std::vector<cmGeneratorTarget*>::const_iterator lt =
(*lg)->GetGeneratorTargets().begin();
lt != (*lg)->GetGeneratorTargets().end(); lt++) {
cmState::TargetType type = (*lt)->GetType();
std::string outputDir = (*lg)->GetCurrentBinaryDirectory();
std::string filename = outputDir + "/" + (*lt)->GetName() + ".project";
retval.push_back((*lt)->GetName());
// Make the project file relative to the workspace
std::string relafilename = cmSystemTools::RelativePath(
this->WorkspacePath.c_str(), filename.c_str());
std::string visualname = (*lt)->GetName();
switch (type) {
case cmState::SHARED_LIBRARY:
case cmState::STATIC_LIBRARY:
case cmState::MODULE_LIBRARY:
visualname = "lib" + visualname;
case cmState::EXECUTABLE:
xml->StartElement("Project");
xml->Attribute("Name", visualname);
xml->Attribute("Path", relafilename);
xml->Attribute("Active", "No");
xml->EndElement();
CreateNewProjectFile(*lt, filename);
break;
default:
break;
}
}
}
return retval;
}
// The "older way of doing it.
std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByProjectMaps(
cmXMLWriter* xml)
{
std::vector<std::string> retval;
// for each sub project in the workspace create a codelite project
for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
it = projectMap.begin();
it != projectMap.end(); ++it) {
// retrive project information
it = this->GlobalGenerator->GetProjectMap().begin();
it != this->GlobalGenerator->GetProjectMap().end(); it++) {
std::string outputDir = it->second[0]->GetCurrentBinaryDirectory();
std::string projectName = it->second[0]->GetProjectName();
retval.push_back(projectName);
std::string filename = outputDir + "/" + projectName + ".project";
// Make the project file relative to the workspace
@ -111,33 +191,13 @@ void cmExtraCodeLiteGenerator::Generate()
// create a project file
this->CreateProjectFile(it->second);
xml.StartElement("Project");
xml.Attribute("Name", projectName);
xml.Attribute("Path", filename);
xml.Attribute("Active", "No");
xml.EndElement();
xml->StartElement("Project");
xml->Attribute("Name", projectName);
xml->Attribute("Path", filename);
xml->Attribute("Active", "No");
xml->EndElement();
}
xml.StartElement("BuildMatrix");
xml.StartElement("WorkspaceConfiguration");
xml.Attribute("Name", this->ConfigName);
xml.Attribute("Selected", "yes");
for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
it = projectMap.begin();
it != projectMap.end(); ++it) {
// retrive project information
std::string projectName = it->second[0]->GetProjectName();
xml.StartElement("Project");
xml.Attribute("Name", projectName);
xml.Attribute("ConfigName", this->ConfigName);
xml.EndElement();
}
xml.EndElement(); // WorkspaceConfiguration
xml.EndElement(); // BuildMatrix
xml.EndElement(); // CodeLite_Workspace
return retval;
}
/* create the project file */
@ -152,6 +212,70 @@ void cmExtraCodeLiteGenerator::CreateProjectFile(
this->CreateNewProjectFile(lgs, filename);
}
std::string cmExtraCodeLiteGenerator::CollectSourceFiles(
const cmMakefile* makefile, const cmGeneratorTarget* gt,
std::map<std::string, cmSourceFile*>& cFiles,
std::set<std::string>& otherFiles)
{
const std::vector<std::string>& srcExts =
this->GlobalGenerator->GetCMakeInstance()->GetSourceExtensions();
std::string projectType;
switch (gt->GetType()) {
case cmState::EXECUTABLE: {
projectType = "Executable";
} break;
case cmState::STATIC_LIBRARY: {
projectType = "Static Library";
} break;
case cmState::SHARED_LIBRARY: {
projectType = "Dynamic Library";
} break;
case cmState::MODULE_LIBRARY: {
projectType = "Dynamic Library";
} break;
default: // intended fallthrough
break;
}
switch (gt->GetType()) {
case cmState::EXECUTABLE:
case cmState::STATIC_LIBRARY:
case cmState::SHARED_LIBRARY:
case cmState::MODULE_LIBRARY: {
std::vector<cmSourceFile*> sources;
gt->GetSourceFiles(sources,
makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); si++) {
// check whether it is a C/C++ implementation file
bool isCFile = false;
std::string lang = (*si)->GetLanguage();
if (lang == "C" || lang == "CXX") {
std::string srcext = (*si)->GetExtension();
for (std::vector<std::string>::const_iterator ext = srcExts.begin();
ext != srcExts.end(); ++ext) {
if (srcext == *ext) {
isCFile = true;
break;
}
}
}
// then put it accordingly into one of the two containers
if (isCFile) {
cFiles[(*si)->GetFullPath()] = *si;
} else {
otherFiles.insert((*si)->GetFullPath());
}
}
}
default: // intended fallthrough
break;
}
return projectType;
}
void cmExtraCodeLiteGenerator::CreateNewProjectFile(
const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
{
@ -168,82 +292,42 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
xml.Attribute("Name", lgs[0]->GetProjectName());
xml.Attribute("InternalType", "");
std::string projectType;
// Collect all used source files in the project
// Sort them into two containers, one for C/C++ implementation files
// which may have an acompanying header, one for all other files
std::string projectType;
std::vector<std::string> srcExts =
this->GlobalGenerator->GetCMakeInstance()->GetSourceExtensions();
std::vector<std::string> headerExts =
this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
std::map<std::string, cmSourceFile*> cFiles;
std::set<std::string> otherFiles;
for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
lg != lgs.end(); lg++) {
cmMakefile* makefile = (*lg)->GetMakefile();
std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
ti != targets.end(); ti++) {
switch ((*ti)->GetType()) {
case cmState::EXECUTABLE: {
projectType = "Executable";
} break;
case cmState::STATIC_LIBRARY: {
projectType = "Static Library";
} break;
case cmState::SHARED_LIBRARY: {
projectType = "Dynamic Library";
} break;
case cmState::MODULE_LIBRARY: {
projectType = "Dynamic Library";
} break;
default: // intended fallthrough
break;
}
switch ((*ti)->GetType()) {
case cmState::EXECUTABLE:
case cmState::STATIC_LIBRARY:
case cmState::SHARED_LIBRARY:
case cmState::MODULE_LIBRARY: {
std::vector<cmSourceFile*> sources;
cmGeneratorTarget* gt = *ti;
gt->GetSourceFiles(sources,
makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); si++) {
// check whether it is a C/C++ implementation file
bool isCFile = false;
std::string lang = (*si)->GetLanguage();
if (lang == "C" || lang == "CXX") {
std::string srcext = (*si)->GetExtension();
for (std::vector<std::string>::const_iterator ext =
srcExts.begin();
ext != srcExts.end(); ++ext) {
if (srcext == *ext) {
isCFile = true;
break;
}
}
}
// then put it accordingly into one of the two containers
if (isCFile) {
cFiles[(*si)->GetFullPath()] = *si;
} else {
otherFiles.insert((*si)->GetFullPath());
}
}
}
default: // intended fallthrough
break;
}
projectType = CollectSourceFiles(makefile, *ti, cFiles, otherFiles);
}
}
// Get the project path ( we need it later to convert files to
// their relative path)
std::string projectPath = cmSystemTools::GetFilenamePath(filename);
CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
projectType);
xml.EndElement(); // CodeLite_Project
}
void cmExtraCodeLiteGenerator::FindMatchingHeaderfiles(
std::map<std::string, cmSourceFile*>& cFiles,
std::set<std::string>& otherFiles)
{
const std::vector<std::string>& headerExts =
this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
// The following loop tries to add header files matching to implementation
// files to the project. It does that by iterating over all source files,
// replacing the file name extension with ".h" and checks whether such a
@ -275,11 +359,17 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
}
}
}
}
// Get the project path ( we need it later to convert files to
// their relative path)
std::string projectPath = cmSystemTools::GetFilenamePath(filename);
void cmExtraCodeLiteGenerator::CreateProjectSourceEntries(
std::map<std::string, cmSourceFile*>& cFiles,
std::set<std::string>& otherFiles, cmXMLWriter* _xml,
const std::string& projectPath, const cmMakefile* mf,
const std::string& projectType)
{
cmXMLWriter& xml(*_xml);
FindMatchingHeaderfiles(cFiles, otherFiles);
// Create 2 virtual folders: src and include
// and place all the implementation files into the src
// folder, the rest goes to the include folder
@ -292,8 +382,10 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
cFiles.begin();
sit != cFiles.end(); ++sit) {
xml.StartElement("File");
xml.Attribute("Name", cmSystemTools::RelativePath(projectPath.c_str(),
sit->first.c_str()));
std::string fpath(sit->first);
std::string frelapath =
cmSystemTools::RelativePath(projectPath.c_str(), sit->first.c_str());
xml.Attribute("Name", frelapath);
xml.EndElement();
}
xml.EndElement(); // VirtualDirectory
@ -350,11 +442,18 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
xml.EndElement(); // ResourceCompiler
xml.StartElement("General");
xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)");
std::string outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
if (!outputPath.empty())
xml.Attribute("OutputFile", outputPath + "/$(ProjectName)");
else
xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)");
xml.Attribute("IntermediateDirectory", "./");
xml.Attribute("Command", "./$(ProjectName)");
xml.Attribute("CommandArguments", "");
xml.Attribute("WorkingDirectory", "$(IntermediateDirectory)");
if (!outputPath.empty())
xml.Attribute("WorkingDirectory", outputPath);
else
xml.Attribute("WorkingDirectory", "$(IntermediateDirectory)");
xml.Attribute("PauseExecWhenProcTerminates", "yes");
xml.EndElement(); // General
@ -408,6 +507,53 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
xml.EndElement(); // GlobalSettings
xml.EndElement(); // Settings
}
void cmExtraCodeLiteGenerator::CreateNewProjectFile(
const cmGeneratorTarget* gt, const std::string& filename)
{
const cmMakefile* mf = gt->Makefile;
cmGeneratedFileStream fout(filename.c_str());
if (!fout) {
return;
}
cmXMLWriter xml(fout);
////////////////////////////////////
xml.StartDocument("utf-8");
xml.StartElement("CodeLite_Project");
std::string visualname = gt->GetName();
switch (gt->GetType()) {
case cmState::STATIC_LIBRARY:
case cmState::SHARED_LIBRARY:
case cmState::MODULE_LIBRARY:
visualname = "lib" + visualname;
default: // intended fallthrough
break;
}
xml.Attribute("Name", visualname);
xml.Attribute("InternalType", "");
// Collect all used source files in the project
// Sort them into two containers, one for C/C++ implementation files
// which may have an acompanying header, one for all other files
std::string projectType;
std::vector<std::string> headerExts =
this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
std::map<std::string, cmSourceFile*> cFiles;
std::set<std::string> otherFiles;
projectType = CollectSourceFiles(mf, gt, cFiles, otherFiles);
// Get the project path ( we need it later to convert files to
// their relative path)
std::string projectPath = cmSystemTools::GetFilenamePath(filename);
CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
projectType);
xml.EndElement(); // CodeLite_Project
}

View File

@ -18,11 +18,16 @@
#include "cmExternalMakefileProjectGenerator.h"
#include <map>
#include <set>
#include <string>
#include <vector>
class cmLocalGenerator;
class cmMakefile;
class cmGeneratorTarget;
class cmXMLWriter;
class cmSourceFile;
class cmExtraCodeLiteGenerator : public cmExternalMakefileProjectGenerator
{
@ -38,6 +43,20 @@ protected:
std::string GetCleanCommand(const cmMakefile* mf) const;
std::string GetRebuildCommand(const cmMakefile* mf) const;
std::string GetSingleFileBuildCommand(const cmMakefile* mf) const;
std::vector<std::string> CreateProjectsByTarget(cmXMLWriter* xml);
std::vector<std::string> CreateProjectsByProjectMaps(cmXMLWriter* xml);
std::string CollectSourceFiles(const cmMakefile* makefile,
const cmGeneratorTarget* gt,
std::map<std::string, cmSourceFile*>& cFiles,
std::set<std::string>& otherFiles);
void FindMatchingHeaderfiles(std::map<std::string, cmSourceFile*>& cFiles,
std::set<std::string>& otherFiles);
void CreateProjectSourceEntries(std::map<std::string, cmSourceFile*>& cFiles,
std::set<std::string>& otherFiles,
cmXMLWriter* xml,
const std::string& projectPath,
const cmMakefile* mf,
const std::string& projectType);
public:
cmExtraCodeLiteGenerator();
@ -49,6 +68,8 @@ public:
void CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
const std::string& filename);
void CreateNewProjectFile(const cmGeneratorTarget* lg,
const std::string& filename);
};
#endif