I am cross compiling with arm-none-eabi-g++
and I am using conan
C/C++ binary package manager together with cmake
build system.
My project consists of C, C++ and ARM assembly files. And it uses our customer's headers which are all located inside the /home/xenlauz/.conan/data
(this is a standard directory where conan
keeps binaries/libraries and header files).
My project is located elsewhere but it builds fine.
I want to make cross-referencing work inside "Neovim" so that I can "go to definition", "go to reference", "rename all symbols at once"... I know that this can be implemented by using clangd
language server (LS).
In order to achieve this, I first had to configure my /home/xenlauz/.config/nvim/init.lua
like shown below...
In "Neovim", I am using package manager "Packer" which is set up like this in order to be able to install the plugins nvim-lsp-installer
and nvim-lspconfig
:
local plugin_packer = require('packer')
plugin_packer.startup(
function()
use {
"williamboman/nvim-lsp-installer", -- LS manager.
requires = {
"neovim/nvim-lspconfig" -- LS configuration engine.
}
}
end
)
Plugin nvim-lsp-installer
is a LS manager which helps us to install and manage any kind of LS while plugin nvim-lspconfig
is a native LS configurator that makes sure "Neovim" can talk with the installed LS. This plugin needs no configuration and we shouldn't configure it at any point because nvim-lsp-installer
is used to configure the individual servers and then pass configuration to nvim-lspconfig
like this:
local plugin_lspinstaller = require("nvim-lsp-installer")
-- NOTE: Store the project directory (Neovim has to be opened in project directory)
local myroot_dir = function()
return vim.fn.getcwd()
end
plugin_lspinstaller.on_server_ready(
function(server)
-- NOTE: Create options.
local server_opts = {}
if server.name == "clangd" then
server_opts = {
cmd = {
"clangd"
},
filetypes = {
"c",
"cpp",
"objc",
"objcpp",
"cuda",
"proto"
},
root_dir = myroot_dir
}
end
-- NOTE: Pass options to the `nvim-lspconfig` to apply them.
server:setup(server_opts)
end
)
With this settings I am able to open "Neovim" and install the clangd
using a "Neovim" command :LspInstall clangd
. This installs a local copy of clangd
executable inside the /home/xenlauz/.local/share/nvim/lsp_servers/clangd/
and I can verify that it is working by running it:
~/.local/share/nvim/lsp_servers/clangd/clangd/bin/clangd --version
clangd version 15.0.6 (https://github.com/llvm/llvm-project
088f33605d8a61ff519c580a71b1dd57d16a03f8)
Features: linux+grpc
Platform: x86_64-unknown-linux-gnu
This clangd
binary automatically runs if I (a) open "Neovim" in my project's directory and then (b) open any .cpp
file.
Unfortunately clangd
does not recognize custom types defined in headers located in the /home/xenlauz/.conan/data
so, e.g. "go to definition" does not work.
I know that clangd
relies on the compile_commands.json
file which contains array of objects, where each object typically contains the following fields:
directory
(directory where compilation command command
should be executed)command
(compilation command that transforms source file
to binary)file
(source file being compiled)In my case compile_commands.json
configuration file is generated inside the project's subfodler ./build/compile_commands.json
and is generated by cmake
whose CMakeLists.txt
includes two crucial lines:
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include_directories(/home/xenlauz/.conan/data)
First line instructs cmake
to generate compile_commands.json
and second command adds -I /home/xenlauz/.conan/data
flag in every command
member inside the compile_commands.json
. I verified that this flag is really added.
This still will not make clangd
recognize headers inside the /home/xenlauz/.conan/data
. The log shows that compile_commands.json
file is found:
[ERROR][2023-03-10 09:12:26] .../vim/lsp/rpc.lua:733 "rpc" "clangd" "stderr" "I[09:12:26.581] Loaded compilation database from /mnt/c/Users/xenlauz/Documents/002--projects/003--sick--workpackage--microengine/ksz8851-test-at-f429zi/worktrees/develop/build/compile_commands.json
but there is an error regarding the .s
ARM assembly file (last line):
[ERROR][2023-03-10 09:12:27] .../vim/lsp/rpc.lua:733 "rpc" "clangd" "stderr" "E[09:12:27.426] Indexing /mnt/c/Users/xenlauz/Documents/002--projects/003--sick--workpackage--microengine/ksz8851-test-at-f429zi/worktrees/develop/src/microengine_at_nucleo_stm32F429/Device/startup_stm32f429xx.s failed: Couldn't build compiler invocation\nI[09:12:27.426] --> $/progress\n"
Note that both lines start with [ERROR]
but later in both lines we can see I[09:12:26.581]
(for info) and E[09:12:27.426]
for error. What a weird log!
I was thinking that maybe I have to configure clangd
a bit. To configure it I have two options...
A: clangd
offers a lot of parameters which I can see if I call it like this:
~/.local/share/nvim/lsp_servers/clangd/clangd/bin/clangd --help
These parameters can be included in my "Neovim" configuration file /home/xenlauz/.config/nvim/init.lua
by slightly editing clangd
configuration that I already referenced like this:
cmd = {
"clangd",
"--log=verbose"
}
Here I added a parameter that enables me a more verbose log which unfortunately I don't understand and I can not paste it here, because post size restrictions.
B: the other option is to add a .clangd
configuration file (link) in the project's main folder. I did add this configuration file and clangd
responds to the changes in this file as well. This is why I tried setting it like this:
CompileFlags:
CompilationDatabase: ./build
Add: -I/home/xenlauz/.conan/data
2nd line points clangd
to the compile_commands.json
file while 3rd line was suppose to add flag -I/home/xenlauz/.conan/data
somehow to the compile commands... Well even after this "go to definition" still does not work...
Any suggestions how to configure clangd
to work for me. It has already taken a lot of time...
After suggestion from user "HighCommander4" I tried editing the startup parameters of clangd
like this:
cmd = {
"clangd",
"--log=verbose",
"--compile-commands-dir=./build",
"--query-driver=/usr/bin/arm-none-eabi-g++,/usr/local/bin/arm-none-eabi-g++,/usr/bin/arm-none-eabi-cpp,/usr/local/bin/arm-none-eabi-cpp,arm-none-eabi-gcc,/usr/bin/arm-none-eabi-gcc,/usr/local/bin/arm-none-eabi-gcc"
},
Unfortunately error: In the included file "stdexcept" file not found
error from verbose log remains. I double checked the paths to compilers by using, e.g. whereis arm-none-.eabi-g++
. I also tried different combinations of compilers in the list but error remains. Instroction about --query-driver=
says:
clangd compilation flags options:
--compile-commands-dir=<string> - Specify a path to look for compile_commands.json. If path is invalid, clangd will look in the current directory and parent paths of each source file
--query-driver=<string> - Comma separated list of globs for white-listing gcc-compatible drivers that are safe to execute. Drivers matching any of these globs will be used to extract system includes. e.g. /usr/bin/**/clang-*,/path/to/repo/**/g++-*
After ADD1 I was getting really frustrated and decided to search for the string arm-none-eabi-b++
from within the ~/.conan/
folder. I read a bit and quickly found out that my programs are not being compiled by the system compilers, e.g. /usr/bin/arm-none-eabi-g++
but the ones from the ~/.conan/
directory:
/home/xenlauz/.conan/data/euler_toolchain_arm_rtos/1.1.0/sick/release/package/cb054d0b3e1ca595dc66bc2339d40f1f8f04ab31/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-g++
After I found this I changed my "Neovim" configuration like this:
cmd = {
"clangd",
"--log=verbose",
"--compile-commands-dir=./build",
"--query-driver=/home/xenlauz/.conan/data/euler_toolchain_arm_rtos/1.1.0/sick/release/package/cb054d0b3e1ca595dc66bc2339d40f1f8f04ab31/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-g++"
},
and it worked. The lesson I learned here is that I should use clangd
with --query-driver=
and always check the logs to find out which compiler is being used. I was a bit naive and believed that system compilers are being used.
The logs show that the file being opened (Ksz8851snlDriverTests.cpp
) contains errors:
In included file: 'cstddef' file not found"
euler/abidefs/abi.h
Unknown type name 'IBase_latest'
Too many errors emitted, stopping now
Just to confirm, do you see these errors in your editor? If not, there may be an issue with your editor configuration where it's not showing diagnostics from clangd. If you do see them, well, they're the reason why go-to-definition is not working :)
The last error in particular, Too many errors emitted, stopping now
, indicates that clangd gives up trying to build an AST for the file due to the previous errors. Without a correct AST, most clangd features including go-to-definition will not work correctly.
So, you need to start by fixing the above errors. Let's take a look at them more closely.
The first error, In included file: 'cstddef' file not found"
indicates that clangd is having trouble finding standard library headers such as <cstddef>
.
This is a somewhat common problem, addressed in this FAQ question on the clangd website.
Since you're using a cross-compiler, arm-none-eabi-g++
, the last paragraph of that section is applicable:
If you’re using an unusual compiler (e.g. a cross-compiler for a different platform) you may want to pass --query-driver=/path/to/mygcc to allow clangd to extract the include paths from it directly.
I would recommend trying --query-driver
as suggested (there are more details about its usage in clangd --help
).
The remaining errors I suspect are downstream of the <cstddef>
one, though I can't be sure. If you've fixed the <cstddef>
error and are still seeing other errors, please feel free to share a new set of logs and I can take another look.