From 5ccfaefb48758c7af0df011df160add1df1e1b53 Mon Sep 17 00:00:00 2001
From: Bill Hoffman <bill.hoffman@kitware.com>
Date: Wed, 26 Nov 2003 14:29:53 -0500
Subject: ENH: generate a sln and dsw file for each sub project in a project

---
 Source/cmGlobalVisualStudio6Generator.cxx | 255 +++++++++++++++++++-----------
 Source/cmGlobalVisualStudio6Generator.h   |   6 +-
 Source/cmGlobalVisualStudio7Generator.cxx | 151 +++++++++++++-----
 Source/cmGlobalVisualStudio7Generator.h   |   6 +-
 Source/cmMakefile.cxx                     |   4 +
 Source/cmMakefile.h                       |   5 +
 6 files changed, 291 insertions(+), 136 deletions(-)

diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx
index 75b7467..5ff3f12 100644
--- a/Source/cmGlobalVisualStudio6Generator.cxx
+++ b/Source/cmGlobalVisualStudio6Generator.cxx
@@ -156,12 +156,24 @@ cmLocalGenerator *cmGlobalVisualStudio6Generator::CreateLocalGenerator()
 
 void cmGlobalVisualStudio6Generator::Generate()
 {
+  // collect sub-projects
+  this->CollectSubprojects();
+  
   // add a special target that depends on ALL projects for easy build
-  // of Debug only
+  // of one configuration only.  
   std::vector<std::string> srcs;
-  m_LocalGenerators[0]->GetMakefile()->
-    AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false,srcs);
-
+  std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
+  for(it = m_SubProjectMap.begin(); it!= m_SubProjectMap.end(); ++it)
+    {
+    std::vector<cmLocalGenerator*>& gen = it->second;
+    // add the ALL_BUILD to the first local generator of each project
+    if(gen.size())
+      {
+      gen[0]->GetMakefile()->
+        AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false,srcs);
+      }
+    }
+  
   // add the Run Tests command
   this->SetupTests();
   
@@ -172,104 +184,40 @@ void cmGlobalVisualStudio6Generator::Generate()
   this->OutputDSWFile();
 }
 
-// output the DSW file
-void cmGlobalVisualStudio6Generator::OutputDSWFile()
-{ 
-  // create the dsw file name
-  std::string fname;
-  fname = m_CMakeInstance->GetStartOutputDirectory();
-  fname += "/";
-  if(strlen(m_LocalGenerators[0]->GetMakefile()->GetProjectName()))
-    {
-    fname += m_LocalGenerators[0]->GetMakefile()->GetProjectName();
-    }
-  else
-    {
-    fname += "Project";
-    }
-  fname += ".dsw";
-  std::ofstream fout(fname.c_str());
-  if(!fout)
-    {
-    cmSystemTools::Error("Error can not open DSW file for write: "
-                         ,fname.c_str());
-    return;
-    }
-  this->WriteDSWFile(fout);
-}
-
-
-inline std::string removeQuotes(const std::string& s)
+// populate the m_SubProjectMap 
+void cmGlobalVisualStudio6Generator::CollectSubprojects()
 {
-  if(s[0] == '\"' && s[s.size()-1] == '\"')
-    {
-    return s.substr(1, s.size()-2);
-    }
-  return s;
-}
-
-
-void cmGlobalVisualStudio6Generator::SetupTests()
-{
-  std::string ctest = 
-    m_LocalGenerators[0]->GetMakefile()->GetDefinition("CMAKE_COMMAND");
-  ctest = removeQuotes(ctest);
-  ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
-  ctest += "/";
-  ctest += "ctest";
-  ctest += cmSystemTools::GetExecutableExtension();
-  if(!cmSystemTools::FileExists(ctest.c_str()))
-    {
-    ctest =     
-      m_LocalGenerators[0]->GetMakefile()->GetDefinition("CMAKE_COMMAND");
-    ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
-    ctest += "/Debug/";
-    ctest += "ctest";
-    ctest += cmSystemTools::GetExecutableExtension();
-    }
-  if(!cmSystemTools::FileExists(ctest.c_str()))
-    {
-    ctest =     
-      m_LocalGenerators[0]->GetMakefile()->GetDefinition("CMAKE_COMMAND");
-    ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
-    ctest += "/Release/";
-    ctest += "ctest";
-    ctest += cmSystemTools::GetExecutableExtension();
-    }
-  // if we found ctest
-  if (cmSystemTools::FileExists(ctest.c_str()))
+  unsigned int i;
+  for(i = 0; i < m_LocalGenerators.size(); ++i)
     {
-    // Create a full path filename for output Testfile
-    std::string fname;
-    fname = m_CMakeInstance->GetStartOutputDirectory();
-    fname += "/";
-    fname += "DartTestfile.txt";
-    
-    // If the file doesn't exist, then ENABLE_TESTING hasn't been run
-    if (cmSystemTools::FileExists(fname.c_str()))
+    std::string name = m_LocalGenerators[i]->GetMakefile()->GetProjectName();
+    m_SubProjectMap[name].push_back(m_LocalGenerators[i]);
+    std::vector<std::string> const& pprojects 
+      = m_LocalGenerators[i]->GetMakefile()->GetParentProjects();
+    for(int k =0; k < pprojects.size(); ++k)
       {
-      std::vector<std::string> srcs;
-      m_LocalGenerators[0]->GetMakefile()->
-        AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false,srcs);
+      m_SubProjectMap[pprojects[k]].push_back(m_LocalGenerators[i]);
       }
     }
 }
 
 // Write a DSW file to the stream
