[CMake] Project Grouping in a solution

Neal Meyer nmeyer at dottedzebra.com
Thu Sep 27 15:08:41 EDT 2007


Richard,

This project organization is much better, Kudos.  However, most of our
directories include only a single project file so there seems to be a lot of
redundant folders in this type of layout, so maybe a little additional
feature that if there is only a single project in the directory don't add
it's directory to the list as well (the project name is usually pretty close
to the directory names).  Also I'd like to see the CMake generated projects
in their own folder to seperate them from the rest of the projects.

A nice addition to this type of functionality might be to add functionality
similar to SOURCE_GROUP() (i.e. PROJECT_GROUP), so that I can design the
whacky project groupings that make sense for my project.

-Neal


On 9/27/07, Richard Moreland <rmoreland at acusoft.com> wrote:
>
> 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
>
> --- 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.txtfile
> +      // 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
>
> _______________________________________________
> CMake mailing list
> CMake at cmake.org
> http://www.cmake.org/mailman/listinfo/cmake
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://public.kitware.com/pipermail/cmake/attachments/20070927/081374a8/attachment-0001.html


More information about the CMake mailing list