Преглед изворни кода

Merge topic 'codelite-organize-by-target'

cbe48879 CodeLite: Optionally use targets to create (sub)project files
Brad King пре 9 година
родитељ
комит
ded15f26b8

+ 5 - 1
Help/generator/CodeLite.rst

@@ -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.
 

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -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

+ 6 - 0
Help/release/dev/codelite-organize-by-target.rst

@@ -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.

+ 7 - 0
Help/variable/CMAKE_CODELITE_USE_TARGETS.rst

@@ -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.

+ 240 - 94
Source/cmExtraCodeLiteGenerator.cxx

@@ -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,26 +99,14 @@ void cmExtraCodeLiteGenerator::Generate()
   xml.StartElement("CodeLite_Workspace");
   xml.Attribute("Name", workspaceProjectName);
 
-  // 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
-    std::string outputDir = it->second[0]->GetCurrentBinaryDirectory();
-    std::string projectName = it->second[0]->GetProjectName();
-    std::string filename = outputDir + "/" + projectName + ".project";
-
-    // Make the project file relative to the workspace
-    filename = cmSystemTools::RelativePath(this->WorkspacePath.c_str(),
-                                           filename.c_str());
+  bool const targetsAreProjects =
+    rmf && rmf->IsOn("CMAKE_CODELITE_USE_TARGETS");
 
-    // 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();
+  std::vector<std::string> ProjectNames;
+  if (targetsAreProjects) {
+    ProjectNames = CreateProjectsByTarget(&xml);
+  } else {
+    ProjectNames = CreateProjectsByProjectMaps(&xml);
   }
 
   xml.StartElement("BuildMatrix");
@@ -123,14 +114,10 @@ void cmExtraCodeLiteGenerator::Generate()
   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();
-
+  for (std::vector<std::string>::iterator it(ProjectNames.begin());
+       it != ProjectNames.end(); it++) {
     xml.StartElement("Project");
-    xml.Attribute("Name", projectName);
+    xml.Attribute("Name", *it);
     xml.Attribute("ConfigName", this->ConfigName);
     xml.EndElement();
   }
@@ -140,6 +127,79 @@ void cmExtraCodeLiteGenerator::Generate()
   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 = 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
+    filename = cmSystemTools::RelativePath(this->WorkspacePath.c_str(),
+                                           filename.c_str());
+
+    // 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();
+  }
+  return retval;
+}
+
 /* create the project file */
 void cmExtraCodeLiteGenerator::CreateProjectFile(
   const std::vector<cmLocalGenerator*>& lgs)
@@ -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,81 +292,41 @@ 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++) {
+      projectType = CollectSourceFiles(makefile, *ti, cFiles, otherFiles);
+    }
+  }
 
-      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;
-      }
+  // Get the project path ( we need it later to convert files to
+  // their relative path)
+  std::string projectPath = cmSystemTools::GetFilenamePath(filename);
 
-      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;
-                }
-              }
-            }
+  CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
+                             projectType);
 
-            // 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;
-      }
-    }
-  }
+  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,
@@ -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
 }
 

+ 21 - 0
Source/cmExtraCodeLiteGenerator.h

@@ -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