C/C++ intellisense doesn't work correctly when compile_commands.json is located outside of program source code.
Following scenario (1) works correctly:
compile_commands.json is located inside program
workspace1:
This scenario (2) doesn't work:
compile_commands.json is located outside program (for example in {HOME} folder)
workspace2:


What I see currently is either of the two:
Neither of the problem exists when compilation database is used like in Scenario 1.
OS and Theia version:
@marechal-p @akosyakov @thegecko
If you set the verbosity level for clangd in your application, what kind of trace can you see on the backend? Usually clangd will tell you if it doesn't find a compilation database.
That is correct. As soon as I move compile_commands.json outside of program I have an inconsistent behaviour. Sometimes it can't simply find a json file and sometimes it finds it correctly but any changes to C/C++ build configuration are not respected and clangd is still using a compile_commands.json found before. It looks like the code that should restart clangd is not working correctly. @marechal-p Have you ever tested this scenario? We are interested in moving compile_commands.json outside as then it will not be included in SCM.
Have you ever tested this scenario?
Yes, as I place the compile_commands.json in my build folders, not in the source's. But I am on Linux so I don't know if this makes a difference.
On my end when I create a new invalid build config in Theia this is the output I get:
_(in this case I do have the compilation db in the sources, let me retry)_
root ERROR C/C++: I[
root ERROR C/C++: 10:54:52.436] <-- workspace/didChangeConfiguration
root ERROR C/C++: I[10:54:52.436
root ERROR C/C++: ] <-- textDocument/didOpen
I[10:54:52.437] Failed to find compilation database for /home/me/projects/easy-cpp/src/main.cpp
And when I use a valid config I don't see any errors.
I am a bit confused by your issue.
Can you try to do the same but have 2 projects and 2 compilation databases in one workspace? Try also to move compilation database completely outside of the workspace. I also do not see this issue when compile_commands.json is project or any of its children folders.
I will also try to run it on Linux to see if behaviour there is the same as the one I see on Mac and Windows.
I tried to setup a small workspace that would mimic your 2nd scenario, and everything works fine on my end. But maybe it is that the project is too simple, I don't know.
edit: Forgot to detail how to use the test project I made:
./cmake.sh, it will create compile_commands.json files into build folders under /tmp/...#include "a.h" or #include "b.h" in one of the two programs, but both cannot be recognized at the same time, because the projects are independent and clangd currently doesn't support multiple compilation databases AFAIK.@marechal-p Thank you for setting up a small example. It is much easier to discuss when we use the same example. I'm able to reproduce the same issue on my Mac using your example. I modify only the bash script slightly as readlink works differently on mac.
I have compile_commands.json located in path : /Users/arkzal01/build/theia-cpp-test/program{number}

My workspace is in: /Users/arkzal01/theia-cpp-test/
Failed to find compilation database for was displayed in logs)Current behavior:
C/C++ intellisense for program 1 (A) still works. Even though it shouldn't. Clangd is still picking compile_commands.json for Program 1 (A).
intellisense for Program1 works correctly even when C/C++ for Program2 (B) is selected:

intellisense for Program2 doesn't work even when C/C++ build config for Program2 (B) is selected:

