Running clangd --check=my_file.cu I get something along these lines (simplified):
I[13:05:09.356] Testing on source file /path/to/my_file.cu
I[13:05:09.362] Loading compilation database...
I[13:05:09.363] Loaded compilation database from /path/to/build/compile_commands.json
I[13:05:09.364] Compile command from CDB is: /path/to/bin/nvcc [...] -isystem=/path/to/lib/include [...] -- /path/to/my_file.cu
[...]
I[13:05:09.364] Parsing command...
I[13:05:09.371] internal (cc1) args are: -cc1 [...] -isystem =/path/to/lib/include [...] -x cuda /path/to/my_file.cu
Crucially, there is a difference between the command in the compilation database and the parsed internal command. Namely, -isystem=/path/to/lib/include becomes -isystem =/path/to/lib/include (with a space). It appears clangd is not properly parsing the = syntax for the system includes.
Clangd is then unable to find the includes for libs installed system-wide unless I manually add -I /path/to/lib/include with the clangd config file.
The form -isystem=/path/to/lib/include is being generated by CMake in the compile commands, and works fine when compiling with NVCC/GCC. However, clangd appears to be misreading this as the path =/path/to/lib/include rather than /path/to/lib/include.
This is with C++/CUDA libraries, but I don't think that is the root cause.
Is there some way to get clangd to properly parse the -isystem flags generated by CMake for NVCC? Is this a bug, or is it consistent with clang's expected behaviour?
Minimum reproducible example
# CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(demo LANGUAGES CUDA CXX)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Download GoogleTest
include(FetchContent)
message(STATUS "> Downloading dependency: GoogleTest")
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
FetchContent_MakeAvailable(googletest)
message(STATUS "> Downloading dependency: GoogleTest - done")
# Build demo executable
add_executable(demo demo.cu)
target_link_libraries(demo GTest::gtest_main)
// demo.cu
#include <iostream>
int main() { std::cout << "Hello world" << std::endl; }
When configuring with cmake -B build ., we get the following compile DB:
[
{
"directory": "/home/sbone/repos/cmake_mvp/build",
"command": "/path/to/bin/nvcc -forward-unknown-to-host-compiler -isystem=/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/include -isystem=/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest --generate-code=arch=compute_52,code=[compute_52,sm_52] -std=c++17 -x cu -c /home/sbone/repos/cmake_mvp/demo.cu -o CMakeFiles/demo.dir/demo.cu.o",
"file": "/home/sbone/repos/cmake_mvp/demo.cu"
},
{
"directory": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-build/googlemock",
"command": "/local/scratch/sbone/mambaforge/envs/cudaj_devel/bin/x86_64-conda-linux-gnu-c++ -I/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock/include -I/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/include -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest -fvisibility-inlines-hidden -fmessage-length=0 -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -pipe -isystem /local/scratch/sbone/mambaforge/envs/cudaj_devel/include -Wall -Wshadow -Wundef -Wno-error=dangling-else -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -o CMakeFiles/gmock.dir/src/gmock-all.cc.o -c /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock/src/gmock-all.cc",
"file": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock/src/gmock-all.cc"
},
{
"directory": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-build/googlemock",
"command": "/local/scratch/sbone/mambaforge/envs/cudaj_devel/bin/x86_64-conda-linux-gnu-c++ -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock/include -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/include -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest -fvisibility-inlines-hidden -fmessage-length=0 -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -pipe -isystem /local/scratch/sbone/mambaforge/envs/cudaj_devel/include -Wall -Wshadow -Wundef -Wno-error=dangling-else -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -o CMakeFiles/gmock_main.dir/src/gmock_main.cc.o -c /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock/src/gmock_main.cc",
"file": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googlemock/src/gmock_main.cc"
},
{
"directory": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-build/googletest",
"command": "/local/scratch/sbone/mambaforge/envs/cudaj_devel/bin/x86_64-conda-linux-gnu-c++ -I/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/include -I/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest -fvisibility-inlines-hidden -fmessage-length=0 -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -pipe -isystem /local/scratch/sbone/mambaforge/envs/cudaj_devel/include -Wall -Wshadow -Wundef -Wno-error=dangling-else -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -o CMakeFiles/gtest.dir/src/gtest-all.cc.o -c /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/src/gtest-all.cc",
"file": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/src/gtest-all.cc"
},
{
"directory": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-build/googletest",
"command": "/local/scratch/sbone/mambaforge/envs/cudaj_devel/bin/x86_64-conda-linux-gnu-c++ -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/include -isystem /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest -fvisibility-inlines-hidden -fmessage-length=0 -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O2 -ffunction-sections -pipe -isystem /local/scratch/sbone/mambaforge/envs/cudaj_devel/include -Wall -Wshadow -Wundef -Wno-error=dangling-else -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -o CMakeFiles/gtest_main.dir/src/gtest_main.cc.o -c /home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/src/gtest_main.cc",
"file": "/home/sbone/repos/cmake_mvp/build/_deps/googletest-src/googletest/src/gtest_main.cc"
}
]
As you can see, the CUDA code has the system includes specified with -isystem=....
Note: this is with CMake 3.24.3 and NVCC cuda_12.2.r12.2/compiler.33191640_0.
Clang indeed does not accept the
-isystem=format of the flag. (You can see this from the way the option is defined in the clang source. Flags which accept=, like--sysroot, have a _EQ form, and-isystemdoes not.)So, if
nvccaccepts-isystem=, then this looks like a subtle inconsistency between the command-line argument syntax ofclangandnvcc. (Possibly unintentional; assumingnvccis the one trying to be compatible withclanghere, this could be worth filing annvccissue about so its developers are aware.)Clangd uses the clang driver to process the commands in
compile_commands.json, so it accepts whatever clang accepts.Assuming
nvccindeed accepts-isystem=, CMake generating annvcccommand using-isystem=is not a CMake bug per se... but ifnvccalso accepts-isystemwith no equals, maybe it would be better for CMake to use the more portable form of the flag? (Could be worth a CMake issue.)For the time being, I think your options are:
Somehow get CMake to generate a command using the
-isystemform. I'm not familiar enough with CMake to make a concrete suggestion, but perhaps you can get it to generate aclangcommand rather than annvcccommand? (You don't have to actually run theclangcommand during the build.)or
Adjust the compile command using the clangd config file. You can remove the incorrect form of the flag and add the correct one using
CompileFlags:.