support commands in settings
For proper CMake support we would need "clangd.arguments": [ "--compile-commands-dir=${command:cmake.launchTargetDirectory}" ].
https://github.com/microsoft/vscode-cmake-tools/issues/654
Problem is that invoking commands is async so you can't just add this in config.ts:
const cmdPrefix = 'command:';
if (name.startsWith(cmdPrefix))
return await vscode.commands.executeCommand(name.substr(cmdPrefix.length));
Btw, looks like the relevant vscode feature request is https://github.com/microsoft/vscode/issues/46471.
The lack of this feature is still keeping the use of cmake presets with clangd or CppTools a big mess.
A workaround is to configure the compilation database in clangd own configuration file not in vscode settings and have cmake generate the .clangd file at configuration stage.
That would basically look something like this:
-
DO NOT configure the settings for
--compile-commands-dir=xxxxxin vscodesettings.json - create a .clangd.in in in your project with:
CompileFlags:
CompilationDatabase: "@CMAKE_BINARY_DIR@"
- Add this to the CmakeLists.txt
configure_file(.clangd.in ${CMAKE_SOURCE_DIR}/.clangd @ONLY)
Every time you change the cmake preset, just reconfigure and make sure to restart clangd.
This is super ugly.
NOTES
- no, it's not acceptable to have a single build directory in a project with several presets for several target platforms,
- it's not possible to reliably run any cmake action after generation is complete, for example to move the
compiler_commands.jsonfile to somewhere else. CMake people do everything they can so that we cannot do that :-)
Every time you change the cmake preset, just reconfigure and make sure to restart clangd.
regarding clangd the restart, it shouldn't be needed. Clangd should re-read both the config file and the compilation database periodically.
no, it's not acceptable to have a single build directory in a project with several presets for several target platforms,
This totally makes sense and we agree that it's the case with a multitude of projects.
All the current solutions are unfortunately equally frustrating for the end user today, they usually need to have an extra step that'll somehow update an input to clangd (e.g. change config file, update the symlink at source root, ...).
We'd rather solve this problem at the clangd side and benefit users across all editors, not just the ones on vscode && using some other extension (we only have so many human power to maintain these systems, hence we try to keep the logic in vscode plugin as minimal as possible).
The biggest problem here is there's no principled way to even figure out a project root in the absence of a compile_commands.json. We can make use of other heuristics like existence of a .git directory, rely on the workspaceRoot provided by LSP clients (which is not always there, and does not reflect the real project root most of the time) but all of these would just keep introducing more and more error factors and the final UX will just be meaningless again for most users, despite all the complexity of the implementation. Hence our negligence of the issue so far.
Also most of the maintainers work in LLVM with mostly a single build configuration hence we lack the full understanding of the workflows involved in a multi-build config environment which also interacts with build systems other than CMAKE. It would be useful for us to hear about ideas/workflows that people have so that we can assess the usefulness/feasibility of different ideas we have in mind.
he biggest problem here is there's no principled way to even figure out a project root in the absence of a compile_commands.json. We can make use of other heuristics like existence of ...
Please note that in a multi-config build environment the problem is not the project root, but rather the build output root for each config.
For example, in my case (cmake + clangd + vscode + cmake-tools), I definitely want my build to be out of source and each build config in its separate build tree (e.g. windows, linux, dev, release, valgrind, etc...).
The one responsible for generating the compilation database is cmake. CMake knows everything about the project, its source, its build output, etc...
The one that invokes cmake is cmake-tools, which knows about the CMakePresets.json which has the source dir, build, dir, preset name, and many more info about the presets. My understanding is that the whole point from this issue is to use such info through a substitution with command in vscode settings.json.
The one who uses compiler_commands.json is clangd and clangd has no idea where cmake is putting that file, and the settings in vscode are so limited that we can only (right now) hardcode a directory for clangd to look into.
So at the end of the day, imho, it's not really clangd's responsibility to figure out where cmake puts its babies. Inside vscode it's just a pity that there is no such seamless integration happening between cmake, cmake-tools, clangd and vscode.
Outside of vscode, I don't know whether there is a universal solution for this problem, but a good compromise is when clangd is working in a cmake environment and that environment has a CMakePresets.json. That presets file could be used by clangd to get a lot of info. That's exactly how Visual Studio for example integrates cmake now...
To conclude, I really appreciate what you guys are doing and it's just so great to have clangd in vscode that I wanted it to be not just great, but perfect :-)
push: having a support for things like --compile-commands-dir=${command:cmake.buildDirectory} would make the usage easier.
push: having a support for things like
--compile-commands-dir=${command:cmake.buildDirectory}would make the usage easier.
@Febbe, see https://github.com/clangd/vscode-clangd/issues/218#issuecomment-898869786 or https://github.com/clangd/vscode-clangd/issues/349#issuecomment-1158602331 for a workaround for this particular use case.
Do developers think about to implement ${command:...} substitution? "cmake.copyCompileCommands" alternative works but having to use it is still uncomfortable.