[CMake] Common Subdirs

Tom Howard tomhoward at users.sf.net
Tue Oct 26 19:50:13 EDT 2004


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I have recently modified CMake to allow common subdirectories (at the
moment CMake will ignore subsequent SUBDIRS statements to the same
directory if the statements are within the same CMakeLists.txt but not
otherwise), such that they will only be configured once (otherwise
Visual Studio will complain about projects with the same name).

For example, I'm working on a project that has 3 libraries and an
executable (ignoring unit test executables).  They are Alpha, Beta,
System (all libs) and Omega (executable).

The CMakeLists.txt file for the System library allows it to be built
individually (i.e the resulting VS solution has 3 projects, System,
ALL_BUILD and INSTALL).

Alpha, Beta use the System library, so their CMakeLists.txt files both
contain (amongst other things) "SUBDIRS(${PATH_TO_SYSTEM})"

Omega also uses the System library as well as the Aplha and Beta
libraries, so it's CMakeLists.txt contains (also amongst other things)
"SUBDIRS{${PATH_TO_SYSTEM} ${PATH_TO_ALPHA} ${PATH_TO_BETA})"

What does this give me?

1) It allows developers working just on the System library to create a
solution (or Makefile) just for it.  They are not burdened with the rest
of the project, except in terms of maintaining the interface.  ALL_BUILD
and INSTALL will only build and install the System components.

2) It allows developers of the Alpha library to work in complete
isolation from the developers of the Beta library and in partial
isolation from the Omega executable (again they need to maintain the
interface).  If changes to System are made by the System developers, The
requisite parts will be build automatically for the Alpha developers the
next time they build Alpha.

3) The Beta developers are in the same situation as the Alpha developers
in terms of System and Omega and they are completely isolated from Alpha.

4) For the developers of Omega, whenever Alpha, Beta or System is
changed by there respective developers, Alpha, Beta and System will be
automatically built as required when the Omega developers build Omega.

I hope you find this new feature as useful as I do.

Normally I would submit a patch for the changes, however I have made
other small changes to CMake that you probably don't want (nothing
major, but enough to screw line numbers in a patch).  Below is a list of
the files that were changed and what changes where made.  Please let me
know if you have and questions or problems.

Cheers,

Tom Howard

====
Source/cmGlobalGenerator.cxx
====

Replace RecursiveConfigure with:

void cmGlobalGenerator::RecursiveConfigure(cmLocalGenerator *lg,
~                                           float startProgress,
~                                           float endProgress)
{
~  // configure the current directory
~  cmLocalGenerator* parent = lg;
~  while( parent->GetParent() )
~  {
~    parent = parent->GetParent();
~  }

~  if( parent->GetIsConfigured( lg->GetMakefile()->GetStartDirectory() ) )
~    return;

~  lg->Configure();
~  parent->SetIsConfigured( lg->GetMakefile()->GetStartDirectory() );

~  // get all the subdirectories
~  std::vector<std::pair<cmStdString, bool> > subdirs =
lg->GetMakefile()->GetSubDirectories();
~  float progressPiece = (endProgress -
startProgress)/(1.0f+subdirs.size());
~  m_CMakeInstance->UpdateProgress("Configuring",
~                                  startProgress + progressPiece);

~  // for each subdir recurse
~  unsigned int i;
~  for (i = 0; i < subdirs.size(); ++i)
~    {
~    cmLocalGenerator *lg2 = this->CreateLocalGenerator();
~    lg2->SetParent(lg);
~    m_LocalGenerators.push_back(lg2);

~    // add the subdir to the start output directory
~    std::string outdir = lg->GetMakefile()->GetHomeOutputDirectory();
~    outdir += "/";
~    outdir += subdirs[i].first;
~    lg2->GetMakefile()->SetStartOutputDirectory(outdir.c_str());
~    lg2->SetExcludeAll(!subdirs[i].second);
~    // add the subdir to the start source directory
~    std::string currentDir = lg->GetMakefile()->GetHomeDirectory();
~    currentDir += "/";
~    currentDir += subdirs[i].first;
~    lg2->GetMakefile()->SetStartDirectory(currentDir.c_str());
~    lg2->GetMakefile()->MakeStartDirectoriesCurrent();

~    this->RecursiveConfigure(lg2,
~                             startProgress + (i+1.0f)*progressPiece,
~                             startProgress + (i+2.0f)*progressPiece);
~    }
}


====
Source/cmLocalGenerator.h
====

Add:

#include <set>

within class cmLocalGenerator add:

public:
~   bool
~   GetIsConfigured( const cmStdString& dir ) const
~   {
~     return m_configured.find( dir ) != m_configured.end();
~   }

~   void
~   SetIsConfigured( const cmStdString& dir )
~   {
~     m_configured.insert( dir );
~   }

protected:
~   std::set< cmStdString > m_configured;



====
Source/cmMakefile.cxx
====

Add:

#include <cmsys/SystemTools.hxx>

Replace AddSubDirectory with:

void cmMakefile::AddSubDirectory(const char* sub, bool topLevel, bool
preorder)
{
~    cmStdString path_new = cmsys::SystemTools::CollapseFullPath( sub,
m_cmCurrentDirectory.c_str() );
~    if( path_new.substr( 0, m_cmHomeDirectory.size() ) ==
m_cmHomeDirectory )
~        path_new = path_new.substr( m_cmHomeDirectory.size()+1 );
~    else
~    {
~        // the subdirectory is on a branch higher in the directory tree
than HomeDir.
~        int len = m_cmHomeDirectory.size() - 1;
~        while( len )
~        {
~            if( path_new.substr( 0, len ) == m_cmHomeDirectory.substr(
0, len ) )
~                break;
~            --len;
~        }
~        if(!len) // there is no relative path to the sub directory.
silently ignore it.  TODO: report error
~            return;
~        path_new = path_new.substr( len );
~        for( size_t i = len-1; i < m_cmHomeDirectory.size(); ++i )
~        {
~            if( m_cmHomeDirectory[ i ] == '/' )
~                path_new = "../" + path_new;
~        }
~    }
~    if(preorder)
~    {
~        m_SubDirectoryOrder[path_new] = preorder;
~    }

~    // make sure it isn't already there
~    for( std::vector<std::pair<cmStdString, bool> >::iterator i =
m_SubDirectories.begin();
~         i != m_SubDirectories.end(); ++i )
~    {
~        if( path_new == i->first )
~            return;
~    }
~    std::pair<cmStdString, bool> p(path_new, topLevel);
~    m_SubDirectories.push_back(p);

}


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFBfuK1w1G4ZUM7KZoRAukeAJ9gW9u00ZSZGFvuCxzBKUWgKGGkNgCeOD44
L93ZgTkc1tql1IwMXBlWCiI=
=4Nvb
-----END PGP SIGNATURE-----



More information about the CMake mailing list