-void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout)
+void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout,
+                                                  std::vector<cmLocalGenerator*>& generators)
 {
   // Write out the header for a DSW file
   this->WriteDSWHeader(fout);
   
-  
   // Get the home directory with the trailing slash
   std::string homedir = m_CMakeInstance->GetHomeDirectory();
   homedir += "/";
     
   unsigned int i;
-  for(i = 0; i < m_LocalGenerators.size(); ++i)
+  bool doneAllBuild = false;
+  bool doneRunTests = false;
+  for(i = 0; i < generators.size(); ++i)
     {
-    cmMakefile* mf = m_LocalGenerators[i]->GetMakefile();
+    cmMakefile* mf = generators[i]->GetMakefile();
     
     // Get the source directory from the makefile
     std::string dir = mf->GetStartDirectory();
@@ -281,28 +229,28 @@ void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout)
     // than one dsp could have been created per input CMakeLists.txt file
     // for each target
     std::vector<std::string> dspnames = 
-      static_cast<cmLocalVisualStudio6Generator *>(m_LocalGenerators[i])
+      static_cast<cmLocalVisualStudio6Generator *>(generators[i])
       ->GetCreatedProjectNames();
-    cmTargets &tgts = m_LocalGenerators[i]->GetMakefile()->GetTargets();
+    cmTargets &tgts = generators[i]->GetMakefile()->GetTargets();
     cmTargets::iterator l = tgts.begin();
     for(std::vector<std::string>::iterator si = dspnames.begin(); 
         l != tgts.end(); ++l)
       {
       // special handling for the current makefile
-      if(mf == m_LocalGenerators[0]->GetMakefile())
+      if(mf == generators[0]->GetMakefile())
         {
         dir = "."; // no subdirectory for project generated
         // if this is the special ALL_BUILD utility, then
         // make it depend on every other non UTILITY project.
         // This is done by adding the names to the GetUtilities
         // vector on the makefile
-        if(l->first == "ALL_BUILD")
+        if(l->first == "ALL_BUILD" && !doneAllBuild)
           {
           unsigned int j;
-          for(j = 0; j < m_LocalGenerators.size(); ++j)
+          for(j = 0; j < generators.size(); ++j)
             {
             const cmTargets &atgts = 
-              m_LocalGenerators[j]->GetMakefile()->GetTargets();
+              generators[j]->GetMakefile()->GetTargets();
             for(cmTargets::const_iterator al = atgts.begin();
                 al != atgts.end(); ++al)
               {
@@ -339,7 +287,34 @@ void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout)
         if ((l->second.GetType() != cmTarget::INSTALL_FILES)
             && (l->second.GetType() != cmTarget::INSTALL_PROGRAMS))
           {
-          this->WriteProject(fout, si->c_str(), dir.c_str(),l->second);
+          bool skip = false;
+          // skip ALL_BUILD and RUN_TESTS if they have already been added
+          if(l->first == "ALL_BUILD" )
+            {
+            if(doneAllBuild)
+              {
+              skip = true;
+              }
+            else
+              {
+              doneAllBuild = true;
+              }
+            }
+          if(l->first == "RUN_TESTS")
+            {
+            if(doneRunTests)
+              {
+              skip = true;
+              }
+            else
+              {
+              doneRunTests = true;
+              }
+            }
+          if(!skip)
+            {
+            this->WriteProject(fout, si->c_str(), dir.c_str(),l->second);
+            }
           ++si;
           }
         }
@@ -350,6 +325,104 @@ void cmGlobalVisualStudio6Generator::WriteDSWFile(std::ostream& fout)
   this->WriteDSWFooter(fout);
 }
 
+void cmGlobalVisualStudio6Generator::OutputDSWFile(const char* projectName,
+                                                   std::vector<cmLocalGenerator*>& generators)
+{
+  if(generators.size() == 0)
+    {
+    return;
+    }
+  std::string fname = generators[0]->GetMakefile()->GetStartOutputDirectory();
+  fname += "/";
+  fname += generators[0]->GetMakefile()->GetProjectName();
+  fname += ".dsw";
+  std::ofstream fout(fname.c_str());
+  if(!fout)
+    {
+    cmSystemTools::Error("Error can not open DSW file for write: ",
+                         fname.c_str());
+    return;
+    }
+  this->WriteDSWFile(fout, generators);
+}
+
+// output the DSW file
+void cmGlobalVisualStudio6Generator::OutputDSWFile()
+{ 
+  std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
+  for(it = m_SubProjectMap.begin(); it!= m_SubProjectMap.end(); ++it)
+    {
+    std::vector<cmLocalGenerator*>& gen = it->second;
+    this->OutputDSWFile(it->first.c_str(), it->second);
+    }
+}
+
+
+inline std::string removeQuotes(const std::string& s)
+{
+  if(s[0] == '\"' && s[s.size()-1] == '\"')
+    {
+    return s.substr(1, s.size()-2);
+    }
+  return s;
+}
+
+
+void cmGlobalVisualStudio6Generator::SetupTests()
+{
+  std::string ctest = 
+    m_LocalGenerators[0]->GetMakefile()->GetDefinition("CMAKE_COMMAND");
+  ctest = removeQuotes(ctest);
+  ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
+  ctest += "/";
+  ctest += "ctest";
+  ctest += cmSystemTools::GetExecutableExtension();
+  if(!cmSystemTools::FileExists(ctest.c_str()))
+    {
+    ctest =     
+      m_LocalGenerators[0]->GetMakefile()->GetDefinition("CMAKE_COMMAND");
+    ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
+    ctest += "/Debug/";
+    ctest += "ctest";
+    ctest += cmSystemTools::GetExecutableExtension();
+    }
+  if(!cmSystemTools::FileExists(ctest.c_str()))
+    {
+    ctest =     
+      m_LocalGenerators[0]->GetMakefile()->GetDefinition("CMAKE_COMMAND");
+    ctest = cmSystemTools::GetFilenamePath(ctest.c_str());
+    ctest += "/Release/";
+    ctest += "ctest";
+    ctest += cmSystemTools::GetExecutableExtension();
+    }
+  // if we found ctest
+  if (cmSystemTools::FileExists(ctest.c_str()))
+    {
+    // Create a full path filename for output Testfile
+    std::string fname;
+    fname = m_CMakeInstance->GetStartOutputDirectory();
+    fname += "/";
+    fname += "DartTestfile.txt";
+    
+    // If the file doesn't exist, then ENABLE_TESTING hasn't been run
+    if (cmSystemTools::FileExists(fname.c_str()))
+      {
+      std::vector<std::string> srcs;
+      std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
+      for(it = m_SubProjectMap.begin(); it!= m_SubProjectMap.end(); ++it)
+        {
+        std::vector<cmLocalGenerator*>& gen = it->second;
+        // add the ALL_BUILD to the first local generator of each project
+        if(gen.size())
+          {
+          gen[0]->GetMakefile()->
+            AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false,srcs);
+          }
+        }
+      }
+    }
+}
+
 
 // Write a dsp file into the DSW file,
 // Note, that dependencies from executables to 
diff --git a/Source/cmGlobalVisualStudio6Generator.h b/Source/cmGlobalVisualStudio6Generator.h
index 4df1a70..ff0d8a3 100644
--- a/Source/cmGlobalVisualStudio6Generator.h
+++ b/Source/cmGlobalVisualStudio6Generator.h
@@ -68,8 +68,11 @@ public:
    * Generate the DSW workspace file.
    */
   virtual void OutputDSWFile();
-
+  virtual void OutputDSWFile(const char* projectName, std::vector<cmLocalGenerator*>& generators);
+  virtual void WriteDSWFile(std::ostream& fout,
+                            std::vector<cmLocalGenerator*>& generators);
 private:
+  void CollectSubprojects();
   void GenerateConfigurations(cmMakefile* mf);
   void SetupTests();
   void WriteDSWFile(std::ostream& fout);
@@ -81,6 +84,7 @@ private:
                             const char* name, const char* path,
                             const std::vector<std::string>& dependencies);
   void WriteDSWFooter(std::ostream& fout);
+  std::map<cmStdString, std::vector<cmLocalGenerator*> > m_SubProjectMap;
 };
 
 #endif
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 5435190..0d0eade 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -157,8 +157,17 @@ void cmGlobalVisualStudio7Generator::SetupTests()
     if (cmSystemTools::FileExists(fname.c_str()))
       {
       std::vector<std::string> srcs;
-      m_LocalGenerators[0]->GetMakefile()->
-        AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false, srcs);
+      std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
+      for(it = m_SubProjectMap.begin(); it!= m_SubProjectMap.end(); ++it)
+        {
+        std::vector<cmLocalGenerator*>& gen = it->second;
+        // add the ALL_BUILD to the first local generator of each project
+        if(gen.size())
+          {
+          gen[0]->GetMakefile()->
+            AddUtilityCommand("RUN_TESTS", ctest.c_str(), "-D $(IntDir)",false,srcs);
+          }
+        }
       }
     }
 }
@@ -233,11 +242,22 @@ void cmGlobalVisualStudio7Generator::GenerateConfigurations(cmMakefile* mf)
 
 void cmGlobalVisualStudio7Generator::Generate()
 {
+  // collect sub-projects
+  this->CollectSubprojects();
   // add a special target that depends on ALL projects for easy build
   // of Debug only
   std::vector<std::string> srcs;
-  m_LocalGenerators[0]->GetMakefile()->
-    AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false, srcs);
+  std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
+  for(it = m_SubProjectMap.begin(); it!= m_SubProjectMap.end(); ++it)
+    {
+    std::vector<cmLocalGenerator*>& gen = it->second;
+    // add the ALL_BUILD to the first local generator of each project
+    if(gen.size())
+      {
+      gen[0]->GetMakefile()->
+        AddUtilityCommand("ALL_BUILD", "echo","\"Build all projects\"",false,srcs);
+      }
+    }
   
   // add the Run Tests command
   this->SetupTests();
@@ -249,42 +269,42 @@ void cmGlobalVisualStudio7Generator::Generate()
   this->OutputSLNFile();
 }
 
-// output the SLN file
-void cmGlobalVisualStudio7Generator::OutputSLNFile()
-{ 
-  // if this is an out of source build, create the output directory
-  if(strcmp(m_CMakeInstance->GetStartOutputDirectory(),
-            m_CMakeInstance->GetHomeDirectory()) != 0)
+void cmGlobalVisualStudio7Generator::OutputSLNFile(const char* projectName,
+                                                   std::vector<cmLocalGenerator*>& generators)
+{
+  if(generators.size() == 0)
     {
-    if(!cmSystemTools::MakeDirectory(m_CMakeInstance->GetStartOutputDirectory()))
-      {
-      cmSystemTools::Error("Error creating output directory for SLN file",
-                           m_CMakeInstance->GetStartOutputDirectory());
-      }
+    return;
     }
-  // create the dsw file name
-  std::string fname;
-  fname = m_CMakeInstance->GetStartOutputDirectory();
+  std::string fname = generators[0]->GetMakefile()->GetStartOutputDirectory();
   fname += "/";
-  if(strlen(m_LocalGenerators[0]->GetMakefile()->GetProjectName()) == 0)
-    {
-    m_LocalGenerators[0]->GetMakefile()->SetProjectName("Project");
-    }
-  fname += m_LocalGenerators[0]->GetMakefile()->GetProjectName();
+  fname += generators[0]->GetMakefile()->GetProjectName();
   fname += ".sln";
   std::ofstream fout(fname.c_str());
   if(!fout)
     {
-    cmSystemTools::Error("Error can not open SLN file for write: "
-                         ,fname.c_str());
+    cmSystemTools::Error("Error can not open DSW file for write: ",
+                         fname.c_str());
     return;
     }
-  this->WriteSLNFile(fout);
+  this->WriteSLNFile(fout, generators);
+}
+
+// output the SLN file
+void cmGlobalVisualStudio7Generator::OutputSLNFile()
+{ 
+  std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
+  for(it = m_SubProjectMap.begin(); it!= m_SubProjectMap.end(); ++it)
+    {
+    std::vector<cmLocalGenerator*>& gen = it->second;
+    this->OutputSLNFile(it->first.c_str(), it->second);
+    }
 }
 
 
 // Write a SLN file to the stream
-void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout)
+void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout,
+                                                  std::vector<cmLocalGenerator*>& generators)
 {
   // Write out the header for a SLN file
   this->WriteSLNHeader(fout);
@@ -292,13 +312,15 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout)
   // Get the home directory with the trailing slash
   std::string homedir = m_CMakeInstance->GetHomeDirectory();
   homedir += "/";
