Generating compile_commands.json : use -MJ or not?

I see that clang has a command line argument, -MJ, that tells it to write a file that can be one entry in the compile_commands.json, which is used by clangd. But, it seems you need to give clang a real compile command along with the -MJ. This confuses me, since ideally you want to gather up these JSON snippets before anything is built. My text editor (using clangd) should work without having to build everything first.

Is there a common way to use -MJ without actually building anything? So I could iterate over all my source files doing a kind of fake build, just to generate the JSON? Or, should I just write the JSON directly without clang? I was going to do the latter, but I notice that -MJ puts some stuff in the JSON that I did not put on the command line; it’s not just a simple echo of all the arguments I gave to clang (or clang++ in my case).

What build system are you using? You can tell CMAKE to generate compile_commands.json for you by specifying -DCMAKE_EXPORT_COMPILE_COMMANDS (CMAKE_EXPORT_COMPILE_COMMANDS — CMake 3.26.3 Documentation) if you’re using either the ninja or makefile generators.

I can’t remember if simply reconfiguring CMAKE with this command is enough to get it to produce the file. If not, you could do a dry-run build, e.g. if you’re using ninja with CMAKE you could reconfigure then run ninja -n.

Does that help at all? I don’t have any experience generating commpile_comands.json without using that CMAKE option.

1 Like

This is the first time I’ve come across -MJ; I’m not aware of a flag that gets clang to just write the CDB entry without compiling (but it’s possible one exists).

Generally, the compile_commands.json file is created by the build system. If you’re writing your own build system, I would suggest having the build system write the JSON itself. If you’re using an existing build system, have a look at whether it already supports writing a CDB as CMake does.

I gave it a quick try, and I see that the things it adds are -x, --target, and --driver-mode. I don’t think these are essential, clangd should be able to figure out and add them itself.

-MJ only gives you fragments. You have to merge them to get a real json file, see sed.
It kinda defeats the purpose to make one run with -fsyntax-only to get the json file and then do a real build.

I was using CMake, but last few days I’ve been experimenting with creating my own build system in Python.

It’s now generating the compile_commands.json from the Python code, without using -MJ, and it seems to be working. So as HighCommander4 said, it appears the things added by -MJ are not essential to clangd.