MantisBT - CMake
View Issue Details
0003218CMakeCMakepublic2006-05-11 02:322008-02-06 10:12
Manuel Klimek 
Bill Hoffman 
normalfeaturealways
closedfixed 
 
 
0003218: Automatic Visual Studio dependency generation (patch)
The visual studio sln generator should write dependant projects from the same cmake tree automatically.

--- cmake-2.4.1-orig/Source/cmGlobalVisualStudio71Generator.cxx 2006-04-30 17:06:37.000000000 +0200
+++ cmake-2.4.1/Source/cmGlobalVisualStudio71Generator.cxx 2006-05-10 13:36:19.343750000 +0200
@@ -44,7 +44,7 @@
 // Write a SLN file to the stream
 void cmGlobalVisualStudio71Generator::WriteSLNFile(std::ostream& fout,
                                                    cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+ std::vector<cmLocalGenerator*>& localGenerators)
 {
   // Write out the header for a SLN file
   this->WriteSLNHeader(fout);
@@ -59,7 +59,71 @@
   bool doneEditCache = false;
   bool doneRebuildCache = false;
   bool donePackage = false;
-
+
+ std::vector<cmLocalGenerator*> generators = localGenerators;
+ if(!generators.empty())
+ {
+ // calculate closure on library dependencies
+ cmLocalGenerator *topGenerator = generators[0];
+ while(topGenerator->GetParent() != NULL)
+ {
+ topGenerator = topGenerator->GetParent();
+ }
+ unsigned int lastSize = 0;
+ do
+ {
+ std::vector<cmLocalGenerator*> dependencyGenerators;
+ lastSize = generators.size();
+ // build closure
+ for(unsigned int i=0; i<generators.size(); ++i)
+ {
+ cmMakefile *makefile = generators[i]->GetMakefile();
+ for(cmTargets::iterator it=makefile->GetTargets().begin(); it != makefile->GetTargets().end(); ++it)
+ {
+ if(it->second.GetType() != cmTarget::STATIC_LIBRARY)
+ {
+ cmTarget::LinkLibraryVectorType::const_iterator j, jend;
+ j = it->second.GetLinkLibraries().begin();
+ jend = it->second.GetLinkLibraries().end();
+ for(;j!= jend; ++j)
+ {
+ cmTarget *dependency = topGenerator->GetGlobalGenerator()->FindTarget(NULL, j->first.c_str());
+ if(dependency)
+ {
+ cmLocalGenerator* generator = topGenerator->GetGlobalGenerator()->FindLocalGenerator(dependency->GetMakefile()->GetCurrentDirectory());
+ bool found = false;
+ for(unsigned int k=0; k<generators.size() && !found; ++k)
+ {
+ if(generators[k] == generator)
+ {
+ found = true;
+ }
+ }
+ for(unsigned int k=0; k<dependencyGenerators.size() && !found; ++k)
+ {
+ if(dependencyGenerators[k] == generator)
+ {
+ found = true;
+ }
+ }
+ if(!found)
+ {
+ dependencyGenerators.push_back(generator);
+ this->ProjectMap[generators[i]->GetMakefile()->GetProjectName()].push_back(generator);
+ }
+ }
+ }
+ }
+ }
+ }
+ for(unsigned int i=0; i<dependencyGenerators.size(); ++i)
+ {
+ generators.push_back(dependencyGenerators[i]);
+ }
+ }
+ while(lastSize < generators.size());
+ }
+
   // For each cmMakefile, create a VCProj for it, and
   // add it to this SLN file
   unsigned int i;
No tags attached.
? patch (8,549) 2007-08-09 08:48
https://public.kitware.com/Bug/file/1094/patch
Issue History
2007-08-09 08:48Torsten MartinsenFile Added: patch
2007-08-09 08:48Torsten MartinsenNote Added: 0008385
2007-08-30 10:32Mathieu MalaterreAssigned ToSystem Admin =>
2007-08-30 10:33Mathieu MalaterreAssigned To => Alex Neundorf
2007-08-30 10:48Alex NeundorfAssigned ToAlex Neundorf => Bill Hoffman
2008-02-06 10:12Bill HoffmanStatusassigned => closed
2008-02-06 10:12Bill HoffmanNote Added: 0010385
2008-02-06 10:12Bill HoffmanResolutionopen => fixed

Notes
(0004392)
Manuel Klimek   
2006-07-03 02:04   
New patch: works for me quite well ;-)

