Skip to content
Published at:

源码阅读-嵌套宏

在源码阅读的时候,有个非常讨厌的家伙---多层嵌套宏,简单的宏还 OK,有些多则嵌套个四五层,看代码时直接血压飙升。

后来一想,编译器的预处理器不就是在预处理阶段把宏展开嘛?命令示例:

bash
$ cc -E main.c > main.i

但实际上多层嵌套的宏一般会出现在大型项目里面,而不是像上面一个的单个文件当中。那问题就转变成了:怎么在编译时保留这个预处理阶段的产生的中间临时文件?或是怎么生成这样的目标文件?这里选后者-去生成目标文件,拿 CMake 的项目来举例:

bash
# 配置、编译
$ cmake -S . -B build
$ cmake --build build -j
...

# 重点:查找对应的target 目标
$ cmake --build build/lvgl --target help | grep lv_gc.i
... src/misc/lv_gc.i

# 生成对应的目标文件
$ cmake --build build/lvgl --target src/misc/lv_gc.i
cd /Users/shibin/repo/lv_sim_vscode_sdl_8/build && /Library/Developer/CommandLineTools/usr/bin/make  -f lvgl/CMakeFiles/lvgl.dir/build.make lvgl/CMakeFiles/lvgl.dir/src/misc/lv_gc.c.i
Preprocessing C source to CMakeFiles/lvgl.dir/src/misc/lv_gc.c.i
cd /Users/shibin/repo/lv_sim_vscode_sdl_8/build/lvgl && /Library/Developer/CommandLineTools/usr/bin/cc -DLV_CONF_INCLUDE_SIMPLE -DLV_LVGL_H_INCLUDE_SIMPLE -I/Users/shibin/repo/lv_sim_vscode_sdl_8 -I/opt/homebrew/Cellar/sdl2/2.26.1/include -isystem /Users/shibin/repo/lv_sim_vscode_sdl_8/lvgl -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=float-cast-overflow -fsanitize-address-use-after-scope -fno-sanitize-recover -g -arch arm64 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk -E /Users/shibin/repo/lv_sim_vscode_sdl_8/lvgl/src/misc/lv_gc.c > CMakeFiles/lvgl.dir/src/misc/lv_gc.c.i

$ find . -name lv_gc.c.i
./build/lvgl/CMakeFiles/lvgl.dir/src/misc/lv_gc.c.i

$ code ./build/lvgl/CMakeFiles/lvgl.dir/src/misc/lv_gc.c.i

CMake项目默认会生成 Makefile 的构建脚本,然后调用 make 去编译项目,多层嵌套的 CMakeLists.txt 项目就会生成多层嵌套的 Makefile 脚本文件。上述前面两个命令不用多解释,是 CMake 的配置和编译,编译缓存会生成在 build 目录下,build 目录下有对应的 Makefile 文件;重点是第三四条命令 :

  • cmake --build build/lvgl --target help :显示build/lvgl下面的 Makefile 里面有哪些目标;这里由于我的是多层CMake 项目,所以我去build/lvgl/Makefile里面去查找
  • grep lv_gc.i :过滤查找 我要展开宏的源代码文件;如果文件名是xxx.c,对应搜索xxx.i
  • cmake --build build/lvgl --target src/misc/lv_gc.i:来去生成对应的 target 目标,就是对应源代码进行预处理的目标

最后可能需要find搜索查找下,多层嵌套的 CMakeLists.txt 项目目录相对复杂点,使用搜索稳妥些。最后打开文件,代码格式化一下,立马清晰了,截图如下:生成的文件还会有源文件的行号注释(指示什么文件的多少行代码如下)

那如果要展开的宏在头文件中,而不是在c文件中呢?把这个头文件包含include到另一个c源文件中,然后去生成这个 c文件的目标文件。

Updated at: