[CMake] Project Grouping in a solution

Richard Moreland rmoreland at acusoft.com
Thu Sep 27 10:01:54 EDT 2007


Attached is an updated patch that works with 2.4.7.

-Richard

Sylvain Benner wrote:
>>
>> Is there a way to group projects in a solution? Something like this 
>> would be handy
>>  
>> CMakeProject
>>      --> ALL_BUILD
>>      --> ZERO_CHECK
>>      etc
>> lib
>>     --> lib1
>>     --> lib2
>>  
>> Possibly something that follows the file system setup.  
>> -Neal
> This topic has been addressed few days ago, a quick search in the 
> mailing list archive would do the trick ( 
> http://www.cmake.org/pipermail/cmake/ )
> And here is the topic: 
> http://www.cmake.org/pipermail/cmake/2007-September/016504.html
>
> --Sylvain
-------------- next part --------------
--- cmGlobalVisualStudio71Generator.cxx	Mon Jul 16 17:16:42 2007
+++ cmGlobalVisualStudio71Generator.cxx	Thu Aug 16 09:15:04 2007
@@ -228,6 +228,9 @@
         }
       }
     }
+
+  WriteAdditionalProjectSections(fout, root, generators);
+
   fout << "Global\n";
   this->WriteSolutionConfigurations(fout);
   fout << "\tGlobalSection(" << this->ProjectConfigurationSectionName
@@ -271,6 +274,8 @@
     }
   fout << "\tEndGlobalSection\n";
 
+  WriteAdditionalGlobalSections(fout, root, generators);
+ 
   // Write the footer for the SLN file
   this->WriteSLNFooter(fout);
 }
--- cmGlobalVisualStudio71Generator.h	Mon Jul 16 17:16:42 2007
+++ cmGlobalVisualStudio71Generator.h	Thu Aug 16 09:15:13 2007
@@ -62,6 +62,12 @@
   virtual void WriteSLNFooter(std::ostream& fout);
   virtual void WriteSLNHeader(std::ostream& fout);
 
+  virtual void WriteAdditionalGlobalSections(std::ostream& fout, cmLocalGenerator* root,
+      std::vector<cmLocalGenerator*>& generators) {}
+
+  virtual void WriteAdditionalProjectSections(std::ostream& fout, cmLocalGenerator* root,
+      std::vector<cmLocalGenerator*>& generators) {}
+
   std::string ProjectConfigurationSectionName;
 };
 #endif
--- cmGlobalVisualStudio8Generator.cxx	Mon Jul 16 17:16:42 2007
+++ cmGlobalVisualStudio8Generator.cxx	Thu Aug 16 10:25:07 2007
@@ -170,10 +170,269 @@
 }
 
 //----------------------------------------------------------------------------
