#graph #header-file #cc #dot #group #generate #visualize

bin+lib include-graph

生成 c/c++ 包含依赖的 dot 图描述

15 个稳定版本

1.2.2 2024 年 3 月 18 日
1.1.1 2024 年 3 月 2 日
1.0.8 2024 年 2 月 28 日

#38可视化

自定义许可协议

1MB
2.5K SLoC

包含依赖查看器

此程序为 c/c++ 的包含头文件生成 dot 图描述。

目的是可视化文件之间的依赖关系。

功能

  • 选择要解析的文件
  • 定义如何分组查看的文件
  • 使用 编译数据库 文件以确定导入。这些文件可以由 gn/cmake/其他工具生成。
  • 使用 gn 自动分组头文件

示例

以下是一个复杂的包含图示例

Include dependencies

以下是一个复杂的放大后的依赖组示例

Include dependencies

构建

这是一个标准的 Rust 二进制文件

  • cargo build --release 将在 target/release/include-graph 生成输出
  • cargo run -- <args-here> 可用于就地运行(并调试)
  • cargo testcargo nextest run 将执行一些集成单元测试(提高测试覆盖率仍在进行中)

使用方法

# Simple run using a configuration database
# if no `output` is provided, the output will go to standard out
include-graph -c configfile.txt -o outfile.dot

# You should generate the graph using graphviz/dot
# For example for the above `outfile.dot`:
dot -T svg -o outfile.svg outfile.dot

# If you install watchexec, you can setup a pipeline like:
watchexec -e txt -- "include-graph -c cfg.txt -o out.dot && dot -Tsvg -o out.svg out.dot"

配置文件格式

以下是一个带有注释的示例配置文件

# Comments start with `#` and last to the end of the line

# Variables are declared first and you can nest variables
# Expansion is specifically `${name}` (this is not shell, so `$name` will not work)
SOURCE_ROOT=/some/path/to/source
OUTPUT_ROOT=${SOURCE_ROOT}/build/out

# The input section describes what files are to be parsed.
#   - what include path  should be searched for `#include "foo.h"`
#   - what files to be parsed using glob rules
input {
    # You may include a compile_commands database which will parse
    # includes (find `-I` arguments to a compiler) or sources.
    #
    # Note that compildb may not include all sources in a directory
    # in which case you should use GLOB for full coverage
    from compiledb ${OUTPUT_ROOT}/compile_commands.json load include_dirs
    from compiledb ${OUTPUT_ROOT}/other_compile_commands.json load sources
    from compiledb ${OUTPUT_ROOT}/third.json load sources, include_dirs
    
    # You may also manually include single directories
    include_dir ${SOURCE_ROOT}/includes/test
    include_dir /third/party/lib

    # Globs are generally including all files. program filters
    # out based on extensions (h, hpp, c, cpp, cxx, cc)
    glob ${SOURCE_ROOT}/src/lib1/**/*
    glob ${SOURCE_ROOT}/src/lib2/**/*
}

# The graph section defines how to setup the graph.
graph {
   # The tool works with absolute paths when parsing includes
   # the `map` section describes how to shorten typically long
   # absolute paths like `/home/user/devel/some/path/....`
   map {
      # Replace some long poath with a short prefix
      ${SOURCE_ROOT}/src/lib1 => first::
      ${SOURCE_ROOT}/src/lib2 => second::

      # This defines what items to actually keep in the output. Not
      # all includes are kept as they would be generally too large.
      #
      # Only prefix-paths are used here
      keep first::
      keep second::

      # Explicitly remove some of the kept items
      drop first::tests/
      drop second::support/library
   }

   # The group section defines how the graph should place
   # things together for easy dependency view.
   # Group logic:
   #   - they must be in order of application
   #   - first group wins (a file belongs to one group only)
   group {
      # This loads build targets from GN:
      #  - compile_root is where the `gn` too will be pointed to
      #  - target defines what GN target to grab `sources` from
      #  - sources will translate gn paths of `//foo` into absolute
      #    system paths
      gn root ${OUTPUT_ROOT} target //src/app/* sources ${SOURCE_ROOT}

      # Groups can be manually defined to group some files
      manual group-name-here {
         # Grouping is done by mapped names
         first::platform/Header.h
         first::platform/Src.cpp
         first::Something.cc
       }

      # Manual groups may have an optional color
      manual group-name-here color lightblue {
        # Grouping is done by mapped names
        first::some/other_header.h
      }
      
      # Optional instructions to ensure headers and sources
      # are grouped together (as they are generally included in
      # the same compilation unit)
      group_source_header
   }

   # you can optionally provide instructions for edge coloring
   color edges {
     from some_group_name red

     # color may be prefixed with "bold" for a bold edge coloring
     to other_group_name bold blue
   }

   # If zoom is non-empty it generates a separate area
   # with the specified "groups" expanded and viewing individual
   # members and dependencies
   zoom {
     # The zoom takes the group name argument, which could
     # be the GN group name or the manual group name
     //src/library:support
     group-name-here
     
     # Focus prefix means to focus on determining dependencies
     # in and out of the specified group(s).
     #
     # Dependences from other zoomed items will only be show
     # if internal or they start/end in a focused zoo group
     focus: //src/library:foo
     focus: //src/something/else:else
   }
}

调试日志

程序使用 env_logger 进行日志配置。

您可以将 RUST_LOG 环境变量设置为控制更多详细日志。请注意,它可能非常详细。

包含处理

使用 RUST_LOG=include-extract=info 打印所有解析的包含信息

使用 RUST_LOG=full-file-list=info 打印通过 glob 查找源文件找到的所有文件

使用 RUST_LOG=gn-path=info 来打印出由glob模式匹配到的所有源文件。

使用 RUST_LOG=compile-db=info 来打印出从编译数据库中解析的信息。使用 RUST_LOG=compile-db=debug 来调试编译数据库的解析。

发布

通过 cargo-smart-release 来使用,首先通过 cargo install cargo-smart-release 安装,然后执行 cargo smart-release

使用 cargo smart-release -h 来查看智能发布的标志。

依赖项

~18–30MB
~440K SLoC