Your example works consistently to what I've seen for more compilated programs. It looks like clangd is locked on particular compile_commands.json and changing C/C++ build config doesn't reset it.
Do not hesitate to let me know if I'm doing something wrong. I'm also setting up my environment on Linux to check if this problem exists there.
Do not hesitate to let me know if I'm doing something wrong.
So far so good :)
I'm also setting up my environment on Linux to check if this problem exists there.
I will wait on you reporting back with this, if it is platform related it could come from the way the language server is restarted? At least it would narrow things down a bit.
On the other hand, here's a few things you could try:
htop or something similar and monitor clangd's PID to see if it correctly gets restarted.Just to make sure that the correct data flows to the right places.
@marechal-p I tried to reproduce the same problem on Linux and I couldn't. It works like a charm on this platform:
platform: Ubuntu 18.04
Theia: latest master
clangd: 8.0.0
It means that this issue is platform specific and it explains why you couldn't reproduce it on Linux. I will try to debug it on my Mac based on your suggestion. I think that it may be connected with -compile-commands-dir not being passed correctly after clangd restart. In that situation clangd is by default checking current folder and its parent for compilation database. That explains why it works correctly when compile_commands.json is located together with the source.
I'll let you know if I get any more information. Do not hesitate to let me know if you have any more ideas in the meantime.
@marechal-p I'm afraid that I will need your help to solve this issue. I confirmed that issue is in Theia code.
On Linux when I change the C/C++ config correct value of compilationDatabasePath is send to the clangd server:
https://github.com/theia-ide/theia/blob/master/packages/languages/src/node/language-server-contribution.ts#L70
On my Mac however compilationDatabasePath always have the same value, no matter which C/C++ config is chosen.
What puzzles me is this is the only place I see where compilationDatabasePath is being set: https://github.com/theia-ide/theia/blob/da771757c27df6eabe8c6e5f0c2bdc69f1439b2a/packages/cpp/src/browser/cpp-language-client-contribution.ts#L85
However on both Mac and Linux this method is being called only once, during creation. Can you point me to the code that is modifying compilationDatabasePath? I also confirmed that createOptions (https://github.com/theia-ide/theia/blob/da771757c27df6eabe8c6e5f0c2bdc69f1439b2a/packages/cpp/src/browser/cpp-language-client-contribution.ts#L121) is also called only once on both Mac and Linux. Based on the comments I thought that it should be called on every change of C/C++ config.
I can also solve the issue I see by always recreating languageclient here: https://github.com/theia-ide/theia/blob/da771757c27df6eabe8c6e5f0c2bdc69f1439b2a/packages/languages/src/browser/language-client-contribution.ts#L107
However I'm pretty sure that there should be an easier way to fix this issue (it also doesnt explain why it works on Linux).
Based on the comments I thought that it should be called on every change of C/C++ config.
Yes, and for that we use filesystem watchers, maybe an issue there?
Can you point me to the code that is modifying
compilationDatabasePath?
It is a bit of chain of events, but it comes from the watchers notifying the CppBuildConfigurationManager which in turn triggers listeners such as:
And then it should restart the LS:
Again, all I can advise would be to place breakpoints at the higher point in the flow and down in order to effectively trace the chain of events and see at which point something is failing.
Your comment finally showed me the problem. This issue was fixed recently in this commit: https://github.com/theia-ide/theia/commit/da771757c27df6eabe8c6e5f0c2bdc69f1439b2a#diff-fc822bfc513331646305f42dbbe661f0 . On my Mac I was testing on version of Theia that didn't have this change. I confirm now that it works in current master on all 3 platforms. Thank you so much @marechal-p. I'm closing this issue.
Thank @simark for the fix ;)
@arekzaluski, I am wondering about your second scenario, where you have two projects, built in two different build directories, with a compile_commands.json in each build directory.
AFAIK, it is not possible with Theia and clangd today to point to both build directories: we support having a single active build configuration at the time, and each build configuration points to a single build directory. So I am wondering what your experience is with that.
There is a discussion about this use case going on clangd-dev, about how frontends (such as Theia) will communicate the configuration to clangd:
http://lists.llvm.org/pipermail/clangd-dev/2019-March/000329.html
@simark My apologies. I forgot to answer you. Both scenarios I described are using separate compile_commands.json (one per project). The only difference in scenarios is the location of those files.
That being said we are also thinking about investigating a solution to support C/C++ intellisense for all programs in the workspace without switching configurations. The solution I was thinking about is to have a single compile_commands.json for all projects in the workspace. I haven't tested it yet so I do not know how much it will affect the speed or if any changes in LSP or Theia code will be required (In theory it should be possible).
Thank you also for the link you sent me. The possibility of supporting multiple compilation databases at the same time in clangd sounds like an awesome feature that will cleanly solve this issue.
The solution I was thinking about is to have a single compile_commands.json for all projects in the workspace.
Not so bad of an idea to bridge the gap made by clangd not currently taking multiple compile dbs.
On the other hand, how would you generate such a global compile_commands.json?
I was wondering if by the nature of the format, one could just merge each program's compile commands and use that big aggregation.
But I still think that each individual programs might possess multiple ways to be built (different flags or whatnot), so the perfect system would track which configuration is set for each program, and it would auto-generate this global compile db somewhere in /tmp, pointing clangd to it.
I also think that it would be better for clangd to support multiple compile_commands.json.
But until then maybe merging each individual dbs will do the trick?
I completely agree that clangd supporting multiple compile_commands.json is a better solution to this problem. Unfortunately until it is added, a single compile_commands.json for all projects sounds like an only possible solution.
At the moment we are using our custom way of generating compile_commands.json (works only with mbed projects at the moment. It is a python script.). It gives us a lot of flexibility with generating compilation databases and is much faster than using cmake (we are running it automatically on every .h,.c,.cpp file being added/deleted/modified). It's also passing different flags per project. We are also automatically generating C/C++ configurations after project is created/imported so user doesn't need to handle it himself/herself. We also have a concept of Active project. At the moment C/C++ intellisense works only with Active project.
We however want to allow C/C++ intellisense for all projects in workspace at the same time, without switching Active project. Luckily our python script can be relatively easily changed to put output into a single compilation database file instead of multiple one's. I'll let you know about the outcome. I'm especially curious about the speed of this solution. I guess it will take clangd longer to find a correct entry in the json file.
Merging the compiling commands file should work, I believe, that would be a good way to "make things work" until clangd supports it natively. The time clangd takes to find entries in the JSON file will be dependent on the number of entries in that file. But the fact that this file comes from two other files that have been merged doesn't change anything. In any case, I wouldn't be too worried about performance of this step.
@simark @marechal-p I've tested a single compile_commands.json approach and it worked for me out of the box. No modifications in Theia code were necessary.
For tests I used 4 relatively big programs in a single workspace and I haven't noticed any drop in performance. Combined json database for 4 programs was around ~140 MB.
clangd version: official 8.0.0 release
platform: Mac OS
It will still be awesome for clangd to be able to handle multiple compile_commands.json at the same time. This however seems like a good workaround for us until it happens.