+std::vector<std::string> buildPathAndSubPathVector(const std::string& path)
+{
+  std::vector<std::string> ret;
+  ret.push_back(path);
+
+  int slashPos;
+  std::string workingPath = path;
+  while ((slashPos = workingPath.find_last_of("/")) != std::string::npos)
+    {
+    workingPath = workingPath.substr(0, slashPos);
+    ret.push_back(workingPath);
+    }
+
+  return ret;
+}
+
+//----------------------------------------------------------------------------
+std::string lastPathComponent(const std::string& path)
+{
+  int slashPos = path.find_last_of("/");
+  if (slashPos != std::string::npos)
+    {
+    return path.substr(slashPos+1, path.length() - slashPos);
+    }
+  return path;
+}
+
+//----------------------------------------------------------------------------
+std::string allButLastPathComponent(const std::string& path)
+{
+  int slashPos = path.find_last_of("/");
+  if (slashPos != std::string::npos)
+    {
+    return path.substr(0, slashPos);
+    }
+  return path;
+}
+
+//----------------------------------------------------------------------------
+std::string foobarPath(const std::string& path)
+{
+  return std::string("SOLUTION FOLDER: ") + path;
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalVisualStudio8Generator::WriteAdditionalProjectSections(
+    std::ostream& fout, cmLocalGenerator* root,
+    std::vector<cmLocalGenerator*>& generators)
+{
+  std::map<std::string, std::string> dspPathMap;
+  bool nestSolutionFolders = 
+      cmSystemTools::IsOn(root->GetMakefile()->GetDefinition("NEST_SOLUTION_FOLDERS"));
+  nestSolutionFolders = true;
+
+  // Get the start directory with the trailing slash
+  std::string rootdir = root->GetMakefile()->GetStartOutputDirectory();
+  rootdir += "/";
+  
+  // For each cmMakefile, create a VCProj for it, and
+  // add it to this SLN file
+  unsigned int i;
+  for(i = 0; i < generators.size(); ++i)
+    {
+    if(this->IsExcluded(root, generators[i]))
+      {
+      continue;
+      }
+    cmMakefile* mf = generators[i]->GetMakefile();
+
+    // Get the source directory from the makefile
+    std::string dir = mf->GetStartOutputDirectory();
+    // remove the home directory and / from the source directory
+    // this gives a relative path 
+    cmSystemTools::ReplaceString(dir, rootdir.c_str(), "");
+
+    // Get the list of create dsp files names from the cmVCProjWriter, more
+    // than one dsp could have been created per input CMakeLists.txt file
+    // for each target
+    std::vector<std::string> dspnames = 
+      static_cast<cmLocalVisualStudio7Generator *>(generators[i])
+      ->GetCreatedProjectNames();
+    cmTargets &tgts = generators[i]->GetMakefile()->GetTargets();
+    cmTargets::iterator l = tgts.begin();
+    for(std::vector<std::string>::iterator si = dspnames.begin(); 
+        l != tgts.end() && si != dspnames.end(); ++l)
+      {
+      // special handling for the current makefile
+      if(mf == generators[0]->GetMakefile())
+        {
+        dir = "."; // no subdirectory for project generated
+        }
+      // Write the project into the SLN file
+      if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0)
+        {
+        }
+      else if ((l->second.GetType() != cmTarget::INSTALL_FILES)
+               && (l->second.GetType() != cmTarget::INSTALL_PROGRAMS))
+        {
+        if (si->c_str() != "")
+          {
+          if (l->first != "ALL_BUILD" && l->first != "INSTALL" && l->first != "RUN_TESTS" &&
+              l->first != "EDIT_CACHE" && l->first != "REBUILD_CACHE" && l->first != "PACKAGE" &&
+              l->first != "ZERO_CHECK" && l->first != "Continuous" && l->first != "Experimental" &&
+              l->first != "Nightly" && l->first != "NightlyMemoryCheck")
+            {
+            std::string path = generators[0]->Convert(mf->GetStartDirectory(), cmLocalGenerator::START);
+            dspPathMap.insert(std::make_pair(si->c_str(), path));
+            }
+          }
+        ++si;
+        }
+      }
+    }
+
+  // Construct the unique list of projects and guids to be written
+  std::map<std::string, std::string> pathGuidMap;
+  //std::vector<std::pair<std::string, std::string> > nestedProjects;
+
+  if (nestSolutionFolders)
+    {
+    std::map<std::string, std::string>::iterator dspPathIter, pathGuidIter;
+    for (dspPathIter = dspPathMap.begin(); dspPathIter != dspPathMap.end(); ++dspPathIter)
+      {
+      // Construct a vector of the path and all subpaths
+      std::vector<std::string> pathAndSubPaths = buildPathAndSubPathVector(dspPathIter->second);
+          //SystemTools::SplitString(dspPathIter->second, '/', true); 
+
+      // For each path, create a guid and insert it into pathGuidMap if it is unique
+      std::vector<std::string>::iterator pathIt;
+      for (pathIt = pathAndSubPaths.begin(); pathIt != pathAndSubPaths.end(); ++pathIt)
+        {
+        pathGuidIter = pathGuidMap.find(*pathIt);
+        if (pathGuidIter == pathGuidMap.end())
+          {
+          // Insert it
+          CreateGUID(foobarPath(*pathIt).c_str());
+          std::string guid = GetGUID(foobarPath(*pathIt).c_str());
+          pathGuidMap.insert(std::make_pair(*pathIt, guid));
+          }
+        else
+          {
+          // Already created
+          }
+        }
+      }
+
+    // Write out all of the new projects, one per unique path component
+    for (pathGuidIter = pathGuidMap.begin(); pathGuidIter != pathGuidMap.end(); ++pathGuidIter)
+      {
+      std::string path = pathGuidIter->first;
+      std::string guid = pathGuidIter->second;
+      std::string lastPartOfPath = lastPathComponent(path);
+      if (lastPartOfPath == ".")
+        {
+        lastPartOfPath = "Root";
+        }
+      fout << "Project(\"" << "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" << "\") = \"" 
+           << lastPartOfPath << "\", \"" << lastPartOfPath << "\", \"{" << guid << "}\"\n";
+      fout << "EndProject\n";
+
+      std::string parentPath = allButLastPathComponent(path);
+      if (parentPath != path)
+        {
+        std::string parentGuid = GetGUID(foobarPath(parentPath).c_str());
+        nestedProjects.push_back(std::make_pair(guid, parentGuid));
+        }
+      }
+
+  if (nestSolutionFolders)
+    {
+    std::vector<cmLocalGenerator*>& children = root->GetChildren();
+    std::vector<cmLocalGenerator*>::iterator it;
+    for (it = children.begin(); it != children.end(); ++it)
+      {
+      cmLocalGenerator* lg = *it;
+      std::string rl = lg->Convert("", cmLocalGenerator::START, cmLocalGenerator::SHELL, true);
+      }
+      
+    for(i = 0; i < generators.size(); ++i)
+      {
+      cmMakefile* mf = generators[i]->GetMakefile();
+      cmLocalVisualStudio7Generator* pg =  
+          static_cast<cmLocalVisualStudio7Generator*>(generators[i]);
+      // Get the list of create dsp files names from the cmVCProjWriter, more
+      // than one dsp could have been created per input CMakeLists.txt file
+      // for each target
+      std::vector<std::string> dspnames = 
+        static_cast<cmLocalVisualStudio7Generator *>(generators[i])
+        ->GetCreatedProjectNames();
+      cmTargets &tgts = pg->GetMakefile()->GetTargets();
+      cmTargets::iterator l = tgts.begin();
+      std::string dir = mf->GetStartDirectory();
+      for(std::vector<std::string>::iterator si = dspnames.begin(); 
+          l != tgts.end() && si != dspnames.end(); ++l)
+        {
+          if (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0)
+          {
+          // TODO
+          // Does this matter for the organization?  Perhaps we could group them
+          // under an External Projects folder
+          }
+        else if ((l->second.GetType() != cmTarget::INSTALL_FILES)
+                 && (l->second.GetType() != cmTarget::INSTALL_PROGRAMS))
+          {
+          if (si->c_str() != "")
+            {
+            std::map<std::string, std::string>::iterator pathGuidIter;
+            std::string path = generators[0]->Convert(dir.c_str(), cmLocalGenerator::START);
+            pathGuidIter = pathGuidMap.find(path);
+            if (pathGuidIter != pathGuidMap.end())
+              {
+              // This find is to make sure we don't add things like RUN_TESTS
+              std::map<std::string, std::string>::iterator dspIter;
+              dspIter = dspPathMap.find(si->c_str());
+              if (dspIter != dspPathMap.end())
+                {
+                std::string projGuid = GetGUID(si->c_str());
+                std::string pathGuid = pathGuidIter->second;
+                nestedProjects.push_back(std::make_pair(projGuid, pathGuid));
+                }
+              else
+                {
+                // Perhaps add it to some Default folder.. ?
+                }
+              }
+            }
+          }
+          ++si;
+        }
+      }
+    }
+  }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalVisualStudio8Generator::WriteAdditionalGlobalSections(
+    std::ostream& fout, cmLocalGenerator* root,
+    std::vector<cmLocalGenerator*>& generators)
+{
+  bool nestSolutionFolders = 
+      cmSystemTools::IsOn(root->GetMakefile()->GetDefinition("NEST_SOLUTION_FOLDERS"));
+  nestSolutionFolders = true;
+
+  if (nestSolutionFolders)
+    {
+    fout << "\tGlobalSection(NestedProjects) = preSolution\n";
+    std::vector<std::pair<std::string, std::string> >::iterator npIter;
+    for (npIter = nestedProjects.begin(); npIter != nestedProjects.end(); ++npIter)
+      {
+      fout << "\t\t{" << npIter->first << "} = {" << npIter->second << "}\n";
+      }
+    fout << "\tEndGlobalSection\n";
+    }
+}
+
+//----------------------------------------------------------------------------
 void cmGlobalVisualStudio8Generator::WriteSLNFile(
   std::ostream& fout, cmLocalGenerator* root,
   std::vector<cmLocalGenerator*>& generators)
 {
+  // Reset nestedProjects
+  nestedProjects.clear();
+
   // Make all targets depend on their respective project's build
   // system check target.
   unsigned int i;
--- cmGlobalVisualStudio8Generator.h	Mon Jul 16 17:16:42 2007
+++ cmGlobalVisualStudio8Generator.h	Thu Aug 16 09:16:08 2007
@@ -59,6 +59,15 @@
   virtual void WriteProjectConfigurations(std::ostream& fout,
                                           const char* name,
                                           bool partOfDefaultBuild);
+
+  virtual void WriteAdditionalGlobalSections(std::ostream& fout, cmLocalGenerator* root,
+    std::vector<cmLocalGenerator*>& generators);
+
+  virtual void WriteAdditionalProjectSections(std::ostream& fout, cmLocalGenerator* root,
+      std::vector<cmLocalGenerator*>& generators);
+
+  std::vector<std::pair<std::string, std::string> > nestedProjects;
+
   std::string PlatformName; // Win32 or x64 
 };
 #endif


More information about the CMake mailing list