背景
最近一直使用VSCode来读代码和写代码,包括一些小的C项目和C++项目,用起来很顺手。
随着项目逐渐深入,我需要更有效率的在各种大型代码库中进行定义跳转及引用查找,并且需要精确的根据项目配置选择宏定义,另外就是在修改代码时对于使用到的数据结构进行代码提示。这里面包含了大量的使用到了GNU Make
系列组织的项目以及Google系列的用ninja
编译工具的项目。针对这两种项目,现在使用VSCode不能满足跨文件的智能感知,这个问题是否能解决呢。
历史
先回顾一下历史,之前智能感知是如何实现的
VS项目 & CMake项目: 风生水起
针对工作中自己写的代码,基本都是使用CLion来创建简单的CMake项目,然后在项目中可以简单的查找代码引用,定义跳转及自动实现代码提示。与此类似的还有使用Visual Studio读项目。
非IDE支持型项目: 刀耕火种
但是针对非IDE支持的项目,就比较费劲了。曾经为了修一个boringssl
库和ReactNative
共用导致boringssl
中jemalloc
的弱符号被ReactNative
中的空实现强符号所覆盖导致执行崩溃的问题,一直追踪使用Makefile的boringssl
库,当时尽管用了Understand
这类的工具,但是遍地的结构体中的函数指针以及难以查看的定义以及引用,大大增加了理解和排查难度。
后来因工作需要理解并修改Electron
的Webrtc
部分音频同步代码,当时完全是用Google的在线代码阅读工具,一边根据代码库中的文件名猜测代码可能在的范围,一遍进去找到关键词,再使用全局搜索工具找定义和引用,虽然麻烦但是也能顺利理解和阅读代码。
非IDE支持型项目: 局部优化
在要修改ffmpeg的movenc
和flvdec
的代码时,我开始使用VSCode的自带C/C++插件,基本能做到大部分能做到当前文件内跳转。虽然跨文件基本不能用,但通过项目内文本搜索也能实现,已经相对很方便了。因为ffmpeg的结构比较合理,理解流程后所有修改基本都在同一个切面文件中修改即可。
搜索
通过一番搜索,发现了可以在.vscode
目录中配置一下c_cpp_properties.json
,配置好includePath即可实现所用到的头文件中库的定义跳转。还有就是可以标注上所需的宏定义,这样就能自动选择条件编译的分支。另外包含目录中所有本地的文件后,基本也可以做到跨文件跳转。样例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ "configurations": [ { "name": "Mac", "includePath": [ "${workspaceFolder}/**", "/Users/sharpbai/sources/ffmpeg-4.2.1/build/include", "/Users/sharpbai/sources/emsdk/upstream/emscripten/system/include" ], "defines": ["__EMSCRIPTEN__"], "macFrameworkPath": [ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" ], "compilerPath": "/usr/bin/clang", "cStandard": "c99", "cppStandard": "c++11", "intelliSenseMode": "clang-x64" } ], "version": 4 } |
但是这样只能解决一些小项目,如果是大项目,有大量的依赖和文件,我不太可能一条一条全把定义等标注下来,有什么好办法么?
经过一番搜索后还真有所发现。VSCode提供了另一种机制,也就是可以将所有编译的命令导出成json, 并指定到c_cpp_properties.json
中即可实现更智能的感知功能。而且经过搜索直接就发现了ninja自带导出编译命令compile_commands.json
的功能。我在Electron的项目中能执行了下面的命令
1 2 |
ninja -C out/Release -t compdb cc cxx objc objcxx > out/Release/compile_commands.json |
这样就导出了编译命令集。下一步就是导入到VSCode中。修改c_cpp_properties.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ "configurations": [ { "name": "Mac", "compileCommands": "${workspaceFolder}/src/out/Release/compile_commands.json", "includePath": [ "${workspaceFolder}/**" ], "defines": [], "macFrameworkPath": [ "/System/Library/Frameworks", "/Library/Frameworks" ], "compilerPath": "/usr/bin/clang", "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "clang-x64" } ], "version": 4 } |
接下来重新打开VSCode的workspace,发现右下角不仅有了表示使用tag进行parse的圆柱图标,也 出现了使用编译命令进行parse的火苗图标。
然后试了下引用查找和定义跳转,无比顺利~
那GNU Make
的项目是否有办法呢? 经过搜索还真有。有一个工具叫做compiledb, 用一下方式安装
1 2 |
pip install compiledb |
然后在ffmpeg的Makefile
所在目录执行以下命令
1 2 3 4 5 |
make clean compiledb make make clean make |
这样既生成了compile_commands.json
又生成了正常编译的目标文件
接下来重启了下VSCode,尝试跳转,又快又准!
到这里不得不赞叹一句:
微软,人类的希望~