The JSON Compilation Database, often know as compile_commands.json
, is a JSON
based document format for specifying how to replay single compilations
independently. This format is used in the clang project and can be easily
generated by CMake with the option -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
. Cmake
supoorts Makefile Generators and Ninja Generators.
It is essential for Language Server Protocol (LSP) implementations that need to
understand how the project is built. And this is exactly where we come to the
point. For example, if we want to use neovim or another fancy editor with
accurate code navigation, auto-completion, and diagnostics, we usually need an
LSP. No problem, clang
is quickly installed.
For all CMake C/C++ projects we have no challenge. CMake takes care of that for us. But what do we do with our non CMake projects such as the OpenBSD Source tree?
Here is a solution using Bear(1) and the OpenBSD src tree.
- Dependencies
$ doas pkg_add clang-tools-extra # for clangd our LSP
$ doas pkg_add bear
- zic(8) as an example
zic(8)
is a simple and good example as it has only one external include
dependency when building.
$ cd /usr/src/usr.sbin/zic
$ ls
Makefile zic.8 zic.c zic.d zic.o
$ make
cc -O2 -pipe -I/usr/src/usr.sbin/zic/../../lib/libc/time -Wall -Werror-implicit-function-declaration -MD -MP -c zic.c
cc -o zic zic.o
You can see, it needs a header file from lib/libc/time
.
So it is obvious that our LSP clangd does not have this information. This can also be seen in the screenshots above. You can see Neovim with LSP in connection with clang.


- Generate compile_commands.json with bear(1)
$ cd /usr/src/usr.sbin/zic
$ make clean
$ bear -- make
$ cat compile_commands.json
[
{
"arguments": [
"/usr/bin/cc",
"-O2",
"-pipe",
"-I/usr/src/usr.sbin/zic/../../lib/libc/time",
"-Wall",
"-Werror-implicit-function-declaration",
"-c",
"zic.c"
],
"directory": "/usr/rsadowski-src/usr.sbin/zic",
"file": "/usr/rsadowski-src/usr.sbin/zic/zic.c"
}
]
With the generated compile_commands.json
, our LSP knows how to build the
zic.c
and also knows that it has to set a corresponding -I
. So there are
no more warnings in our neovim editor and an auto-completion only works
correctly on all includes.
Of course, this also works for the entire OpenBSD kernel. Here is an example:
$ cd /usr/src/sys/arch/`uname -m`/conf && config GENERIC.MP
$ cd /usr/src/sys/arch/`uname -m`/compile/GENERIC.MP
$ make clean && bear -- make