I have long heard that Clangd is better than IntelliSense. But what does that actually mean better? It is, after all, just an opinion. I decided to check it out. In the following text, I describe how I swapped IntelliSense for Clangd and what the results were.
While working on a project on nRF with Zephyr using Visual Studio Code, we got an idea: How about swapping IntelliSense for Clangd? Is it worth a try? In theory, they offer the same thing, just in a different way. I decided to see if it was actually worth it.
We substitute IntelliSense for Clandg in the VSC on the Zephyr RTOS.
IntelliSense -> Clang
Here we go.
1) Add clangd plugin configuration to settings.json:
2) Still a project configuration file in the root directory of the project. The file must be named ".clangd" and its contents are:
3) Install the clangd plugin in your VSC:
The plugin should install clangd if it does not find it in the PATH, or in the directory specified in step 1 ("clangd.path": "/usr/bin/clangd").
4) Install the clangd plugin in your VSC:
Now enjoy autocomplete, path recognition, object information and code checking while editing.
And it's in a pretty nice form for the developer:
Troubleshooting
Here we present an example of a configuration for nRF and Zephyr processors, but with some minor adjustments, this approach will work for other cases as well.
When working with Zephyr, it's a good idea to add an additional configuration file that is global in scope. File .clangd
placed in the root directory of the project will act on all files below it in the directory structure. You can have different configurations for different directories by simply placing separate files in them .clangd
. However, once you start viewing Zephyr source files outside of your project, this configuration no longer applies. For example, when you open a file kernel.h
From the Zephyr catalog, errors may occur.
All because clangd does not understand our project's compiler arguments, and there is no ".clangd" file above the "kernel.h" file that tells it to ignore them. The global configuration file is called something else for some reason: "config.yaml". Its location depends on the operating system:
- Windows:
%LocalAppData%%clangdconfig.yaml;
- Linux:
~/.config/clangd/config.yaml;
Copy the contents of your ".clangd" file to "config.yaml" and the problem will be solved.
You can quickly access both configuration files in Visual Studio Code by pressing [CTRL+SHIFT+P] and typing "clangd: configuration."
In order for an external tool to do well in analyzing C/C++ code, it must "know" the same thing as the compiler. This means knowing how each file is compiled (with what flags, inclusions, etc.) and the "internals" of the toolchain. We provide this information by providing:
- The path to
compile_commands.json
(In parameter:--compile-commands-dir=${workspaceFolder}/build
); - Compiler/toolchain (in parameter:
--query-driver=${env:ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin/arm-zephyr-eabi-*
- thanks to the "*" clangd will choose by itself whether it should be arm-zephyr-eabi-gcc or g++);
Of course, the paths can be specified as absolute, but in the future you have to remember to update them if you change the toolchain or output directory.
You can also do the configuration of the clangd plugin through the GUI:
In the ".clangd" file, we can also suppress errors, even for individual files or groups. Example:
Of course, remember: "Don't shoot the messenger."
Important Note
In the case of our project based on NRF SDK v2.6.1, the latest clangd (v1.8.3) dropped "...arm-zephyr-eabi/12.2.0/include/" from the list of included directories. This made it impossible to find some Zephyr header files (error: In included file: 'stddef.h' file not found). So I recommend installing version e.g. 17.0.3 - in this version we did not have this problem.
What to do if something doesn't work?
1. switch the login level from --log=error
at --log=verbose
(in the clangd plugin configuration or in settings.json).
2. open some .c/.cpp file so clangd has something to analyze.
3. open the "Output" of the clangd plugin:
4. restart clangd by pressing [CTRL+SHIFT+P] and typing "clangd: restart":
5. see for a start if clangd gets the correct parameters:
Also check the paths in the log and compare those with compile_commands.json.
And that's it.
Summary.
After switching from IntelliSense to Clangd, we noticed several significant benefits:
- More effectivelanguage understanding: Clangd has a better understanding of the structure and hierarchy of the code, which allows for more precise analysis.
- Better support for hierarchies: You can more easily see the structure and dependencies in the code.
- Faster hints and automation: Clangd immediately informs you about missing inclusions or automatically adds them, which speeds up your work.
These changes have definitely streamlined our workflow and improved our coding efficiency.
Clangd has a lot of fans at GoodByte, so maybe you too will take a day or two to get familiar with it.
It's a really cool tool. Seriously.