Say we have make
files (not cmake/premake/ninja etc) for our project that do work for gcc and clang. We want to generate out from them JSON Compilation Database to feed it into clang-modernize
tool. How to do such thing? (is there any parser in clang infrastructure or some script with usage like make CC='cc_args.py gcc' CXX='cc_args.py g++'
or some other tool)?
-
7Have you looked at https://github.com/rizsotto/Bear? (Which is linked from the clang-modernize site? – Etan Reisner Jan 15 '14 at 13:53
-
1@EtanReisner: That's an answer. – Benjamin Bannier Jan 21 '14 at 12:56
-
7In my opinion, this a very interesting question. Maybe it was a mistaje to close it. Reards – lrleon Jul 19 '16 at 03:03
-
5I found a compiledb recently. It may help https://github.com/nickdiego/compiledb-generator – Eisenfrost Aug 11 '18 at 14:36
-
`Bear` is an extremely useful tool. Works cool even for Linux Kernel complicated `Makefiles`. – St.Antario Dec 13 '19 at 18:20
-
Just want to point it out that it's conceptually wrong to list cmake and ninja together. – smwikipedia Dec 18 '22 at 06:40
7 Answers
I have no personal experience with it but Bear seems to be targeted to your scenario. (It was linked from the clang-modernize site.)

- 77,877
- 8
- 106
- 148
-
2
-
I am using Bear to generate compilation database for VS Code. Though the compile db looks fine, the VS Code is still not smart enough to find symbol definition with the compile DB. It seems there's still a long way to go for the Intellisense in VS Code. After all, VS code is a folder-based tool. Not a project-based tool like Visual Studio. – smwikipedia Dec 22 '22 at 10:50
-
@smwikipedia AFAIK the database isn't used by VS Code directly but rather by an lsp-server it runs, likely `clangd`. So you should look into that. E.g. in my case I have an old large proprietary project at work with lots of targets *(like libs and executables)*. It was Makefile-based until an year ago *(when I moved it to Meson)*. So I've been using Bear + Emacs + clangd as an LSP-server, and it was always working perfectly for me, the "intellisense" in Emacs was always on point. – Hi-Angel May 06 '23 at 11:57
Make has a usually-undesired feature of emitting the compiler command lines to its standard output, but in this case you can use it with a shell (and jq) pipeline. With GNU Make on Bash:
make --always-make --dry-run \
| grep -wE 'gcc|g\+\+' \
| grep -w '\-c' \
| jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$").string[1:]}]' \
> compile_commands.json
On Windows, cmd.exe
syntax is similar:
- use
^
instead of\
for line continuation - use
"
-delimited strings only - use
"""
to escape a"
within a"
-delimited string - use
^^
to escape a^
within a"
-delimited string
However, this doesn't handle cases where the makefile recursively invokes itself (or other makefiles) in subdirectories using the -C
argument.

- 1,111
- 11
- 10
-
2Had to use `grep -E -w 'gcc|g++'` for the first grep, otherwise I had no results. For anyone using msys/cygwin replace the jq line with `| jq -nR "[inputs|{directory:\"$(cygpath -m $(pwd))\", command:., file: match(\" [^ ]+$\").string[1:]}]" \ ` – Teharez Jun 19 '20 at 09:50
-
@Teharez Thanks, updated the `grep`. With MSYS2 one might also need to use `mingw32-make` instead of `make`. – Tanz87 Jun 19 '20 at 10:59
-
This answer is really good, and if someone use clang like me, try to add gcc|g++|clang in line 2. – GGGin Aug 24 '20 at 08:18
-
@GGGin There are [many different compilers](https://en.cppreference.com/w/cpp/compiler_support) and they should not be mixed in the same build process. – Tanz87 Aug 24 '20 at 09:22
-
1
-
1
-
After this command in Wine build my `compile_commands.json` has just `[]`, and I had to do a full rebuild because Makefile just disappeared `make: *** No targets specified and no makefile found. Stop.`. `bear` from the other answer worked better for me. – Hi-Angel Sep 18 '21 at 21:41
-
Maybe someone is in my same situation. I have a macOS and Bear was generating an empty compile_commands.json
file. They acknowledge this problem in the README and suggest to use scan-build as a workaround. Unfortunately, I was still getting an empty file. Two alternative solutions I found are:

- 161
- 1
- 16
-
How to use Compiledb. I have installed it but unable to find compiledb command in that – shekhar singh May 19 '23 at 04:48
If you don't have the permission to install Bear/compiledb, or you can't build Bear from source, then a Web app could help.
I built such a simple web app at https://texttoolkit.com/compilation-database-generator, which generates compile_commands.json
from the make output.

- 660
- 7
- 15
Since I don't have enough points to react under answers yet, I wanted to comment under @Tanz87 's answer, who suggests to dry-run make
, and uses grep
and jq
to format the output.
My CMake has detected /usr/bin/c++
as the default compiler (I'm on WSL2, Ubuntu 21.10), and thus the grep -wE 'gcc|g\+\+'
command does not work, and just like @Hi-Angel, my compile_commands.json
ended up with []
.
The fix is to also grep for c++
, so the whole command becomes:
make --always-make --dry-run \
| grep -wE 'gcc|g\+\+|c\+\+' \
| grep -w '\-c' \
| jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$").string[1:]}]' \
> compile_commands.json
Edit: That being said, while the solution does seem to generate a compile_commands.json
file, running clang-tidy
in the build directory prints an error from the clang backend for every file in the compilation database:
error: no such file or directory: '&&' [clang-diagnostic-error]
Every command
entry in the compile_commands.json
file looks like this:
"cd /build/src && /usr/bin/c++ -I/src/src -std=gnu++2a -o CMakeFiles/project.dir/subdir/subsubdir/sourcefile.cpp.o -c /project/src/subdir/subsubdir/sourcefile.cpp
This project uses CMake to generate the Make build system files. Unfortunately, no solution yet.
Edit: Edit: Removing cd /build/src &&
from each command
in the compile_commands.json
fixes that particular error. Using sed
:
sed 's|cd.*.&&||g' compile_commands.json
Edit: Edit: Edit: As a oneliner, it requires some extra slashes for the &&
tokens:
make --always-make --dry-run
| grep -wE 'gcc|g\+\+|c\+\+'
| grep -w '\-c'
| sed 's|cd.*.\&\&||g'
| jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$").string[1:]}]' \
> compile_commands.json

- 111
- 2
- 4
I put together this compiler wrapper, you may want to massage the if
clause which extracts the filename argument. It only detects .c files
I invoke it like this: make ... CC="cc_wrapper $CC"
or: make ... CC="cc_wrapper gcc"
#! /bin/bash
# Writing to a common output file, so buffer for atomic output
if file=($(printf "%s\n" "$@" | grep '\.c$'))
then JSON="$(jq -nR '[inputs|{directory:$pwd, arguments:[$ARGS.positional[]], file:.}]' --arg pwd "$PWD" --args -- "$@" <<< "${file}")"
# c2rust transpile "$file.compile_commands.json" will still look for a file called compile_commands.json so we have to provide it
mkdir -p "$file.c2rs"
echo "$JSON" > "$file.c2rs/compile_commands.json"
fi
exec "$@"

- 1,265
- 12
- 24
I have found that for some make projects compiledb
is able to intercept make output and generate a valid compile_commands.json
file. However, for some projects it generates an empty compile_commands.json
file. The solution that always works for me is as below.
make clean;make VERBOSE=y all &> make_output.txt
compiledb --parse make_output.txt
This always generates a valid compile_commands.json file even for make projects where compiledb is not able to directly intercept the make output.
Hope this helps.

- 3,119
- 19
- 19
- 37

- 63
- 5