-    
+  bool doneAllBuild = false;
+  bool doneRunTests = false;
+  
   // For each cmMakefile, create a VCProj for it, and
   // add it to this SLN file
   unsigned int i;
-  for(i = 0; i < m_LocalGenerators.size(); ++i)
+  for(i = 0; i < generators.size(); ++i)
     {
-    cmMakefile* mf = m_LocalGenerators[i]->GetMakefile();
+    cmMakefile* mf = generators[i]->GetMakefile();
 
     // Get the source directory from the makefile
     std::string dir = mf->GetStartDirectory();
@@ -310,28 +332,28 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout)
     // than one dsp could have been created per input CMakeLists.txt file
     // for each target
     std::vector<std::string> dspnames = 
-      static_cast<cmLocalVisualStudio7Generator *>(m_LocalGenerators[i])
+      static_cast<cmLocalVisualStudio7Generator *>(generators[i])
       ->GetCreatedProjectNames();
-    cmTargets &tgts = m_LocalGenerators[i]->GetMakefile()->GetTargets();
+    cmTargets &tgts = generators[i]->GetMakefile()->GetTargets();
     cmTargets::iterator l = tgts.begin();
     for(std::vector<std::string>::iterator si = dspnames.begin(); 
         l != tgts.end(); ++l)
       {
       // special handling for the current makefile
-      if(mf == m_LocalGenerators[0]->GetMakefile())
+      if(mf == generators[0]->GetMakefile())
         {
         dir = "."; // no subdirectory for project generated
         // if this is the special ALL_BUILD utility, then
         // make it depend on every other non UTILITY project.
         // This is done by adding the names to the GetUtilities
         // vector on the makefile
-        if(l->first == "ALL_BUILD")
+        if(l->first == "ALL_BUILD" && !doneAllBuild)
           {
           unsigned int j;
-          for(j = 0; j < m_LocalGenerators.size(); ++j)
+          for(j = 0; j < generators.size(); ++j)
             {
             const cmTargets &atgts = 
-              m_LocalGenerators[j]->GetMakefile()->GetTargets();
+              generators[j]->GetMakefile()->GetTargets();
             for(cmTargets::const_iterator al = atgts.begin();
                 al != atgts.end(); ++al)
               {
@@ -369,7 +391,33 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout)
         if ((l->second.GetType() != cmTarget::INSTALL_FILES)
             && (l->second.GetType() != cmTarget::INSTALL_PROGRAMS))
           {
-          this->WriteProject(fout, si->c_str(), dir.c_str(),l->second);
+          bool skip = false;
+                if(l->first == "ALL_BUILD" )
+            {
+            if(doneAllBuild)
+              {
+              skip = true;
+              }
+            else
+              {
+              doneAllBuild = true;
+              }
+            }
+          if(l->first == "RUN_TESTS")
+            {
+            if(doneRunTests)
+              {
+              skip = true;
+              }
+            else
+              {
+              doneRunTests = true;
+              }
+            }
+          if(!skip)
+            {
+            this->WriteProject(fout, si->c_str(), dir.c_str(),l->second);
+            }
           ++si;
           }
         }
@@ -389,11 +437,11 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout)
        << "\tGlobalSection(ProjectDependencies) = postSolution\n";
 
   // loop over again and compute the depends
-  for(i = 0; i < m_LocalGenerators.size(); ++i)
+  for(i = 0; i < generators.size(); ++i)
     {
-    cmMakefile* mf = m_LocalGenerators[i]->GetMakefile();
+    cmMakefile* mf = generators[i]->GetMakefile();
     cmLocalVisualStudio7Generator* pg =  
-      static_cast<cmLocalVisualStudio7Generator*>(m_LocalGenerators[i]);
+      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
@@ -416,11 +464,11 @@ void cmGlobalVisualStudio7Generator::WriteSLNFile(std::ostream& fout)
   fout << "\tEndGlobalSection\n";
   fout << "\tGlobalSection(ProjectConfiguration) = postSolution\n";
   // loop over again and compute the depends
-  for(i = 0; i < m_LocalGenerators.size(); ++i)
+  for(i = 0; i < generators.size(); ++i)
     {
-    cmMakefile* mf = m_LocalGenerators[i]->GetMakefile();
+    cmMakefile* mf = generators[i]->GetMakefile();
     cmLocalVisualStudio7Generator* pg =  
-      static_cast<cmLocalVisualStudio7Generator*>(m_LocalGenerators[i]);
+      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
@@ -603,3 +651,20 @@ void cmGlobalVisualStudio7Generator::GetDocumentation(cmDocumentationEntry& entr
   entry.brief = "Generates Visual Studio .NET 2002 project files.";
   entry.full = "";
 }
+
+// populate the m_SubProjectMap 
+void cmGlobalVisualStudio7Generator::CollectSubprojects()
+{
+  unsigned int i;
+  for(i = 0; i < m_LocalGenerators.size(); ++i)
+    {
+    std::string name = m_LocalGenerators[i]->GetMakefile()->GetProjectName();
+    m_SubProjectMap[name].push_back(m_LocalGenerators[i]);
+    std::vector<std::string> const& pprojects 
+      = m_LocalGenerators[i]->GetMakefile()->GetParentProjects();
+    for(int k =0; k < pprojects.size(); ++k)
+      {
+      m_SubProjectMap[pprojects[k]].push_back(m_LocalGenerators[i]);
+      }
+    }
+}
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index a268a44..a8e2fb1 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -82,7 +82,10 @@ public:
   std::vector<std::string> *GetConfigurations();
       
 protected:
-  virtual void WriteSLNFile(std::ostream& fout);
+  void CollectSubprojects();
+  void OutputSLNFile(const char* projectName,
+                     std::vector<cmLocalGenerator*>& generators);
+  virtual void WriteSLNFile(std::ostream& fout, std::vector<cmLocalGenerator*>& generators);
   virtual void WriteProject(std::ostream& fout, 
                             const char* name, const char* path,
                             const cmTarget &t);
@@ -103,6 +106,7 @@ protected:
 
   std::vector<std::string> m_Configurations;
   std::map<cmStdString, cmStdString> m_GUIDMap;
+  std::map<cmStdString, std::vector<cmLocalGenerator*> > m_SubProjectMap;
 };
 
 #endif
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index c1bb833..348c489 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -954,6 +954,10 @@ void cmMakefile::RemoveDefinition(const char* name)
 
 void cmMakefile::SetProjectName(const char* p)
 {
+  if(m_ProjectName.size())
+    {
+    m_ParentProjects.push_back(m_ProjectName);
+    }
   m_ProjectName = p;
 }
 
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 37678e7..28a5c3e 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -252,6 +252,10 @@ public:
     return m_ProjectName.c_str();
     }
   
+  std::vector<std::string> const& GetParentProjects()
+    {
+      return m_ParentProjects;
+    }
   /**
    * Set the name of the library.
    */
@@ -630,6 +634,7 @@ protected:
   std::string m_cmCurrentListFile;
 
   std::string m_ProjectName;    // project name
+  std::vector<std::string> m_ParentProjects;
 
   // libraries, classes, and executables
   cmTargets m_Targets;
-- 
cgit v0.12