ENH: Add support for exporting graphviz of the project dependencies

This commit is contained in:
Andy Cedilnik 2006-03-03 14:24:31 -05:00
parent 93c95f1cc5
commit bc4e5581ee
4 changed files with 187 additions and 0 deletions

View File

@ -606,6 +606,11 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
// The dependency map.
DependencyMap dep_map;
if ( m_OriginalLinkLibraries.size() == 0 )
{
m_OriginalLinkLibraries = m_LinkLibraries;
}
// 1. Build the dependency graph
//
for(LinkLibraries::reverse_iterator lib = m_LinkLibraries.rbegin();

View File

@ -95,6 +95,7 @@ public:
enum LinkLibraryType {GENERAL, DEBUG, OPTIMIZED};
typedef std::vector<std::pair<std::string,LinkLibraryType> > LinkLibraries;
const LinkLibraries &GetLinkLibraries() {return m_LinkLibraries;}
const LinkLibraries &GetOriginalLinkLibraries() {return m_OriginalLinkLibraries;}
/**
* Clear the dependency information recorded for this target, if any.
@ -321,6 +322,7 @@ private:
std::vector<cmSourceFile*> m_SourceFiles;
LinkLibraries m_LinkLibraries;
LinkLibraries m_PrevLinkedLibraries;
LinkLibraries m_OriginalLinkLibraries;
bool m_LinkLibrariesAnalyzed;
bool m_LinkDirectoriesComputed;
std::vector<std::string> m_Frameworks;

View File

@ -22,6 +22,7 @@
#include "cmCommands.h"
#include "cmCommand.h"
#include "cmFileTimeComparison.h"
#include "cmGeneratedFileStream.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
# include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
@ -398,6 +399,17 @@ void cmake::SetArgs(const std::vector<std::string>& args)
// skip for now
i++;
}
else if(arg.find("--graphviz=",0) == 0)
{
std::string path = arg.substr(strlen("--graphviz="));
path = cmSystemTools::CollapseFullPath(path.c_str());
cmSystemTools::ConvertToUnixSlashes(path);
m_GraphVizFile = path;
if ( m_GraphVizFile.empty() )
{
cmSystemTools::Error("No file specified for --graphviz");
}
}
else if(arg.find("--debug-trycompile",0) == 0)
{
std::cout << "debug trycompile on\n";
@ -1383,6 +1395,11 @@ int cmake::Configure()
{
this->m_CacheManager->SaveCache(this->GetHomeOutputDirectory());
}
if ( !m_GraphVizFile.empty() )
{
std::cout << "Generate graphviz: " << m_GraphVizFile << std::endl;
this->GenerateGraphViz(m_GraphVizFile.c_str());
}
if(cmSystemTools::GetErrorOccuredFlag())
{
return -1;
@ -1980,3 +1997,163 @@ const char* cmake::GetCPackCommand()
return m_CPackCommand.c_str();
}
void cmake::GenerateGraphViz(const char* fileName)
{
cmGeneratedFileStream str(fileName);
if ( !str )
{
return;
}
str << "digraph G {" << std::endl;
str << "node [" << std::endl;
str << " fontsize = \"12\"" << std::endl;
str << "];" << std::endl;
cmGlobalGenerator* gg = this->GetGlobalGenerator();
std::vector<cmLocalGenerator*> localGenerators;
gg->GetLocalGenerators(localGenerators);
std::vector<cmLocalGenerator*>::iterator lit;
// for target deps
// 1 - cmake target
// 2 - external target
// 0 - no deps
std::map<cmStdString, int> targetDeps;
std::map<cmStdString, cmTarget*> targetPtrs;
std::map<cmStdString, cmStdString> targetNamesNodes;
char tgtName[100];
int cnt = 0;
// First pass get the list of all cmake targets
for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
{
cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
cmTargets::iterator tit;
for ( tit = targets->begin(); tit != targets->end(); ++ tit )
{
//std::cout << "Found target: " << tit->first.c_str() << std::endl;
sprintf(tgtName, "node%d", cnt++);
targetNamesNodes[tit->first.c_str()] = tgtName;
targetPtrs[tit->first.c_str()] = &tit->second;
//str << " \"" << tgtName << "\" [ label=\"" << tit->first.c_str() << "\" shape=\"box\"];" << std::endl;
}
}
// Ok, now find all the stuff we link to that is not in cmake
for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
{
cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
cmTargets::iterator tit;
for ( tit = targets->begin(); tit != targets->end(); ++ tit )
{
const cmTarget::LinkLibraries* ll = &(tit->second.GetOriginalLinkLibraries());
cmTarget::LinkLibraries::const_iterator llit;
if ( ll->size() > 0 )
{
targetDeps[tit->first.c_str()] = 1;
}
for ( llit = ll->begin(); llit != ll->end(); ++ llit )
{
const char* libName = llit->first.c_str();
std::map<cmStdString, cmStdString>::iterator tarIt = targetNamesNodes.find(libName);
if ( tarIt == targetNamesNodes.end() )
{
sprintf(tgtName, "node%d", cnt++);
targetDeps[libName] = 2;
targetNamesNodes[libName] = tgtName;
//str << " \"" << tgtName << "\" [ label=\"" << libName << "\" shape=\"ellipse\"];" << std::endl;
}
else
{
std::map<cmStdString, int>::iterator depIt = targetDeps.find(libName);
if ( depIt == targetDeps.end() )
{
targetDeps[libName] = 1;
}
}
}
}
}
// Write out nodes
std::map<cmStdString, int>::iterator depIt;
for ( depIt = targetDeps.begin(); depIt != targetDeps.end(); ++ depIt )
{
const char* tgtName = depIt->first.c_str();
std::map<cmStdString, cmStdString>::iterator tarIt = targetNamesNodes.find(tgtName);
if ( tarIt == targetNamesNodes.end() )
{
// We should not be here.
std::cout << "Cannot find library: " << tgtName << " even though it was added in the previous pass" << std::endl;
abort();
}
str << " \"" << tarIt->second.c_str() << "\" [ label=\"" << tgtName << "\" shape=\"";
if ( depIt->second == 1 )
{
std::map<cmStdString, cmTarget*>::iterator tarTypeIt= targetPtrs.find(tgtName);
if ( tarTypeIt == targetNamesNodes.end() )
{
// We should not be here.
std::cout << "Cannot find library: " << tgtName << " even though it was added in the previous pass" << std::endl;
abort();
}
cmTarget* tg = tarTypeIt->second;
switch ( tg->GetType() )
{
case cmTarget::EXECUTABLE:
str << "house";
break;
case cmTarget::STATIC_LIBRARY:
str << "diamond";
break;
case cmTarget::SHARED_LIBRARY:
str << "polygon";
break;
case cmTarget::MODULE_LIBRARY:
str << "octagon";
break;
default:
str << "box";
}
}
else
{
str << "ellipse";
}
str << "\"];" << std::endl;
}
// Now generate the connectivity
for ( lit = localGenerators.begin(); lit != localGenerators.end(); ++ lit )
{
cmTargets* targets = &((*lit)->GetMakefile()->GetTargets());
cmTargets::iterator tit;
for ( tit = targets->begin(); tit != targets->end(); ++ tit )
{
std::map<cmStdString, int>::iterator depIt = targetDeps.find(tit->first.c_str());
if ( depIt == targetDeps.end() )
{
continue;
}
std::map<cmStdString, cmStdString>::iterator cmakeTarIt = targetNamesNodes.find(tit->first.c_str());
const cmTarget::LinkLibraries* ll = &(tit->second.GetOriginalLinkLibraries());
cmTarget::LinkLibraries::const_iterator llit;
for ( llit = ll->begin(); llit != ll->end(); ++ llit )
{
const char* libName = llit->first.c_str();
std::map<cmStdString, cmStdString>::iterator tarIt = targetNamesNodes.find(libName);
if ( tarIt == targetNamesNodes.end() )
{
// We should not be here.
std::cout << "Cannot find library: " << libName << " even though it was added in the previous pass" << std::endl;
abort();
}
str << " \"" << cmakeTarIt->second.c_str() << "\" -> \"" << tarIt->second.c_str() << "\"" << std::endl;
}
}
}
// TODO: Use dotted or something for external libraries
//str << " \"node0\":f4 -> \"node12\"[color=\"#0000ff\" style=dotted]" << std::endl;
//
str << "}" << std::endl;
}

View File

@ -311,6 +311,8 @@ protected:
//! Make sure all commands are what they say they are and there is no macros.
void CleanupCommandsAndMacros();
void GenerateGraphViz(const char* fileName);
cmVariableWatch* m_VariableWatch;
@ -329,6 +331,7 @@ private:
bool m_ClearBuildSystem;
bool m_DebugTryCompile;
cmFileTimeComparison* m_FileComparison;
std::string m_GraphVizFile;
void UpdateConversionPathTable();
};