clangd: Cannot find C++ headers when cross compiling with gcc and a --sysroot specified

I seem to be experiencing an issue very similar to #157 with clangd built from git.

My usecase is using a cross compilation toolchain created using yocto. Basically, the problem seems to be that clangd does not take the --sysroot argument into account when setting up include paths.

I have this source file:

#include <iostream>

int main(int argc, char **argv) {
  std::cout << "hello\n";
  return 0;
}

and this compile_commands.json:

[
{
  "directory": "/home/kalle/dev/lsp-clangd-debugging/build-poky",
  "command": "/home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/bin/x86_64-poky-linux/x86_64-poky-linux-g++ --sysroot=/home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux -o CMakeFiles/hello.dir/hello.cpp.o -c /home/kalle/dev/lsp-clangd-debugging/hello.cpp",
  "file": "/home/kalle/dev/lsp-clangd-debugging/hello.cpp"
}
]

Then, running clangd --check hello.cpp, I get this output:

I[22:02:34.060] clangd version 16.0.0 (git@github.com:llvm/llvm-project.git c0bc461999fdac918dd26867947c24eb6235c8d0)
I[22:02:34.060] Features: linux+debug
I[22:02:34.060] PID: 361828
I[22:02:34.060] Working directory: /home/kalle/dev/lsp-clangd-debugging
I[22:02:34.060] argv[0]: /usr/local/llvm/bin/clangd
I[22:02:34.060] argv[1]: --check=hello.cpp
I[22:02:34.061] Entering check mode (no LSP server)
I[22:02:34.061] Testing on source file /home/kalle/dev/lsp-clangd-debugging/hello.cpp
I[22:02:34.061] Loading compilation database...
I[22:02:34.062] Loaded compilation database from /home/kalle/dev/lsp-clangd-debugging/compile_commands.json
I[22:02:34.063] Compile command from CDB is: /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/bin/x86_64-poky-linux/x86_64-poky-linux-g++ --target=x86_64-poky-linux --driver-mode=g++ --sysroot=/home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux -o CMakeFiles/hello.dir/hello.cpp.o -c -resource-dir=/usr/local/llvm/lib/clang/16.0.0 -- /home/kalle/dev/lsp-clangd-debugging/hello.cpp
I[22:02:34.064] Parsing command...
I[22:02:34.066] internal (cc1) args are: -cc1 -triple x86_64-poky-linux -fsyntax-only -disable-free -clear-ast-before-backend -main-file-name hello.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -mllvm -treat-scalable-fixed-error-as-warning -debugger-tuning=gdb -fcoverage-compilation-dir=/home/kalle/dev/lsp-clangd-debugging/build-poky -resource-dir /usr/local/llvm/lib/clang/16.0.0 -isysroot /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux -internal-isystem /usr/local/llvm/lib/clang/16.0.0/include -internal-isystem /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/local/include -internal-externc-isystem /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/include -internal-externc-isystem /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/include -fdeprecated-macro -fdebug-compilation-dir=/home/kalle/dev/lsp-clangd-debugging/build-poky -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -no-round-trip-args -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -x c++ /home/kalle/dev/lsp-clangd-debugging/hello.cpp
I[22:02:34.066] Building preamble...
I[22:02:34.095] Indexing headers...
I[22:02:34.096] Built preamble of size 214292 for file /home/kalle/dev/lsp-clangd-debugging/hello.cpp version null in 0.03 seconds
E[22:02:34.097] [pp_file_not_found] Line 2: 'iostream' file not found
I[22:02:34.097] Building AST...
E[22:02:34.111] [undeclared_var_use] Line 7: use of undeclared identifier 'std'
I[22:02:34.111] Indexing AST...
I[22:02:34.111] Building inlay hints
I[22:02:34.112] Testing features at each token (may be slow in large files)
I[22:02:34.129] All checks completed, 2 errors

E.g. it does not find <iostream>. Looking at the cc1 args, it is clear that the c++ include directories are missing, as if it had missed taking the sysroot into account.

