【问题标题】:Create a .dot graph of a C++ projects dependencies from the output of gcc -MG -MM从 gcc -MG -MM 的输出创建 C++ 项目依赖项的 .dot 图
【发布时间】:2022-01-19 04:21:22
【问题描述】:

我正在尝试可视化 c++ 项目的依赖关系。我想使用标准工具:g++ 来生成依赖,sed(?) 来格式化,graphviz/dot 来输出一个 svg。

我正在使用 g++ -MG -MM *.cc 调用 g++。输出类似于:

compare.o: compare.cc compare.h types.h
config.o: config.cc config.h mute.h types.h log.h
lamp.o: lamp.cc lamp.h il_types.h
log.o: log.cc log.h FreeRTOS.h task.h mute.h string.h
login.o: login.cc login.h \
 utils/bcrypt.hpp utils/async.h
math.o: math.cc math.h types.h log.h FreeRTOS.h task.h \
  mute.h

如何将此输出转换为点图语法,以便可视化依赖关系?

【问题讨论】:

    标签: c++ c dependencies g++ graphviz


    【解决方案1】:

    当然,您可以轻松地使用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
    

    【讨论】:

      猜你喜欢
      • 2010-09-10
      • 1970-01-01
      • 1970-01-01
      • 2010-10-30
      • 2017-03-25
      • 1970-01-01
      • 2016-11-26
      • 2013-01-30
      • 2022-01-25
      相关资源
      最近更新 更多