当然,您可以轻松地使用awk 或类似的工具从中生成一个 .dot 文件,但既然您已经在使用 C++,不妨也将它用于该任务(我做这种事情大量使用 C 和 C++ 代码来生成数据结构的点表示以便于查看。从流中获取输入而不是遍历数据结构并没有什么不同。
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <unordered_set>
// Read a complete line where a trailing \ indicates a continued line
bool readline(std::istream &in, std::string &line) {
if (std::getline(in, line)) {
while (line.back() == '\\') {
std::string continuation;
if (!std::getline(in, continuation)) {
std::cerr << "Missing continuation line!\n";
std::exit(EXIT_FAILURE);
}
line.replace(line.end() - 1, line.end(), continuation);
}
return true;
} else {
return false;
}
}
// Replace (some) characters that can't be in dot node names with underscores
std::string normalize(const std::string &name) {
std::string norm;
norm.reserve(name.size());
std::replace_copy_if(name.begin(), name.end(), std::back_inserter(norm),
[](char c){ return std::strchr("/. ", c) != nullptr; },
'_');
return norm;
}
// Define a new node if it didn't already exist in the graph.
bool define_node(std::unordered_set<std::string> &seen,
const std::string &name) {
auto res = seen.insert(name);
if (res.second) {
std::cout << normalize(name) << " [shape=box, label=\"" << name << "\"];\n";
return true;
} else {
return false;
}
}
int main() {
// Header
std::cout << "digraph dependencies {\n";
std::unordered_set<std::string> seen;
std::string line;
while (readline(std::cin, line)) {
auto colon = line.find(':');
if (colon == std::string::npos) {
std::cerr << "Malformed line! Expected format: file: dep ...\n";
return EXIT_FAILURE;
}
auto file = line.substr(0, colon);
auto nfile = normalize(file);
define_node(seen, file);
std::istringstream deps{line.substr(colon + 1)};
for (std::string depfile; deps >> depfile; ) {
define_node(seen, depfile);
// Edge
std::cout << normalize(depfile) << " -> " << nfile << ";\n";
}
}
// Footer
std::cout << "}\n";
return 0;
}
用法:
$ g++ -o gendot -O -Wall -Wextra gendot.cc
# Assuming bash/ksh for the extglob syntax to exclude gendot.cc.
# Or put it somewhere else.
$ g++ -MG -MM !(gendot).cc | ./gendot | dot -Tsvg -o dependencies.svg