使用woboq codebrowser阅读Linux源代码

说明

最近总是要看大量与内核有关的代码,虽然bootlin可以看,但是函数间的跳转需要自己手动查看确认,速度也实在是难以忍受。
而本文要介绍的woboq codebrowser 是一个 C++ 写的命令行工具,它调用 LLVM 解析任何一个 C++ 项目的所有源码,上开源工具woboq_codebrowser利用LLVM/CLang深度解析C++源码并据此建立索引,并生成html文件,这样就可以通过浏览器就行在线浏览,界面也很不错.
但是在编译Linux内核源代码需要注意一点:编译机器不能和需要编译的内核版本相差太大.我试图在ubuntu18.04(内核版本是5.0)编译2.6的内核,结果由于2.6内核需要的工具都是老版本,在ubuntu18.04上已经不提供了,导致编译非常困,最终失败.
本篇文章是以ubuntu18.04编译4.14的内核为例,来演示整个编译过程.

准备

安装woboq_codebrowser

虽然woboq_codebrowser提供了多种安装方式,但是还是建议源代码安装.在安装之前,需要先安装LLVM和GCC. 在我实际的安装测试中,需要两者的版本都是7.

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
29
30
31
32
33
34
35
36
37
38
39
40
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.4.0-1ubuntu1~18.04.1' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)

$ ls -al /usr/bin | grep llvm-config
lrwxrwxrwx 1 root root 29 Nov 22 2018 llvm-config-7 -> ../lib/llvm-7/bin/llvm-config

# 编译得到woboq_codebrowser
$ git clone https://github.com/woboq/woboq_codebrowser
$ cd woboq_codebrowser
$ cmake . -DLLVM_CONFIG_EXECUTABLE=/usr/bin/llvm-config-7 -DCMAKE_BUILD_TYPE=Release
$ make -j12

# 编译成功得到的结果如下:
$ ls -al
total 92
drwxr-xr-x 8 user user 4096 Nov 29 09:39 .
drwxr-xr-x 9 user user 4096 Nov 29 09:13 ..
-rw-r--r-- 1 user user 16363 Nov 29 09:39 CMakeCache.txt
drwxr-xr-x 4 user user 4096 Nov 29 09:41 CMakeFiles
-rw-r--r-- 1 user user 2018 Nov 29 09:39 cmake_install.cmake
-rw-r--r-- 1 user user 224 Aug 1 21:56 CMakeLists.txt
-rw-r--r-- 1 user user 465 Aug 1 21:56 CONTRIBUTING.md
drwxr-xr-x 3 user user 4096 Aug 1 21:56 data
drwxr-xr-x 3 user user 4096 Nov 29 09:41 generator
-rw-r--r-- 1 user user 91 Aug 1 21:56 .gitignore
-rw-r--r-- 1 user user 35 Aug 1 21:56 global.h
drwxr-xr-x 3 user user 4096 Nov 29 09:41 indexgenerator
-rw-r--r-- 1 user user 7951 Nov 29 09:39 Makefile
-rw-r--r-- 1 user user 9260 Aug 1 21:56 README.md
drwxr-xr-x 2 user user 4096 Aug 1 21:56 scripts
drwxr-xr-x 2 user user 4096 Aug 1 21:56 tests
-rw-r--r-- 1 user user 155 Aug 1 21:56 .travis.yml

安装Bear

woboq_codebrowser 如果需要能够解析出C++源代码,则需要能够编译得到一个compile_commands.json文件.对于通过cmake编译的程序,可以使用cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON当时得到compile_commands.json,但是对于非cmake项目而言,就可以借助于Bear生成compile_commands.json.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ git clone https://github.com/rizsotto/Bear.git
$ cmake $BEAR_SOURCE_DIR
$ make all
$ make install # to install
$ make check # to run tests
$ make package # to make packages
# 如果安装成功,出现如下界面
$ bear
usage: bear [-h] [--version] [--verbose] [--cdb <file>] [--field-output]
[--use-cc <path>] [--use-c++ <path>] [--use-fortran <path>]
[--use-only] [--include INCLUDE] [--exclude EXCLUDE] [--append]
[--libear LIBEAR]
...
bear: error: missing build command

编译

woboq codebrowser是一个C++写的命令行工具,它调用LLVM解析任何一个C++项目的所有源码,然后输出一组HTML文件以及对应的Javascript源码。随后我们可以把这组HTML文件拷贝到某个Web服务器上,就可以在浏览器里浏览C++项目的源码了。比如可以用鼠标点击任何一个symbol,即可跳转到symbol的声明或者定义所在的位置。
为了能解析源码,woboq codebrowser需要知道源码编译的步骤。这些步骤不仅列出了需要关注的源码文件,而且会真的被woboq codebrowser调用的LLVM/Clang执行,从而做宏替换(macro execution)之类的预编译工作,从而得到完备的源码。如果一个C++项目恰好是用CMake来组织的,那么恭喜你,只需要给cmake命令加一个参数,就可以得到这个“编译步骤”,并保存到一个叫compile_commands.json的文件里,方便woboq codebrowser读取。
现在对应的需要编译的linux内核源代码,我们以linux-4.14内核为例来说明编译过程.

1
$ make menuconfig

运行之后会出来一个图形界面,选择需要编译安装的内核,模块等等.可以根据自己的实际需要进行选择,在本例中我是直接选择默认配置安装.配置完成之后,运行如下的命令编译Linux内核

1
2
3
4
$ make clean
$ bear make #这个过程根据机器配置需要等待30到60min不等
$ ls -al | grep compile_commands.json
-rw-r--r-- 1 user user 67775054 Nov 29 14:30 compile_commands.json

如果最终生成一个compile_commands.json文件,则说明编译成功.
参考: Linux 内核编译步骤及配置详解

woboq_codebrowser解析代码

解析代码

根据Using the generato这个配置中的说明,

1
/path/to/codebrowser_generator -b $BUILD_DIRECTORY -a -o $OUTPUT_DIRECTORY -p codebrowser:$SOURCE_DIRECTORY:$VERSION

  • codebrowser_generator, 是编译codebrowser得到的二进制文件,位于woboq_codebrowser/generator 目录下
  • BUILD_DIRECTORY 是通过Bear编译得到的Linux的目录
  • OUTPUT_DIRECTORY 是codebrowser_generator解析BUILD_DIRECTORY输出的目录,这个目录也是之后生成的html文件的目录
  • SOURCE_DIRECTORY 一般和BUILD_DIRECTORY是同一个目录
  • VERSION 内核版本.
    在本例中,我的写法是:
    1
    $ ./codebrowser_generator -b /home/user/soft/linux/linux-4.14.156 -a -o /home/user/soft/linux/output4.14 -p codebrowser:/home/user/soft/linux/linux-4.14.156:2.14.156

生产html文件

1
$ codebrowser_generator $OUTPUT_DIRECTORY

在本例中,我的写法是:

1
$ln -s /codebrowser_generator/data /home/user/soft/linux/output4.14/data

由于生成的代码解析文件完全是html文件,所以我们可以通过Python生成一个简单的Web服务,或者防治到Nginx等Web服务器的目录下.最后的效果就是:

总结

写起来感觉非常的简单,自己踩坑踩了大半天了.希望对linux内核源代码有兴趣的同学有帮助.

参考

利用Woboq CodeBrowser工具在线浏览源代码
浏览Paddle C++源码
woboq_codebrowser
Bear
Linux 内核编译步骤及配置详解