Pārlūkot izejas kodu

ENH: add support for out of source source

Ken Martin 20 gadi atpakaļ
vecāks
revīzija
791aa6052b

+ 11 - 2
Source/CMakeLists.txt

@@ -56,8 +56,6 @@ SET(SRCS
   cmListFileLexer.c
   cmLocalGenerator.cxx
   cmLocalGenerator.h
-  cmLocalUnixMakefileGenerator.cxx
-  cmLocalUnixMakefileGenerator.h
   cmLocalUnixMakefileGenerator2.cxx
   cmLocalXCodeGenerator.cxx
   cmMakeDepend.cxx
@@ -292,6 +290,17 @@ IF(BUILD_TESTING)
     --build-two-config
     --test-command simple)
 
+  ADD_TEST(OutOfSource ${CMAKE_CTEST_COMMAND}
+    --build-and-test 
+    "${CMake_SOURCE_DIR}/Tests/OutOfSource"
+    "${CMake_BINARY_DIR}/Tests/OutOfSource"
+    --build-generator ${CMAKE_GENERATOR}
+    --build-project OutOfSource
+    --build-makeprogram ${MAKEPROGRAM}
+    --build-two-config
+    --test-command 
+    "${CMake_BINARY_DIR}/Tests/OutOfSource/SubDir/OutOfSourceSubdir/simple")
+
   ADD_TEST(PreOrder ${CMAKE_CTEST_COMMAND}
     --build-and-test 
     "${CMake_SOURCE_DIR}/Tests/PreOrder"

+ 7 - 5
Source/cmEnableTestingCommand.cxx

@@ -15,6 +15,7 @@
 
 =========================================================================*/
 #include "cmEnableTestingCommand.h"
+#include "cmSubDirectory.h"
 
 // we do this in the final pass so that we now the subdirs have all 
 // been defined
@@ -64,18 +65,19 @@ void cmEnableTestingCommand::FinalPass()
   if (!m_Makefile->GetSubDirectories().empty())
     {
     fout << "SUBDIRS(";
-    const std::vector<std::pair<cmStdString, bool> >& subdirs = m_Makefile->GetSubDirectories();
-    std::vector<std::pair<cmStdString, bool> >::const_iterator i = subdirs.begin();
-    fout << (*i).first.c_str();
+    const std::vector<cmSubDirectory>& subdirs 
+      = m_Makefile->GetSubDirectories();
+    std::vector<cmSubDirectory>::const_iterator i = subdirs.begin();
+    fout << (*i).SourcePath.c_str();
     ++i;
     for(; i != subdirs.end(); ++i)
       {
-      fout << " " << i->first.c_str();
+      fout << " " << i->SourcePath.c_str();
       }
     fout << ")" << std::endl << std::endl;;
     }
   fout.close();  
-
+  
   return;
 }
 

+ 12 - 13
Source/cmGlobalGenerator.cxx

@@ -18,6 +18,8 @@
 #include "cmLocalGenerator.h"
 #include "cmake.h"
 #include "cmMakefile.h"
+#include "cmSubDirectory.h"
+
 #include <stdlib.h> // required for atof
 
 #if defined(_WIN32) && !defined(__CYGWIN__) 
