现状
Linux内核由于其本身代码量庞大,其中又包含各种平台宏定义开关/配置,外加各种结构体指针的注册,这使得阅读内核代码变成一件令人头疼的事。针对这个问题目前常见的解决方案有以下几种:
- 使用简单的文本浏览工具 + grep进行代码搜索浏览,这种方法最简单,效率也最低。
- 使用source insight进行代码浏览,使用这种方法的人应该很多,但是在浏览内核代码的时候有个缺点就是内核下有多个平台的头文件、源码,如果不做排除的话在代码跳转的时候往往能找到很多个同名函数或变量的定义,还得一个一个去确认,非常麻烦。虽然可以手动排除目录但仍然比较麻烦,之前好像看到网上有大神弄了一个脚本还是插件啥的可以根据内核中编译出的.o自动排除未编译的文件,这种相对方便点,但是头文件可能还是得手动排除。另外最重要的是source insight是收费软件,后面不用我说,相信大家心里有数┐( ̄ヘ ̄)┌。
- 使用vim + ctags,这种方法就比较高大上了,比较适合大神使用,咱vim都没玩的很透的人一般用不了。
- 使用VSCode加上C++ Intellisense插件或者global插件(见文章末尾参考链接2、3、4),类似source insight,需要手动排除未编译文件减小索引范围,代码定位不准。
新的方法
本文要介绍的是使用VSCode + Remote SSH + clangd插件来阅读linux内核代码。其中VSCode作为最强大的代码开发工具之一,主要负责主体框架及界面展示。Remote SSH插件用于访问远程服务器,实现远程代码本地化访问,也具有与远程服务器shell交互的终端功能,可以替代常用的putty、xshell、securecrt之类的工具(虽然功能上略弱)。clangd插件用于代码语义分析、代码补全、跳转等。该方案克服了上面列举的几种方案的几乎各种缺点,能做到代码精准跳转、精准自动补全,其他默认一些如代码着色自动缩进之类的VSCode自带。另外最重要的是这些都是免费的!
除VSCode IDE以外,该方法的核心是clangd插件,clangd默认通过读取工程编译自动生成的compile_commands.json文件来索引其中包含的源文件和关联的头文件,因此能避免索引非编译的代码造成解析时语义混乱。下面展示一段compile_commands.json文件中的大致内容:
[
{
"arguments": [
"cc",
"-c",
"-Wp,-MD,net/netfilter/.nf_conntrack_proto_udp.o.d",
"-nostdinc",
"-isystem",
"/home/work/my-kernel/prebuilts/gcc-x64/arm-cortexa9-linux-gnueabihf-4.9.3/bin/../lib/gcc/arm-cortexa9-linux-gnueabihf/4.9.3/include",
"-I./arch/arm/include",
"-Iarch/arm/include/generated/uapi",
"-Iarch/arm/include/generated",
"-Iinclude",
"-I./arch/arm/include/uapi",
"-Iarch/arm/include/generated/uapi",
"-I./include/uapi",
"-Iinclude/generated/uapi",
"-include",
"./include/linux/kconfig.h",
"-D__KERNEL__",
"-mlittle-endian",
"-Wall",
"-Wundef",
"-Wstrict-prototypes",
"-Wno-trigraphs",
"-fno-strict-aliasing",
"-fno-common",
"-Werror-implicit-function-declaration",
"-Wno-format-security",