Search code examples
language-server-protocolclangd

Include path using compile_commands.json


I have a large project with nested Makefiles which compile, primarily C++ and Obj-C files (with some MSL -- Metal Shader Language files mixed in). I have recently switched from VSCode to neovim and am trying to set up a LSP with clangd. I have everything working properly on the client side in neovim, I'm just having trouble with clangd being able to recognize include paths.

I understand that I need to have a compile_commands.json file for clangd to become away of include paths. I originally tried using bear, but for some reason it just outputted an empty json, even with running make clean before hand.

So I figured, my best bet is to write the json file myself. I don't need it to be completely accurate, I just want the LSP to be able to recognize include paths.

So here are my questions. Do I need to make a separate json entry for each translation unit? That is for each file.cpp, do I need to have a

...
{
    "directory": "...",
    "command": "...",
    "file": "..."
},
...

entry? What do I do when I create new files, will I have to make a new json entry? If I have a compile_commands.json in my root directory, do I have to tell clangd where it is? I figure that is a yes. Is there a manual way to tell clangd about include paths? I can't quite get compile_flags.txt to work either. I think that because there are so many directories in my project, that clangd doesn't quite know where compile_flags.txt is.

Are there alternatives to bear because it has not been working on my machine?


Solution

  • As I mentioned in a comment, hand-writing a CDB ("compilation database" a.k.a. compile_commands.json file) is error-prone and I don't recommend it; it's probably a better of use your time to dig into why bear (or another tool used to generate a CDB such as https://github.com/nickdiego/compiledb) is not working.

    I'll address this part of your question though because it's relevant even when generating the CDB with a tool:

    Do I need to make a separate json entry for each translation unit? [...] What do I do when I create new files, will I have to make a new json entry?

    The short answer is: for best results, yes.

    The CDB serves two purposes:

    1. Telling clangd what compile flags to use when parsing files in the project
    2. Giving clangd a list of all source files in the project so it knows what to index

    For purpose (1) it's not essential for every source file to have its own entry in the index: if clangd can't find an entry for a file, it will choose another entry and use the compile flags from that. If all the files in the project use the same compile flags, then clangd will successfully parse newly added files when you open them, even if you haven't given them their own entry in the CDB.

    However, that still leaves purpose (2): clangd will not index files which are not listed in the CDB, and so if you don't add new files to the CDB, operations that rely on the index will not work as well (for example "find references" will not find references contained in the new files).

    In most build systems, when you add a new source file, you have to add it to a build system metadata file (e.g. makefile, CMakeLists.txt etc.) anyways; when making such an edit, it's a good idea to re-generate the CDB (e.g. re-run bear) as well.