diff options
Diffstat (limited to 'Source/cmGraphVizWriter.cxx')
-rw-r--r-- | Source/cmGraphVizWriter.cxx | 116 |
1 files changed, 110 insertions, 6 deletions
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index 0fcda4e..c23156d 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -67,6 +67,36 @@ const char* getShapeForTarget(const cmLinkItem& item) return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN; } } + +struct DependeesDir +{ + template <typename T> + static const cmLinkItem& src(const T& con) + { + return con.src; + } + + template <typename T> + static const cmLinkItem& dst(const T& con) + { + return con.dst; + } +}; + +struct DependersDir +{ + template <typename T> + static const cmLinkItem& src(const T& con) + { + return con.dst; + } + + template <typename T> + static const cmLinkItem& dst(const T& con) + { + return con.src; + } +}; } cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName, @@ -173,18 +203,16 @@ void cmGraphVizWriter::VisitLink(cmLinkItem const& depender, return; } + // write global data directly this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType); if (this->GeneratePerTarget) { - auto fileStream = PerTargetFileStreams[depender.AsStr()].get(); - this->WriteNode(*fileStream, dependee); - this->WriteConnection(*fileStream, depender, dependee, scopeType); + PerTargetConnections[depender].emplace_back(depender, dependee, scopeType); } if (this->GenerateDependers) { - auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get(); - this->WriteNode(*fileStream, depender); - this->WriteConnection(*fileStream, depender, dependee, scopeType); + TargetDependersConnections[dependee].emplace_back(dependee, depender, + scopeType); } } @@ -288,10 +316,86 @@ void cmGraphVizWriter::Write() } } + // write global data and collect all connection data for per target graphs for (auto const gt : sortedGeneratorTargets) { auto item = cmLinkItem(gt, false, gt->GetBacktrace()); this->VisitItem(item); } + + if (this->GeneratePerTarget) { + WritePerTargetConnections<DependeesDir>(PerTargetConnections, + PerTargetFileStreams); + } + + if (this->GenerateDependers) { + WritePerTargetConnections<DependersDir>(TargetDependersConnections, + TargetDependersFileStreams); + } +} + +void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, + const cmLinkItem& rootItem, + Connections& extendedCons, + std::set<cmLinkItem>& visitedItems) +{ + // some "targets" are not in map, e.g. linker flags as -lm or + // targets without dependency. + // in both cases we are finished with traversing the graph + if (connectionMap.find(rootItem) == connectionMap.cend()) { + return; + } + + const Connections& origCons = connectionMap.at(rootItem); + + for (const Connection& con : origCons) { + extendedCons.emplace_back(con); + const cmLinkItem& dstItem = con.dst; + bool const visited = visitedItems.find(dstItem) != visitedItems.cend(); + if (!visited) { + visitedItems.insert(dstItem); + FindAllConnections(connectionMap, dstItem, extendedCons, visitedItems); + } + } +} + +void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, + const cmLinkItem& rootItem, + Connections& extendedCons) +{ + std::set<cmLinkItem> visitedItems = { rootItem }; + FindAllConnections(connectionMap, rootItem, extendedCons, visitedItems); +} + +template <typename DirFunc> +void cmGraphVizWriter::WritePerTargetConnections( + const ConnectionsMap& connections, const FileStreamMap& streams) +{ + // the per target connections must be extended by indirect dependencies + ConnectionsMap extendedConnections; + for (auto const& conPerTarget : connections) { + const cmLinkItem& rootItem = conPerTarget.first; + Connections& extendedCons = extendedConnections[conPerTarget.first]; + FindAllConnections(connections, rootItem, extendedCons); + } + + for (auto const& conPerTarget : extendedConnections) { + const cmLinkItem& rootItem = conPerTarget.first; + + // some of the nodes are excluded completely and are not written + if (this->ItemExcluded(rootItem)) { + continue; + } + + const Connections& cons = conPerTarget.second; + auto fileStream = streams.at(rootItem.AsStr()).get(); + + for (const Connection& con : cons) { + const cmLinkItem& src = DirFunc::src(con); + const cmLinkItem& dst = DirFunc::dst(con); + this->WriteNode(*fileStream, con.dst); + this->WriteConnection(*fileStream, src, dst, con.scopeType); + } + } } void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs, |