@@ -580,32 +582,29 @@ void cmGlobalGenerator::RecursiveConfigure(cmLocalGenerator *lg,
   lg->Configure();
                                   
   // get all the subdirectories
-  std::vector<std::pair<cmStdString, bool> > subdirs = lg->GetMakefile()->GetSubDirectories();
+  std::vector<cmSubDirectory> 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)
+  std::vector<cmSubDirectory>::const_iterator sdi = subdirs.begin();
+  int i;
+  for (i = 0; sdi != subdirs.end(); ++sdi, ++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()->GetStartOutputDirectory();
-    outdir += "/";
-    outdir += subdirs[i].first;
-    lg2->GetMakefile()->SetStartOutputDirectory(outdir.c_str());
-    lg2->SetExcludeAll(!subdirs[i].second);
+    lg2->GetMakefile()->SetStartOutputDirectory(sdi->BinaryPath.c_str());
+    lg2->SetExcludeAll(!sdi->IncludeTopLevel);
     // add the subdir to the start source directory
-    std::string currentDir = lg->GetMakefile()->GetStartDirectory();
-    currentDir += "/";
-    currentDir += subdirs[i].first;
-    lg2->GetMakefile()->SetStartDirectory(currentDir.c_str());
+    lg2->GetMakefile()->SetStartDirectory(sdi->SourcePath.c_str());
     lg2->GetMakefile()->MakeStartDirectoriesCurrent();
-  
+    
     this->RecursiveConfigure(lg2, 
                              startProgress + (i+1.0f)*progressPiece,
                              startProgress + (i+2.0f)*progressPiece);

+ 2 - 2
Source/cmGlobalVisualStudio6Generator.cxx

@@ -210,7 +210,7 @@ void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout,
   this->WriteDSWHeader(fout);
   
   // Get the home directory with the trailing slash
-  std::string homedir = root->GetMakefile()->GetCurrentDirectory();
+  std::string homedir = root->GetMakefile()->GetStartOutputDirectory();
   homedir += "/";
     
   unsigned int i;
@@ -227,7 +227,7 @@ void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout,
     cmMakefile* mf = generators[i]->GetMakefile();
     
     // Get the source directory from the makefile
-    std::string dir = mf->GetStartDirectory();
+    std::string dir = mf->GetStartOutputDirectory();
     // remove the home directory and / from the source directory
     // this gives a relative path 
     cmSystemTools::ReplaceString(dir, homedir.c_str(), "");

+ 5 - 5
Source/cmGlobalVisualStudio71Generator.cxx

@@ -48,9 +48,9 @@ void cmGlobalVisualStudio71Generator::WriteSLNFile(std::ostream& fout,
   // Write out the header for a SLN file
   this->WriteSLNHeader(fout);
   
-  // Get the home directory with the trailing slash
-  std::string homedir = root->GetMakefile()->GetCurrentDirectory();
-  homedir += "/";
+  // Get the start directory with the trailing slash
+  std::string rootdir = root->GetMakefile()->GetStartOutputDirectory();
+  rootdir += "/";
   bool doneAllBuild = false;
   bool doneRunTests = false;
   bool doneInstall  = false;
@@ -67,10 +67,10 @@ void cmGlobalVisualStudio71Generator::WriteSLNFile(std::ostream& fout,
     cmMakefile* mf = generators[i]->GetMakefile();
 
     // Get the source directory from the makefile
-    std::string dir = mf->GetStartDirectory();
+    std::string dir = mf->GetStartOutputDirectory();
     // remove the home directory and / from the source directory
     // this gives a relative path 
-    cmSystemTools::ReplaceString(dir, homedir.c_str(), "");
+    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

+ 5 - 5
Source/cmGlobalVisualStudio7Generator.cxx

@@ -327,9 +327,9 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout,
   // Write out the header for a SLN file
   this->WriteSLNHeader(fout);
   
-  // Get the home directory with the trailing slash
-  std::string homedir = root->GetMakefile()->GetCurrentDirectory();
-  homedir += "/";
+  // Get the start directory with the trailing slash
+  std::string rootdir = root->GetMakefile()->GetStartOutputDirectory();
+  rootdir += "/";
   bool doneAllBuild = false;
   bool doneRunTests = false;
   bool doneInstall  = false;
@@ -346,10 +346,10 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout,
     cmMakefile* mf = generators[i]->GetMakefile();
 
     // Get the source directory from the makefile
-    std::string dir = mf->GetStartDirectory();
+    std::string dir = mf->GetStartOutputDirectory();
     // remove the home directory and / from the source directory
     // this gives a relative path 
-    cmSystemTools::ReplaceString(dir, homedir.c_str(), "");
+    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

+ 4 - 4
Source/cmLocalGenerator.cxx

@@ -20,6 +20,7 @@
 #include "cmMakefile.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSourceFile.h"
+#include "cmSubDirectory.h"
 #include "cmOrderLinkDirectories.h"
 
 cmLocalGenerator::cmLocalGenerator()
@@ -318,12 +319,11 @@ void cmLocalGenerator::GenerateInstallRules()
   cmMakefile* mf = this->GetMakefile();
   if ( !mf->GetSubDirectories().empty() )
     {
-    const std::vector<std::pair<cmStdString, bool> >& subdirs = mf->GetSubDirectories();
-    std::vector<std::pair<cmStdString, bool> >::const_iterator i = subdirs.begin();
+    const std::vector<cmSubDirectory>& subdirs = mf->GetSubDirectories();
+    std::vector<cmSubDirectory>::const_iterator i = subdirs.begin();
     for(; i != subdirs.end(); ++i)
       {
-      std::string odir = mf->GetCurrentOutputDirectory();
-      odir += "/" + (*i).first;
+      std::string odir = i->BinaryPath;
       cmSystemTools::ConvertToUnixSlashes(odir);
       fout << "INCLUDE(\"" <<  odir.c_str() 
            << "/cmake_install.cmake\")" << std::endl;

+ 0 - 1
Source/cmLocalGenerator.h

@@ -177,7 +177,6 @@ protected:
   virtual void AddInstallRule(std::ostream& fout, const char* dest, int type, 
     const char* files, bool optional = false, const char* properties = 0);
   
-  bool m_FromTheTop;
   cmMakefile *m_Makefile;
   cmGlobalGenerator *m_GlobalGenerator;
   // members used for relative path function ConvertToMakefilePath

+ 12 - 11
Source/cmLocalUnixMakefileGenerator.cxx

@@ -22,6 +22,7 @@
 #include "cmMakeDepend.h"
 #include "cmCacheManager.h"
 #include "cmGeneratedFileStream.h"
+#include "cmSubDirectory.h"
 
 #include <cmsys/RegularExpression.hxx>
 
@@ -1738,15 +1739,15 @@ void cmLocalUnixMakefileGenerator::BuildInSubDirectory(std::ostream& fout,
 
 
 void 
-cmLocalUnixMakefileGenerator::
-OutputSubDirectoryVars(std::ostream& fout,
-                       const char* var,
-                       const char* target,
-                       const char* target1,
-                       const char* target2,
-                       const char* depend,
-                       const std::vector<std::pair<cmStdString, bool> >& SubDirectories,
-                       bool silent, int order)
+cmLocalUnixMakefileGenerator
+::OutputSubDirectoryVars(std::ostream& fout,
+                         const char* var,
+                         const char* target,
+                         const char* target1,
+                         const char* target2,
+                         const char* depend,
+                         const std::vector<cmSubDirectory>& SubDirectories,
+                         bool silent, int order)
 {
   if(!depend)
     {
@@ -1762,7 +1763,7 @@ OutputSubDirectoryVars(std::ostream& fout,
   
   // make sure all the pre-order subdirectories are fist
   // other than that keep the same order that the user specified
-  std::vector<std::pair<cmStdString, bool> > orderedDirs;
+  std::vector<cmStdString> orderedDirs;
   // collect pre-order first
   for(ii =0; ii < SubDirectories.size(); ii++)
     {
@@ -1847,7 +1848,7 @@ OutputSubDirectoryVars(std::ostream& fout,
 void cmLocalUnixMakefileGenerator::OutputSubDirectoryRules(std::ostream& fout)
 {
     // Output Sub directory build rules
-  const std::vector<std::pair<cmStdString, bool> >& SubDirectories
+  const std::map<std::string, cmSubDirectory>& SubDirectories
     = m_Makefile->GetSubDirectories();
     
   if( SubDirectories.size() == 0)

+ 3 - 2
Source/cmLocalUnixMakefileGenerator.h

@@ -23,6 +23,7 @@ class cmDependInformation;
 class cmMakeDepend;
 class cmTarget;
 class cmSourceFile;
+class cmSubDirectory;
 
 /** \class cmLocalUnixMakefileGenerator
  * \brief Write a LocalUnix makefiles.
@@ -148,8 +149,8 @@ protected:
                                       const char* target1,
                                       const char* target2,
                                       const char* depend,
-                                      const std::vector<std::pair<cmStdString, bool> >&
-                                      SubDirectories,
+                                      const std::map<std::string, 
+                                      cmSubDirectory>& SubDirectories,
                                       bool silent = false, int order = 0);
 
   virtual void OutputMakeRule(std::ostream&, 

+ 17 - 11
Source/cmLocalUnixMakefileGenerator2.cxx

@@ -21,6 +21,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
+#include "cmSubDirectory.h"
 #include "cmake.h"
 
 // Include dependency scanners for supported languages.  Only the
@@ -1313,23 +1314,24 @@ cmLocalUnixMakefileGenerator2
   // boolean is true should be included.  Keep track of the last
   // pre-order and last post-order rule created so that ordering can
   // be enforced.
-  const std::vector<std::pair<cmStdString, bool> >&
-    subdirs = m_Makefile->GetSubDirectories();
+  const std::vector<cmSubDirectory>& subdirs = m_Makefile->GetSubDirectories();
   std::string lastPre = "";
   std::string lastPost = "";
-  for(std::vector<std::pair<cmStdString, bool> >::const_iterator
+  for(std::vector<cmSubDirectory>::const_iterator
         i = subdirs.begin(); i != subdirs.end(); ++i)
     {
-    if(i->second)
+    if(i->IncludeTopLevel)
       {
       // Add the subdirectory rule either for pre-order or post-order.
-      if(m_Makefile->IsDirectoryPreOrder(i->first.c_str()))
+      if(i->PreOrder)
         {
-        this->WriteSubdirRule(makefileStream, pass, i->first.c_str(), lastPre);
+        this->WriteSubdirRule(makefileStream, pass, 
+                              i->BinaryPath.c_str(), lastPre);
         }
       else
         {
-        this->WriteSubdirRule(makefileStream, pass, i->first.c_str(), lastPost);
+        this->WriteSubdirRule(makefileStream, pass, 
+                              i->BinaryPath.c_str(), lastPost);
         }
       }
     }
@@ -1366,11 +1368,8 @@ cmLocalUnixMakefileGenerator2
 
     // Change back to the starting directory.  Any trailing slash must
     // be removed to avoid problems with Borland Make.
-    std::string destFull = m_Makefile->GetStartOutputDirectory();
-    destFull += "/";
-    destFull += subdir;
     std::string back =
-      cmSystemTools::RelativePath(destFull.c_str(),
+      cmSystemTools::RelativePath(subdir,
                                   m_Makefile->GetStartOutputDirectory());
     if(back.size() && back[back.size()-1] == '/')
       {
@@ -2254,6 +2253,13 @@ cmLocalUnixMakefileGenerator2
     {
     s.replace(pos, 1, "_");
     }
+
+  // Replace ":" drive specifier with a single underscore
+  while((pos = s.find(':')) != std::string::npos)
+    {
+    s.replace(pos, 1, "_");
+    }
+
   return s;
 }
 

+ 113 - 40
Source/cmMakefile.cxx

@@ -195,7 +195,6 @@ void cmMakefile::Print() const
   std::cout << " m_cmHomeDirectory; " << 
     m_cmHomeDirectory.c_str() << std::endl;
   std::cout << " m_ProjectName; " <<  m_ProjectName.c_str() << std::endl;
-  this->PrintStringVector("m_SubDirectories ", m_SubDirectories); 
   this->PrintStringVector("m_IncludeDirectories;", m_IncludeDirectories);
   this->PrintStringVector("m_LinkDirectories", m_LinkDirectories);
   for( std::vector<cmSourceGroup>::const_iterator i = m_SourceGroups.begin();
@@ -343,7 +342,7 @@ bool cmMakefile::ReadListFile(const char* filename_in, const char* external_in)
       }
     }
   
-      // keep track of the current file being read
+  // keep track of the current file being read
   if (filename)
     {
     if(m_cmCurrentListFile != filename)
@@ -364,35 +363,35 @@ bool cmMakefile::ReadListFile(const char* filename_in, const char* external_in)
   //   rather than the "external" call)
   if (!external)
     {
-      // is there a parent CMakeLists file that does not go beyond the
-      // Home directory? if so recurse and read in that List file 
-      std::string parentList = this->GetParentListFileName(filename);
-      if (parentList != "")
+    // is there a parent CMakeLists file that does not go beyond the
+    // Home directory? if so recurse and read in that List file 
+    std::string parentList = this->GetParentListFileName();
+    if (parentList != "")
+      {
+      std::string srcdir = this->GetCurrentDirectory();
+      std::string bindir = this->GetCurrentOutputDirectory();
+      
+      std::string::size_type pos = parentList.rfind('/');
+      this->SetCurrentDirectory(parentList.substr(0, pos).c_str());
+      this->SetCurrentOutputDirectory
+        ((m_HomeOutputDirectory +
+          parentList.substr(m_cmHomeDirectory.size(),
+                            pos - m_cmHomeDirectory.size())).c_str());
+      
+      // if not found, oops
+      if(pos == std::string::npos)
         {
-          std::string srcdir = this->GetCurrentDirectory();
-          std::string bindir = this->GetCurrentOutputDirectory();
-
-          std::string::size_type pos = parentList.rfind('/');
-
-          this->SetCurrentDirectory(parentList.substr(0, pos).c_str());
-          this->SetCurrentOutputDirectory((m_HomeOutputDirectory +
-                                           parentList.substr(m_cmHomeDirectory.size(),
-                                                             pos - m_cmHomeDirectory.size())).c_str());
-
-          // if not found, oops
-          if(pos == std::string::npos)
-            {
-            cmSystemTools::Error("Trailing slash not found");
-            }
-
-          this->ReadListFile(parentList.c_str());
-
-          // restore the current directory
-          this->SetCurrentDirectory(srcdir.c_str());
-          this->SetCurrentOutputDirectory(bindir.c_str());
+        cmSystemTools::Error("Trailing slash not found");
         }
+      
+      this->ReadListFile(parentList.c_str());
+      
+      // restore the current directory
+      this->SetCurrentDirectory(srcdir.c_str());
+      this->SetCurrentOutputDirectory(bindir.c_str());
+      }
     }
-
+  
   // are we at the start CMakeLists file or are we processing a parent 
   // lists file
   //
@@ -834,24 +833,52 @@ void cmMakefile::AddLinkDirectory(const char* dir)
     }
 }
 
-bool cmMakefile::IsDirectoryPreOrder(const char* dir)
-{
-  return (m_SubDirectoryOrder.find(dir) != m_SubDirectoryOrder.end());
-}
-
 void cmMakefile::AddSubDirectory(const char* sub, bool topLevel, bool preorder)
 {
-  if(preorder)
+  // the source path must be made full if it isn't already
+  std::string srcPath = sub;
+  if (!cmSystemTools::FileIsFullPath(srcPath.c_str()))
+    {
+    srcPath = this->GetCurrentDirectory();
+    srcPath += "/";
+    srcPath += sub;
+    }
+
+  // binary path must be made full if it isn't already
+  std::string binPath = sub;
+  if (!cmSystemTools::FileIsFullPath(binPath.c_str()))
     {
-    m_SubDirectoryOrder[sub] = preorder;
+    binPath = this->GetCurrentOutputDirectory();
+    binPath += "/";
+    binPath += sub;
     }
-  std::pair<cmStdString, bool> p(sub, topLevel);
-  // make sure it isn't already there
-  if (std::find(m_SubDirectories.begin(),
-                m_SubDirectories.end(), p) == m_SubDirectories.end())  
+  
+  
+  this->AddSubDirectory(srcPath.c_str(), binPath.c_str(), topLevel, preorder);
+}
+
+                        
+void cmMakefile::AddSubDirectory(const char* srcPath, const char *binPath,
+                                 bool topLevel, bool preorder)
+{
+  // has this directory already been added? If so error
+  unsigned int i;
+  for (i = 0; i < m_SubDirectories.size(); ++i)
     {
-    m_SubDirectories.push_back(p);
+    if (m_SubDirectories[i].SourcePath == srcPath)
+      {
+      cmSystemTools::Error("Attempt to add subdirectory multiple times for directory.\n", srcPath);
+      return;
+      }
     }
+  
+  // now add it
+  cmSubDirectory s;
+  s.SourcePath = srcPath;
+  s.BinaryPath = binPath;
+  s.IncludeTopLevel = topLevel;
+  s.PreOrder = preorder;
+  m_SubDirectories.push_back(s);
 }
 
 void cmMakefile::AddIncludeDirectory(const char* inc, bool before)
@@ -1185,6 +1212,51 @@ void cmMakefile::AddExtraDirectory(const char* dir)
   m_AuxSourceDirectories.push_back(dir);
 }
 
+// return the file name for a parent CMakeLists file. It will return the
+// parent to the CMakeLists file to the m_CurrentDirectory
+
+
+std::string cmMakefile::GetParentListFileName()
+{
+  std::string parentFile;
+
+  bool done = false;
+  cmLocalGenerator *lg = m_LocalGenerator;
+  cmLocalGenerator *lgp = 0;
+  
+  while (!done)
+    {
+    // first find the lg for the current directory
+    if (!strcmp(lg->GetMakefile()->GetStartDirectory(),
+                this->GetCurrentDirectory()))
+      {
+      // now get the parent
+      lgp = lg->GetParent();
+      done = true;
+      }
+    else
+      {
+      lg = lg->GetParent();
+      if (!lg)
+        {
+        return parentFile;
+        }
+      }
+    }
+  
+  // if we are the top then stop
+  if (!lgp)
+    {
+    return parentFile;
+    }
+  
+  // otherwise get the list file for the parent local generator
+  parentFile = lgp->GetMakefile()->GetCurrentDirectory();
+  parentFile += "/CMakeLists.txt";
+  return parentFile;
+}
+
+#if 0
 
 // return the file name for the parent CMakeLists file to the 
 // one passed in. Zero is returned if the CMakeLists file is the
@@ -1243,6 +1315,7 @@ std::string cmMakefile::GetParentListFileName(const char *currentFileName)
 
   return parentFile;
 }
+#endif
 
 // expance CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR in the
 // include and library directories.

+ 9 - 8
Source/cmMakefile.h

@@ -24,6 +24,8 @@
 #include "cmListFileCache.h"
 #include "cmCacheManager.h"
 
+#include "cmSubDirectory.h"
+
 #include <cmsys/RegularExpression.hxx>
 
 class cmFunctionBlocker;
@@ -212,6 +214,8 @@ public:
    * Add a subdirectory to the build.
    */
   void AddSubDirectory(const char*, bool includeTopLevel=true, bool preorder = false);
+  void AddSubDirectory(const char* fullSrcDir,const char *fullBinDir, 
+                       bool includeTopLevel=true, bool preorder = false);
 
   /**
    * Add an include directory to the build.
@@ -416,7 +420,7 @@ public:
   /**
    * Get a list of the build subdirectories.
    */
-  const std::vector<std::pair<cmStdString, bool> >& GetSubDirectories()
+  const std::vector<cmSubDirectory>& GetSubDirectories()
     { 
     return m_SubDirectories;
     }
@@ -653,9 +657,6 @@ public:
    */
   std::string GetModulesFile(const char* name);
 
-  ///! Return true if the directory is preorder.
-  bool IsDirectoryPreOrder(const char* dir);
-  
   ///! Set/Get a property of this directory 
   void SetProperty(const char *prop, const char *value);
   const char *GetProperty(const char *prop) const;
@@ -683,7 +684,8 @@ protected:
   cmTargets m_Targets;
   std::vector<cmSourceFile*> m_SourceFiles;
 
-  std::vector<std::pair<cmStdString, bool> > m_SubDirectories; // list of sub directories
+  // list of sub directories
+  std::vector<cmSubDirectory> m_SubDirectories; 
   struct StringSet : public std::set<cmStdString>
   {
   };
@@ -712,10 +714,9 @@ protected:
   
 private:
   /**
-   * Get the name of the parent directories CMakeLists file
-   * given a current CMakeLists file name
+   * Get the name of the parent generator's CMakeLists file
    */
-  std::string GetParentListFileName(const char *listFileName);
+  std::string GetParentListFileName();
 
   void ReadSources(std::ifstream& fin, bool t);
   friend class cmMakeDepend;    // make depend needs direct access 

+ 22 - 5
Source/cmSubdirCommand.cxx

@@ -41,16 +41,33 @@ bool cmSubdirCommand::InitialPass(std::vector<std::string> const& args)
       preorder = true;
       continue;
       }
-    std::string directory = std::string(m_Makefile->GetCurrentDirectory()) + 
-      "/" + i->c_str();
-    if ( cmSystemTools::FileIsDirectory(directory.c_str()) )
+
+    // if they specified a relative path then compute the full
+    std::string srcPath = std::string(m_Makefile->GetCurrentDirectory()) + 
+        "/" + i->c_str();
+    if (cmSystemTools::FileIsDirectory(srcPath.c_str()))
+      {
+      std::string binPath = 
+        std::string(m_Makefile->GetCurrentOutputDirectory()) + 
+        "/" + i->c_str();
+      m_Makefile->AddSubDirectory(srcPath.c_str(), binPath.c_str(),
+                                  intoplevel, preorder);
+      }
+    // otherwise it is a full path
+    else if ( cmSystemTools::FileIsDirectory(i->c_str()) )
       {
-      m_Makefile->AddSubDirectory(i->c_str(), intoplevel, preorder);
+      // we must compute the binPath from the srcPath, we just take the last
+      // element from the source path and use that
+      std::string binPath = 
+        std::string(m_Makefile->GetCurrentOutputDirectory()) + 
+        "/" + cmSystemTools::GetFilenameName(i->c_str());
+      m_Makefile->AddSubDirectory(i->c_str(), binPath.c_str(),
+                                  intoplevel, preorder);
       }
     else
       {
       std::string error = "Incorrect SUBDIRS command. Directory: ";
-      error += directory + " does not exists.";
+      error += *i + " does not exists.";
       this->SetError(error.c_str());   
       res = false;
       }