Index: cmGlobalVisualStudio71Generator.cxx
===================================================================
--- cmGlobalVisualStudio71Generator.cxx (.../tags/cmake-2.4.2/Source/cmGlobalVisualStudio71Generator.cxx) (revision 16548)
+++ cmGlobalVisualStudio71Generator.cxx (.../trunk/cmake/Source/cmGlobalVisualStudio71Generator.cxx) (revision 16548)
@@ -48,7 +48,7 @@
 void cmGlobalVisualStudio71Generator
 ::WriteSLNFile(std::ostream& fout,
                                                    cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+ std::vector<cmLocalGenerator*>& localGenerators)
 {
   // Write out the header for a SLN file
   this->WriteSLNHeader(fout);
@@ -64,6 +64,150 @@
   bool doneRebuildCache = false;
   bool donePackage = false;
   
+ std::vector<cmLocalGenerator*> generators = localGenerators;
+ if(!generators.empty())
+ {
+ // initialize used targets
+ // for every generator we'll store all targets in this
+ // generator we depend on
+ // we start by adding all targets in the generators we got
+ // as parameter to this method:
+ // (this adds cmake standard targets like INSTALL and ZERO_CHECK etc,
+ // too, which is used later to prevent totally unrelated projects
+ // from getting linked in by FindTarget with a standard target as
+ // argument)
+ std::vector< std::vector<cmTarget*> > usedTargets(generators.size());
+ for(unsigned int i=0; i<generators.size(); ++i)
+ {
+ cmMakefile *makefile = generators[i]->GetMakefile();
+ // add all targets to our "used target matrix"
+ for(cmTargets::iterator it=makefile->GetTargets().begin(); it !=
+ makefile->GetTargets().end(); ++it)
+ {
+ usedTargets[i].push_back(&it->second);
+ }
+ }
+
+ // calculate closure on library dependencies
+ // let's get the top generator; we need it to find
+ // targets anywhere in the tree if we're in a subdirectory
+ cmLocalGenerator *topGenerator = generators[0];
+ while(topGenerator->GetParent() != NULL)
+ {
+ topGenerator = topGenerator->GetParent();
+ }
+ // algorithm:
+ // for each target in the "used target matrix":
+ // find all dependent targets:
+ // if any new target is found, add it to the "used target matrix"
+ // loop until no new dependencies are found
+ bool changed = false;
+ do
+ {
+ changed = false;
+ // build closure
+ unsigned int generatorSize = generators.size();
+ for(unsigned int iGenerator=0; iGenerator<generatorSize; ++iGenerator)
+ {
+ for(unsigned int iTarget=0; iTarget<usedTargets[iGenerator].size(); ++iTarget)
+ {
+ // find all targets this target depends on;
+ // use link libraries as well as utilities (for example
+ // executables that are needed for the build process)
+ std::vector<std::string> targetDependencies;
+ {
+ cmTarget::LinkLibraryVectorType::const_iterator j, jend;
+ j = usedTargets[iGenerator][iTarget]->GetLinkLibraries().begin();
+ jend = usedTargets[iGenerator][iTarget]->GetLinkLibraries().end();
+ for(;j!= jend; ++j)
+ {
+ targetDependencies.push_back(j->first);
+ }
+ }
+ {
+ std::set<cmStdString>::const_iterator j, jend;
+ j = usedTargets[iGenerator][iTarget]->GetUtilities().begin();
+ jend = usedTargets[iGenerator][iTarget]->GetUtilities().end();
+ for(;j!= jend; ++j)
+ {
+ targetDependencies.push_back(*j);
+ }
+ }
+ // for each target we depend on, check if this target is
+ // already in our "used target matrix"
+ for(unsigned int iDependency=0; iDependency<targetDependencies.size();
+ ++iDependency)
+ {
+ bool foundTarget = false;
+ for(unsigned int gen=0; gen<usedTargets.size(); ++gen)
+ {
+ for(unsigned int k=0; k<usedTargets[gen].size() &&
+ !foundTarget; ++k)
+ {
+ if(usedTargets[gen][k]->GetName() == targetDependencies[iDependency])
+ {
+ foundTarget = true;
+ }
+ }
+ }
+ // if it's not in our "used target matrix", enter it:
+ if(!foundTarget)
+ {
+ // find the target globally (as far as I understand,
+ // cmake doesn't support multiple targets with the
+ // same name in subdirectories, with the exception
+ // of some standard cmake targets (INSTALL, ZERO_CHECK ...)
+ // so FindTarget should always return one exact match;
+ cmTarget *dependency =
+ topGenerator->GetGlobalGenerator()->
+ FindTarget(NULL,targetDependencies[iDependency].c_str());
+ if(dependency)
+ {
+ // do we have to add the whole generator? Yes, since
+ // we just want to include the project files where the
+ // targets are built in our workspace
+ // but we'll only add the dependencies for the targets
+ // that depend on our main target
+ cmLocalGenerator* generator =
+ dependency->GetMakefile()->GetLocalGenerator();
+ // let's see if we already have this generator
+ // perhaps we should do string comparison, not
+ // pointer comparison?
+ int entryGenerator = -1;
+ for(unsigned int k=0; k<generators.size() &&
+ (entryGenerator == -1); ++k)
+ {
+ if(generators[k] == generator)
+ {
+ entryGenerator = k;
+ }
+ }
+ // if we don't find the generator the new target is
+ // in, we add the generator
+ if(entryGenerator == -1)
+ {
+ // we have to update the project map - if we don't
+ // the target dependencies will not be written
+ this->ProjectMap[generators[iGenerator]->
+ GetMakefile()->GetProjectName()].push_back(generator);
+ entryGenerator = generators.size();
+ generators.push_back(generator);
+ usedTargets.push_back(std::vector<cmTarget*>());
+ }
+ // we know that this is a new target, otherwise we
+ // wouldn't end here - so just add the new target
+ usedTargets[entryGenerator].push_back(dependency);
+ // run again over the new "used target matrix"
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ while(changed);
+ }
+
   // For each cmMakefile, create a VCProj for it, and
   // add it to this SLN file
   unsigned int i;
@@ -294,10 +438,17 @@
                                               const char* dir,
                                               cmTarget& t)
 {
- std::string d = cmSystemTools::ConvertToOutputPath(dir);
+ std::string d = dir;
+ d += "/";
+ d += dspname;
+ d += ".vcproj";
+ d = cmSystemTools::ConvertToOutputPath(d.c_str());
+ if(d[0] != '\"')
+ {
+ d = std::string("\"") + d + std::string("\"");
+ }
   fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \""
- << dspname << "\", \""
- << d << "\\" << dspname << ".vcproj\", \"{"
+ << dspname << "\", " << d << " ,\"{"
        << this->GetGUID(dspname) << "}\"\n";
   fout << "\tProjectSection(ProjectDependencies) = postProject\n";
   this->WriteProjectDepends(fout, dspname, dir, t);
(0006578)
Manuel Klimek   
2007-02-28 02:31   
If you need an up to date patch or to resolve some issues to get this into the main line, please let me know, I'm willing to help ...

Manuel
(0007710)
Manuel Klimek   
2007-05-22 06:38   
An additional fix for target dependency generation in subdir sln files...

Index: E:/proj/cmake/Source/cmGlobalVisualStudio71Generator.cxx
===================================================================
--- E:/proj/cmake/Source/cmGlobalVisualStudio71Generator.cxx (revision 24706)
+++ E:/proj/cmake/Source/cmGlobalVisualStudio71Generator.cxx (working copy)
@@ -188,7 +188,9 @@
                   {
                   // we have to update the project map - if we don't
                   // the target dependencies will not be written
- this->ProjectMap[generators[iGenerator]->
+ // we must use the current generator (generators[0]),
+ // since this will be used when writing the dependencies
+ this->ProjectMap[generators[0]->
                     GetMakefile()->GetProjectName()].push_back(generator);
                   entryGenerator = generators.size();
                   generators.push_back(generator);
(0008385)
Torsten Martinsen   
2007-08-09 08:48   
Attached updated patch for CMake 2.4.7.
(0010385)
Bill Hoffman   
2008-02-06 10:12   
This should be fixed in CVS CMake now. Please try, as this implementation will go in 2.6 beta.