Skip to main content
  1. Posts/

JSON Compilation Database with non-cmake projects

·362 words·2 mins· loading · loading ·
Rafael Sadowski
Author
Rafael Sadowski
Shut up and hack

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.

  1. Dependencies
$ doas pkg_add clang-tools-extra # for clangd our LSP
$ doas pkg_add bear
  1. 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.

  1. 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