编译数据库是一个json格式,它提供了编译源文件时的命令、参数、源文件、工作目录等信息,可以基于编译数据库对C/C++代码进行分析。一般的生成文件名为compile_commands.json
。
这里包含对Compilation database — Sarcasm notebook的整理。
主流的支持基于编译数据库分析的工具有:clang-check,clang-doc,clang-include-fixer,clang-rename,clang-tidy,clangd。
如何获得项目的编译数据库
使用cmake构建项目
原来是cmake
的地方替换成cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1
。
生成的编译数据库形如:
[{ "directory": "/home/user/llvm/build", "arguments": ["/usr/bin/clang++", "-Irelative", "-DSOMEDEF=With spaces, quotes and \\-es.", "-c", "-o", "file.o", "file.cc"], "file": "file.cc" }, { "directory": "/home/user/llvm/build", "command": "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc", "file": "file2.cc" }, ]
注意到这里有arguments
和command
两种输出形式,一般认为arguments
结果要好。
使用bazel构建项目
- github.com/google/kyth… -- google出品
- github.com/hedronvisio… -- clangd推荐
- grailbio/bazel-compilation-database: Tool to generate compile_commands.json from the Bazel build system (github.com)
使用ninja构建项目
使用如下格式生成。
ninja -t compdb > compile_commands.json
使用clang编译单个文件
使用类似 clang -MJ c_struct.o.json c_struct.c -o c_struct.o
的选项生成。生成的格式形如下。注意如下几个细节:
- 生成文件的末尾的
,
,这并不是标准的json;同时缺乏通常的编译数据库生成的[]
。因此,基于这种方案生成的编译数据库文件需要手动调整(这里提供一个自动化脚本)。 arguments
中clang
的命令被替换成非软链接的绝对路径,且添加上了一些选项如-xc
,--target=x86_64-pc-linux-gnu
。这样的编译数据库,是使用了clang编译器而不是driver。- 除了
arguments
还有output
项,且/tmp/c_struct-d6903c.o
和c_struct.o
并不一样。
{ "directory": "/root", "file": "c_struct.c", "output": "/tmp/c_struct-3faa5e.o", "arguments": ["/usr/lib/llvm-14/bin/clang", "-xc", "c_struct.c", "--target=x86_64-pc-linux-gnu"]},
使用bear进行wrap
使用bear build。这个回复中提到不建议使用scan-build
中的intercept-build
。
优势
- 可以搞定任何构建命令的编译数据库生成问题。
- 生成的编译数据库使用
arguments
而不是command
,避免了转义的问题(但很多对编译数据库的分析工具可能仅支持command
项)。
不足
- 由于bear仅监控本次实际构建的命令,因此如果是项目的增量式构建则只会输出部分编译数据库结果,但全量构建可能会非常耗时。经常会出现,"全版本动辄近一个小时,很影响效率,大部分时间都浪费在等待编译结束"。
使用compiledb对make进行wrap(推荐)
compiledb有所有bear的优势,且弥补了bear的不足;性能方面也有优势。改进之处包括:
-
可以跳过时间构建而只生成
compile_commands.json
,如compiledb -n make
。 -
可以基于build-log来生成编译数据库。
make -Bnwk > build-log.txt compiledb --parse build-log.txt # 或 compiledb < build-log.txt # 使用管道的方式也行 make -Bnwk | compiledb -o-
-
使用
command
风格的编译数据库:compiledb --command-style make # 根据我的实验,在已经构建完成之后使用该命令,仍然能够得到编译数据库
不足:
- 仅能够对
make
指令进行wrap。
bash复制代码
# 可编译 > gcc testnum.c main.c # bear可wrap > bear -- gcc testnum.c main.c #compiledb不可wrap > compiledb gcc testnum.c main.c Usage: compiledb [OPTIONS] COMMAND [ARGS]... Try 'compiledb -h' for help. Error: No such command 'gcc'.
TODO:
- 补全
citnames
及intercept
命令行的使用(bear相关)。 - 补全交叉编译时的问题。
- 补全编译数据库供基于clang的分析工具时的局限性。