Running /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/bin/x86_64-poky-linux/x86_64-poky-linux-g++ -E -x c++ - -v < /dev/null gives:

...
ignoring nonexistent directory "/not/exist/usr/include/c++/11.2.0"
ignoring nonexistent directory "/not/exist/usr/include/c++/11.2.0/x86_64-poky-linux"
ignoring nonexistent directory "/not/exist/usr/include/c++/11.2.0/backward"
ignoring nonexistent directory "/not/exist/usr/lib/x86_64-poky-linux/11.2.0/include"
ignoring nonexistent directory "/not/exist/usr/local/include"
ignoring nonexistent directory "/home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/lib/x86_64-poky-linux/gcc/x86_64-poky-linux/11.2.0/../../../../../x86_64-poky-linux/include"
ignoring nonexistent directory "/not/exist/usr/include/"
#include "..." search starts here:
#include <...> search starts here:
 /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/lib/x86_64-poky-linux/gcc/x86_64-poky-linux/11.2.0/include
 /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/lib/x86_64-poky-linux/gcc/x86_64-poky-linux/11.2.0/include-fixed
End of search list.
...

By contrast, including the --sysroot arg – /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/bin/x86_64-poky-linux/x86_64-poky-linux-g++ --sysroot=/home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux -E -x c++ - -v < /dev/null – I instead get:

...
ignoring nonexistent directory "/home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/lib/x86_64-poky-linux/11.2.0/include"
ignoring nonexistent directory "/home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/local/include"
ignoring nonexistent directory "/home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/lib/x86_64-poky-linux/gcc/x86_64-poky-linux/11.2.0/../../../../../x86_64-poky-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/include/c++/11.2.0
 /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/include/c++/11.2.0/x86_64-poky-linux
 /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/include/c++/11.2.0/backward
 /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/lib/x86_64-poky-linux/gcc/x86_64-poky-linux/11.2.0/include
 /home/kalle/misc/poky-install-x86_64/sysroots/x86_64-pokysdk-linux/usr/lib/x86_64-poky-linux/gcc/x86_64-poky-linux/11.2.0/include-fixed
 /home/kalle/misc/poky-install-x86_64/sysroots/core2-64-poky-linux/usr/include/
End of search list.
...

System information

Output of clangd --version:

clangd version 16.0.0 (git@github.com:llvm/llvm-project.git c0bc461999fdac918dd26867947c24eb6235c8d0)
Features: linux+debug
Platform: x86_64-unknown-linux-gnu

Editor/LSP plugin: Emacs/lsp-mode but also happens with clangd --check <file>

Operating system: Linux (Arch Linux)

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 17

Commits related to this issue

Most upvoted comments

Just want to say, thank you for this post. This helped me: https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clangd/Configuration.html

Here is what my flag looks like: --query-driver=/home/talksik/Qt/6.6.1/Boot2Qt/raspberrypi4-64/toolchain/sysroots/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux-*

Yep, just confirmed that it works alright if I specify the --query-driver argument. I am closing this now.

I am facing a similar issue when using clangd with toolchain from the yocto SDK. Adding the query driver option with g++ helps in finding some of the headers e.g. the ones from the standard library.

Headers residing in the target sysroot (e.g. protobufs), however, are still not seen by clangd. The problem is, that the query driver g++ is in the native sysroot and headers are in the target sysroot.

Yocto SDK contains a CMakeToolchainFile that makes CMake builds work (g++ compiling files sees all the headers). QtCreator uses clangd to index the project and can somehow figure out where the headers are based on the files generated by CMake in the build directory.

My intuition is that the ability to pass g++ with the flag --sysroot=/path/to/target-sysroot in the query-driver parameter would solve the problem.

I don’t understand why clangd does not see the headers despite having access to compile_commands.json generated by CMake during successful build.

As a workaround you can try generating an environment script, just like the one in the SDK, but for the recipe’s sysroot. This way you will have everything in one sysroot.

Look for meta-ide-support. You will have to inherit from toolchain-scripts and use toolchain_create_tree_env_script.

https://stackoverflow.com/questions/48622241/build-system-derived-toolchain-in-yocto