使用 Woboq CodeBrowser 搭建源代码网站
背景
在日常学习工作中,我们不免需要浏览一些库的源码。在本地浏览源代码,例如使用Source Insight
,当然是可以的,但问题是一是不方便,二是很多库下载下来是以头文件配合静态库或动态库的形式存在的,看不到cpp
代码,因此阅读会受限。现在Web
技术高速发展,有没有办法用网页直接查看源代码,并且还有类似于Code
的代码跳转功能呢?换句话说,如何把C/C++
代码转化为前端页面,并且最好是静态的前端页面,就是一个难题了。
幸运的是,github
上有人提前考虑到了这件事情,并且有了具体的项目,已经有1k
多的star
。并且原作者还基于这个框架弄出了一个在线的源代码网站,方便开发者查看各个C/C++
库的源代码,例如Qt
、GCC
、Linux Kernel
、GNU C Library
等。
那么问题来了,都有在线的网站了为什么还要自己搭建一个呢?原因就是这个网站在国内被墙了。有人会说?开梯子啊,不是每个节点都能上,我嫌他烦,因此决定自己搭建一个源代码网站一劳永逸。我的源码网站地址:https://davidingplus.github.io/code-browser/
工作原理简介
Woboq CodeBrowser
是基于LLVM/Clang
实现的一个命令行工具。它通过深度解析C/C++
源码生成最终我们需要的静态HTML
文件。Woboq CodeBrowser
包含codebrowser_generator
和codebrowser_indexgenerator
两个子命令。生成HTML
文件到最终可以通过浏览器阅读代码,整体分三个步骤:
- 先通过
codebrowser_generator
解析.h
和.cpp
生成对应的.h.html
和.cpp.html
。 - 然后通过
codebrowser_indexgenerator
为所有目录生成index.html
。 - 最后我们可以把这些
HTML
文件拷贝到某个Web
服务器上,就可以在浏览器里愉快地浏览C/C++
项目的源码了。
安装Woboq CodeBrowser工具
我们通过源码编译安装这个工具。
首先将该项目克隆到本地,由于需要用LLVM/Clang
工具链,强烈建议在Linux
下操作。
1 | git clone https://github.com/KDAB/codebrowser.git |
克隆下的项目中有三个目录比较重要,一是data
目录,这是一些前端的资源文件,例如png
、css
、js
等;二是generator
目录,这是可执行文件codebrowser_generator
的源码目录;三是indexgenerator
,这是可执行文件codebrowser_indexgenerator
的源码目录。
前面提到,编译这个工具需要用到LLVM/Clang
工具链,结合github
上的issue#119,使用llvm-14
和clang-14
的版本比较合适。以Ubuntu
为例:
1 | sudo apt install llvm-14 clang-14 libclang-14-dev |
但是在Ubuntu20.04
及以下的版本上会出现定位不到软件包的问题,官方提供了一个解决方案,参见博客https://blog.csdn.net/weixin_50749380/article/details/128319851
这样我们的编译环境就安装好了,紧接着我们需要构建这个项目并且将编译后的文件安装到本地。项目受CMake
管理,同时参考官方文档,构建流程就很简单了。
1 | mkdir -p build |
安装完毕以后data
目录,两个可执行文件codebrowser_generator
和codebrowser_indexgenerator
就成功安装到本地了。
如何使用
接下来以googletest-1.12.1
为例,展示如何使用这个工具构建静态的源代码网站。
生成compile_commands.json
compile_commands.json
文件是一种特定格式的compilation database文件,而所谓compilation database
其实很简单,它里面记录的是每一个源码文件在编译时详细的信息(包括文件路径,文件名,编译选项等等)。而compile_commands.json
文件是LibTooling需要的以json
格式呈现的compilation database
文件,以下截取的是compile_commands.json
中的一个entry
:
1 | [ |
Woboq Codebrowser
是基于LLVM/Clang
实现的工具,也是基于compile_commands.json
来分析源码关系的。
换句话说,要想使用Woboq Codebrowser
,必须首先生成compile_commands.json
文件。如果项目是由cmake
构建的,那么恭喜你,只需加上-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
即可。如果是传统的make build system
也不要担心,Bear
和compdb
工具可以帮我们生成compile_commands.json
文件。
现在让我们一起生成googletest-1.12.1
项目对应的compile_commands.json
。首先我们拉取googletest的源码到本地。源码采用CMake
工具的管理,这样正好很方便的能帮我们生成compile_commands.json
。之所以这么推荐CMake
是因为使用其他的工具可能需要编译整个工程才能生成该文件,费事费力。
因为我是C++11
标准的环境,因此需要使用的版本是1.12.1
,切换到对应的tag
。当然直接下载对应的release
源码也行。
1 | git checkout release-1.12.1 # target tag |
然后我们使用CMake
工具生成compile_commands.json
文件,个人建议使用gcc/g++
编译器。
1 | mkdir -p build |
在build
目录下看到compile_commands.json
文件正确生成即为成功。
使用codebrowser_generator生成html
codebrowser_generator
是一个可执行文件,有各种执行参数,说明如下:
-a
:处理compile_commands.json
中的所有文件。如果没有传递这个参数,那么就需要传递要处理的文件列表-o
:指定文件输出目录-b
:是指包含compile_commands.json
的构建目录。如果没有传递这个参数,编译参数可以在--
后通过命令行传递-p
:(一个或多个)用于项目规范。即项目的名称、源代码的绝对路径和用冒号分隔的版本信息。示例:-p projectname:/path/to/source/code:0.3beta
-d
:指定包含所有JavaScript
和CSS
文件的数据URL
。默认为相对于输出目录的../data
。示例:-d https://codebrowser.dev/data/
-e
:是对外部项目的引用。示例:-e clang/include/clang:/opt/llvm/include/clang/:https://codebrowser.dev/llvm
例如,对于当前googletest-1.12.1
项目,一条合适的命令可能是这样的:
1 | codebrowser_generator -b ./compile_commands.json -a -p googletest-1.12.1:"${PWD}/..":1.12.1 -o ./docs -d ../data |
执行完的结果是这样的:
需要注意的是,上面的操作都是在根目录的build
构建目录执行的,这也是CMake
用户的构建习惯。
同时,-o ./docs
代表文件输出在build/docs
中,-d ../data
是指定资源文件的相对路径,代表资源文件位于生成目录docs
的父级目录。至于为什么是../data
,后面会详细解释。安装好Woboq CodeBrowser
工具以后data
目录会被安装在/usr/local/share/woboq/data
,将其拷贝为build/data
即可。
使用codebrowser_indexgenerator为每个目录生成index.html
codebrowser_indexgenerator
同样有很多执行参数,说明如下:
-p
:(一个或多个)用于项目规范。即项目的名称、源代码的绝对路径和用冒号分隔的版本信息。示例:-p projectname:/path/to/source/code:0.3beta
-d
:指定包含所有JavaScript
和CSS
文件的数据URL
。默认为相对于输出目录的../data
。示例:-d https://codebrowser.dev/data/
同样执行类似命令:
1 | codebrowser_indexgenerator ./docs -d ../data |
类似执行结果如下,可以看到每个目录对应都有了index.html
。
关于-d参数以及资源文件
上面提到,为什么我使用的是-d ../data
呢?我们先弄清楚data
目录是干嘛的。
data
目录存放着前端代码需要的资源文件,例如CSS
、JS
和图片资源等。因此需要指明这个目录的路径,绝对路径或者相对路径。由于我的code-browser项目需要存放很多库的源代码,因此我将data
目录统一在根目录中,每个库的源代码对应一个自己的子目录,因此最终的结果是这样的:
这样就能正确定位到资源文件的路径了,codebrowser_generator
生成的html
文件同理。用户使用自己的习惯和方式即可。