ENH: Add support for exporting graphviz of the project dependencies
This commit is contained in:
parent
93c95f1cc5
commit
bc4e5581ee
|
@ -606,6 +606,11 @@ cmTarget::AnalyzeLibDependencies( const cmMakefile& mf )
|
||||||
// The dependency map.
|
// The dependency map.
|
||||||
DependencyMap dep_map;
|
DependencyMap dep_map;
|
||||||
|
|
||||||
|
if ( m_OriginalLinkLibraries.size() == 0 )
|
||||||
|
{
|
||||||
|
m_OriginalLinkLibraries = m_LinkLibraries;
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Build the dependency graph
|
// 1. Build the dependency graph
|
||||||
//
|
//
|
||||||
for(LinkLibraries::reverse_iterator lib = m_LinkLibraries.rbegin();
|
for(LinkLibraries::reverse_iterator lib = m_LinkLibraries.rbegin();
|
||||||
|
|
|
@ -95,6 +95,7 @@ public:
|
||||||
enum LinkLibraryType {GENERAL, DEBUG, OPTIMIZED};
|
enum LinkLibraryType {GENERAL, DEBUG, OPTIMIZED};
|
||||||
typedef std::vector<std::pair<std::string,LinkLibraryType> > LinkLibraries;
|
typedef std::vector<std::pair<std::string,LinkLibraryType> > LinkLibraries;
|
||||||
const LinkLibraries &GetLinkLibraries() {return m_LinkLibraries;}
|
const LinkLibraries &GetLinkLibraries() {return m_LinkLibraries;}
|
||||||
|
const LinkLibraries &GetOriginalLinkLibraries() {return m_OriginalLinkLibraries;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the dependency information recorded for this target, if any.
|
* Clear the dependency information recorded for this target, if any.
|
||||||
|
@ -321,6 +322,7 @@ private:
|
||||||
std::vector<cmSourceFile*> m_SourceFiles;
|
std::vector<cmSourceFile*> m_SourceFiles;
|
||||||
LinkLibraries m_LinkLibraries;
|
LinkLibraries m_LinkLibraries;
|
||||||
LinkLibraries m_PrevLinkedLibraries;
|
LinkLibraries m_PrevLinkedLibraries;
|
||||||
|
LinkLibraries m_OriginalLinkLibraries;
|
||||||
bool m_LinkLibrariesAnalyzed;
|
bool m_LinkLibrariesAnalyzed;
|
||||||
bool m_LinkDirectoriesComputed;
|
bool m_LinkDirectoriesComputed;
|
||||||
std::vector<std::string> m_Frameworks;
|
std::vector<std::string> m_Frameworks;
|
||||||
|
|
177
Source/cmake.cxx
177
Source/cmake.cxx
|
@ -22,6 +22,7 @@
|
||||||
#include "cmCommands.h"
|
#include "cmCommands.h"
|
||||||
#include "cmCommand.h"
|
#include "cmCommand.h"
|
||||||
#include "cmFileTimeComparison.h"
|
#include "cmFileTimeComparison.h"
|
||||||
|
#include "cmGeneratedFileStream.h"
|
||||||
|
|
||||||
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
||||||
# include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
|
# 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
|
// skip for now
|
||||||
i++;
|
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)
|
else if(arg.find("--debug-trycompile",0) == 0)
|
||||||
{
|
{
|
||||||
std::cout << "debug trycompile on\n";
|
std::cout << "debug trycompile on\n";
|
||||||
|
@ -1383,6 +1395,11 @@ int cmake::Configure()
|
||||||
{
|
{
|
||||||
this->m_CacheManager->SaveCache(this->GetHomeOutputDirectory());
|
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())
|
if(cmSystemTools::GetErrorOccuredFlag())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1980,3 +1997,163 @@ const char* cmake::GetCPackCommand()
|
||||||
return m_CPackCommand.c_str();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -311,6 +311,8 @@ protected:
|
||||||
|
|
||||||
//! Make sure all commands are what they say they are and there is no macros.
|
//! Make sure all commands are what they say they are and there is no macros.
|
||||||
void CleanupCommandsAndMacros();
|
void CleanupCommandsAndMacros();
|
||||||
|
|
||||||
|
void GenerateGraphViz(const char* fileName);
|
||||||
|
|
||||||
cmVariableWatch* m_VariableWatch;
|
cmVariableWatch* m_VariableWatch;
|
||||||
|
|
||||||
|
@ -329,6 +331,7 @@ private:
|
||||||
bool m_ClearBuildSystem;
|
bool m_ClearBuildSystem;
|
||||||
bool m_DebugTryCompile;
|
bool m_DebugTryCompile;
|
||||||
cmFileTimeComparison* m_FileComparison;
|
cmFileTimeComparison* m_FileComparison;
|
||||||
|
std::string m_GraphVizFile;
|
||||||
|
|
||||||
void UpdateConversionPathTable();
|
void UpdateConversionPathTable();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue