冗余头文件检查(四):构建可调试的 IWYU 开发环境
冗余头文件检查(四):构建可调试的 IWYU 开发环境
为什么需要可调试的开发环境
在后续的文章中,我们需要深入分析 IWYU 的源码结构和核心算法。为了能够高效地进行源码调试,首先需要搭建一个支持断点调试的开发环境。
一个好的 IWYU 开发环境应该具备以下特性:
- 支持 VSCode 断点调试
- 能够查看变量的实时值
- 可以方便地修改代码并重新编译
- 方便追踪 Clang AST 的构建过程
编译 Debug 版本的 IWYU
获取依赖
首先,确保系统已经安装了必要的依赖:
1
2
3
4
5
6
7
8
9
10
# Ubuntu/Debian
sudo apt-get install \
cmake \
build-essential \
clang-10 \
libclang-10-dev \
libllvm10-dev
# macOS (使用 Homebrew)
brew install llvm@10 cmake
编译 Debug 版本
普通的 CMake 编译默认是 Release 模式,为了支持调试,我们需要显式指定 Debug 模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 克隆仓库
git clone https://github.com/include-what-you-use/include-what-you-use.git
cd include-what-you-use
# 2. 创建构建目录
mkdir build-debug
cd build-debug
# 3. 配置为 Debug 模式
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang \
-DLLVM_DIR=/usr/lib/llvm-10/lib/cmake/llvm \
..
# 4. 编译
ninja -j$(nproc)
# 5. 验证编译成功
./bin/include-what-you-use --version
注意:-DLLVM_DIR 的路径可能因系统而异,需要根据实际安装位置调整。
编译优化
为了加快编译速度,可以使用 ccache:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 安装 ccache
sudo apt-get install ccache # Ubuntu/Debian
brew install ccache # macOS
# 使用 ccache 重新编译
rm -rf CMakeCache.txt
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang \
-DLLVM_DIR=/usr/lib/llvm-10/lib/cmake/llvm \
..
ninja -j$(nproc)
配置 VSCode 调试
安装必要的扩展
在 VSCode 中,安装以下扩展:
- C/C++ (ms-vscode.cpptools)
- CMake Tools (ms-vscode.cmake-tools)
创建 launch.json
在项目根目录下创建 .vscode/launch.json:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug IWYU",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build-debug/bin/include-what-you-use",
"args": [
"src/example.cpp",
"--verbose"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"setupCommands": [
{
"description": "Enable pretty-printing for lldb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build-iwyu"
}
]
}
创建 tasks.json
同时创建 .vscode/tasks.json 用于编译:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"version": "2.0.0",
"tasks": [
{
"label": "build-iwyu",
"type": "shell",
"command": "ninja",
"args": [
"-C",
"build-debug"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}
调试 IWYU 源码
设置断点
在 VSCode 中打开 IWYU 源码,设置断点的位置:
include-what-you-use/iwyu.cc- 主入口include-what-you-use/iwyu_ast_util.cc- AST 工具函数include-what-you-use/iwyu_driver.cc- 驱动逻辑
调试会话
- 在 VSCode 中按
F5启动调试 - 程序会在断点处暂停
- 使用以下快捷键进行调试操作:
F5- 继续执行F10- 单步跳过F11- 单步进入Shift+F11- 单步跳出Shift+F5- 停止调试
查看变量和表达式
在调试过程中,可以:
- 将鼠标悬停在变量上查看值
- 在 Watch 窗口添加表达式
- 在 Call Stack 窗口查看调用栈
调试 Clang AST
IWYU 依赖于 Clang 的 AST,要在 IWYU 内部查看 AST 结构,可以:
- 在 IWYU 的
iwyu_driver.cc中找到 AST 遍历的位置 - 设置断点
- 在断点处添加输出代码,例如:
1
2
3
4
5
// 在 AST 回调函数中添加
if (const auto* decl = dyn_cast<VarDecl>(d)) {
llvm::errs() << "Found variable: " << decl->getQualifiedNameAsString() << "\n";
decl->dump(); // 打印完整的 AST 节点信息
}
更为高级的 Clang AST 调试
如果需要更深入地了解 Clang AST 的结构,可以独立使用 Clang 的工具:
1
2
3
4
5
6
7
8
# 生成完整的 AST 输出
clang -Xclang -ast-dump src/example.cpp
# 生成带有位置信息的 AST
clang -Xclang -ast-dump -fno-color-diagnostics src/example.cpp
# 使用 clang-check 进行更详细的分析
clang-check -ast-dump src/example.cpp --
常见调试场景
1. 调试为什么某个头文件被建议添加
在 iwyu.cc 的 ProcessFile 函数中设置断点,查看:
SymbolInfo中记录的符号信息IncludePicker如何选择合适的头文件
2. 调试为什么某个头文件被建议移除
在 iwyu_ast_util.cc 的 MarkUsedSymbols 函数中设置断点,查看:
- 哪些符号被标记为”已使用”
- 未被使用的
#include是如何被识别的
3. 调试循环依赖检测
在 iwyu.cc 中搜索 DetectCycles 相关函数,查看 IWYU 如何构建和处理循环依赖。
快速迭代开发流程
为了提高开发效率,可以建立以下开发循环:
1
2
3
4
5
6
7
8
9
10
11
# 1. 修改源码
vim include-what-you-use/src/iwyu.cc
# 2. 编译(自动触发,如果在 VSCode 中)
# 或手动执行:
cd build-debug && ninja -j$(nproc)
# 3. 测试
./bin/include-what-you-use src/example.cpp
# 4. 如果需要调试,直接在 VSCode 中按 F5
使用 Docker 构建统一环境
为了避免本地环境差异导致的问题,可以使用 Docker 构建一个统一的开发环境(后面有介绍)。
总结
通过构建可调试的 IWYU 开发环境,我们获得了:
- 可视化调试能力:可以在 VSCode 中设置断点、查看变量值
- 快速迭代能力:Debug 模式下编译快,修改代码后可以快速重新编译测试
- 深入了解能力:可以追踪 IWYU 如何与 Clang AST 交互,理解其内部处理流程
这个环境将成为我们后续分析源码和扩展功能的基础。
本文由作者按照 CC BY 4.0 进行授权