1

Setup

I'm using clangd through neovim with nvim-lspconfig.

require('lspconfig').clangd.setup {
    -- on_attach = keybinds.on_attach,
    cmd = {
        "clangd",
        "--background-index",
        "--suggest-missing-includes",
        -- "--compile-commands-dir=/home/localuser/test/build",
    },
    filetypes = { "c", "cpp", "objc", "objcpp" },
}

Problem

clangd is not finding project specific includes.

What it should be doing

According to the documentation: (https://clangd.llvm.org/installation.html)

clangd will look in the parent directories of the files you edit looking for it, and also in subdirectories named build/. For example, if editing $SRC/gui/window.cpp, we search in $SRC/gui/, $SRC/gui/build/, $SRC/, $SRC/build/, …

I've built the project with cmake flag -DCMAKE_EXPORT_COMPILE_COMMANDS=1 and i have compile_commands.json in the build directory: ~/test/build/compile_commands.json

The source file I am editing is ~/test/src/main.cpp

As per the documentation, clangd should find the compilation database from the build folder, as the build folder is in a parent folder of the source file, but it does not.

What is happening

clangd gives errors on includes. I've included the full ~/.local/state/nvim/lsp.log at the end.

  • I can explicitly show clangd where the JSON is with the --compile-commands-dir flag (commented in first code block), and then it does work. However that is a system-wide configuration so I don't want to do that (and according to the documentation I shouldn't have to)
  • I can also symlink ./build/compile_commands.json to ./compile_commands.json, and then clangd works correctly.

Logs

I've created a small example. Its basically just a main() function which includes the opencv library (required in CMakeLists.txt) The project compiles just fine, but clangd complains that opencv2/opencv.hpp cannot be found.

Here's the test project directory layout:

localadmin@workstation:~/test$ tree
.
├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.16.3
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   └── tmp
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       ├── CMakeCXXCompilerId.cpp
│   │   │       └── tmp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   ├── TargetDirectories.txt
│   │   └── test.dir
│   │       ├── build.make
│   │       ├── cmake_clean.cmake
│   │       ├── CXX.includecache
│   │       ├── DependInfo.cmake
│   │       ├── depend.internal
│   │       ├── depend.make
│   │       ├── flags.make
│   │       ├── link.txt
│   │       ├── progress.make
│   │       └── src
│   │           └── main.cpp.o
│   ├── cmake_install.cmake
│   ├── compile_commands.json
│   ├── Makefile
│   └── test
├── build.sh
├── CMakeLists.txt
└── src
    └── main.cpp

And here's the full lsp.log:

[START][2022-10-24 14:16:22] LSP logging initiated
[INFO][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:662 "Starting RPC client"   { args = { "--background-index", "--suggest-missing-includes" }, cmd = "clangd", extra = { cwd = "/home/localadmin/test" }}
[TRACE][2022-10-24 14:16:22] .../lua/vim/lsp.lua:1283   "LSP[clangd]"   "initialize_params" { capabilities = { callHierarchy = { dynamicRegistration = false }, offsetEncoding = { "utf-8", "utf-16" }, textDocument = { codeAction = { codeActionLiteralSupport = { codeActionKind = { valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" } } }, dataSupport = true, dynamicRegistration = false, isPreferredSupport = true, resolveSupport = { properties = { "edit" } } }, completion = { completionItem = { commitCharactersSupport = false, deprecatedSupport = false, documentationFormat = { "markdown", "plaintext" }, preselectSupport = false, snippetSupport = false }, completionItemKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } }, contextSupport = false, dynamicRegistration = false, editsNearCursor = true }, declaration = { linkSupport = true }, definition = { linkSupport = true }, documentHighlight = { dynamicRegistration = false }, documentSymbol = { dynamicRegistration = false, hierarchicalDocumentSymbolSupport = true, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, hover = { contentFormat = { "markdown", "plaintext" }, dynamicRegistration = false }, implementation = { linkSupport = true }, publishDiagnostics = { relatedInformation = true, tagSupport = { valueSet = { 1, 2 } } }, references = { dynamicRegistration = false }, rename = { dynamicRegistration = false, prepareSupport = true }, signatureHelp = { dynamicRegistration = false, signatureInformation = { activeParameterSupport = true, documentationFormat = { "markdown", "plaintext" }, parameterInformation = { labelOffsetSupport = true } } }, synchronization = { didSave = true, dynamicRegistration = false, willSave = false, willSaveWaitUntil = false }, typeDefinition = { linkSupport = true } }, window = { showDocument = { support = false }, showMessage = { messageActionItem = { additionalPropertiesSupport = false } }, workDoneProgress = true }, workspace = { applyEdit = true, configuration = true, symbol = { dynamicRegistration = false, hierarchicalWorkspaceSymbolSupport = true, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, workspaceEdit = { resourceOperations = { "rename", "create", "delete" } }, workspaceFolders = true } }, clientInfo = { name = "Neovim", version = "0.8.0" }, initializationOptions = vim.empty_dict(), processId = 377762, rootPath = "/home/localadmin/test", rootUri = "file:///home/localadmin/test", trace = "off", workspaceFolders = { { name = "/home/localadmin/test", uri = "file:///home/localadmin/test" } }}
[DEBUG][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:285    "rpc.send"  { id = 1, jsonrpc = "2.0", method = "initialize", params = { capabilities = { callHierarchy = { dynamicRegistration = false }, offsetEncoding = { "utf-8", "utf-16" }, textDocument = { codeAction = { codeActionLiteralSupport = { codeActionKind = { valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" } } }, dataSupport = true, dynamicRegistration = false, isPreferredSupport = true, resolveSupport = { properties = { "edit" } } }, completion = { completionItem = { commitCharactersSupport = false, deprecatedSupport = false, documentationFormat = { "markdown", "plaintext" }, preselectSupport = false, snippetSupport = false }, completionItemKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } }, contextSupport = false, dynamicRegistration = false, editsNearCursor = true }, declaration = { linkSupport = true }, definition = { linkSupport = true }, documentHighlight = { dynamicRegistration = false }, documentSymbol = { dynamicRegistration = false, hierarchicalDocumentSymbolSupport = true, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, hover = { contentFormat = { "markdown", "plaintext" }, dynamicRegistration = false }, implementation = { linkSupport = true }, publishDiagnostics = { relatedInformation = true, tagSupport = { valueSet = { 1, 2 } } }, references = { dynamicRegistration = false }, rename = { dynamicRegistration = false, prepareSupport = true }, signatureHelp = { dynamicRegistration = false, signatureInformation = { activeParameterSupport = true, documentationFormat = { "markdown", "plaintext" }, parameterInformation = { labelOffsetSupport = true } } }, synchronization = { didSave = true, dynamicRegistration = false, willSave = false, willSaveWaitUntil = false }, typeDefinition = { linkSupport = true } }, window = { showDocument = { support = false }, showMessage = { messageActionItem = { additionalPropertiesSupport = false } }, workDoneProgress = true }, workspace = { applyEdit = true, configuration = true, symbol = { dynamicRegistration = false, hierarchicalWorkspaceSymbolSupport = true, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, workspaceEdit = { resourceOperations = { "rename", "create", "delete" } }, workspaceFolders = true } }, clientInfo = { name = "Neovim", version = "0.8.0" }, initializationOptions = vim.empty_dict(), processId = 377762, rootPath = "/home/localadmin/test", rootUri = "file:///home/localadmin/test", trace = "off", workspaceFolders = { { name = "/home/localadmin/test", uri = "file:///home/localadmin/test" } } }}
[ERROR][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:734    "rpc"   "clangd"    "stderr"    "I[14:16:22.583] clangd version 10.0.0-4ubuntu1 
I[14:16:22.583] PID: 377766
I[14:16:22.583] Working directory: /home/localadmin/test
I[14:16:22.583] argv[0]: clangd
I[14:16:22.583] argv[1]: --background-index
I[14:16:22.583] argv[2]: --suggest-missing-includes
I[14:16:22.583] Starting LSP over stdin/stdout
I[14:16:22.584] <-- initialize(1)
I[14:16:22.584] --> reply:initialize(1) 0 ms
"
[DEBUG][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:388    "rpc.receive"   { id = 1, jsonrpc = "2.0", result = { capabilities = { codeActionProvider = { codeActionKinds = { "quickfix", "refactor", "info" } }, completionProvider = { resolveProvider = false, triggerCharacters = { ".", ">", ":" } }, declarationProvider = true, definitionProvider = true, documentFormattingProvider = true, documentHighlightProvider = true, documentLinkProvider = { resolveProvider = false }, documentOnTypeFormattingProvider = { firstTriggerCharacter = "
", moreTriggerCharacter = {} }, documentRangeFormattingProvider = true, documentSymbolProvider = true, executeCommandProvider = { commands = { "clangd.applyFix", "clangd.applyTweak" } }, hoverProvider = true, referencesProvider = true, renameProvider = { prepareProvider = true }, selectionRangeProvider = true, signatureHelpProvider = { triggerCharacters = { "(", "," } }, textDocumentSync = 2, typeHierarchyProvider = true, workspaceSymbolProvider = true }, offsetEncoding = "utf-8" }}
[DEBUG][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:285    "rpc.send"  { jsonrpc = "2.0", method = "initialized", params = vim.empty_dict()}
[INFO][2022-10-24 14:16:22] .../lua/vim/lsp.lua:1343    "LSP[clangd]"   "server_capabilities"   { server_capabilities = { codeActionProvider = { codeActionKinds = { "quickfix", "refactor", "info" } }, completionProvider = { resolveProvider = false, triggerCharacters = { ".", ">", ":" } }, declarationProvider = true, definitionProvider = true, documentFormattingProvider = true, documentHighlightProvider = true, documentLinkProvider = { resolveProvider = false }, documentOnTypeFormattingProvider = { firstTriggerCharacter = "
", moreTriggerCharacter = {} }, documentRangeFormattingProvider = true, documentSymbolProvider = true, executeCommandProvider = { commands = { "clangd.applyFix", "clangd.applyTweak" } }, hoverProvider = true, referencesProvider = true, renameProvider = { prepareProvider = true }, selectionRangeProvider = true, signatureHelpProvider = { triggerCharacters = { "(", "," } }, textDocumentSync = { change = 2, openClose = true, save = { includeText = false }, willSave = false, willSaveWaitUntil = false }, typeHierarchyProvider = true, workspaceSymbolProvider = true }}
[DEBUG][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:285    "rpc.send"  { jsonrpc = "2.0", method = "textDocument/didOpen", params = { textDocument = { languageId = "cpp", text = '#include <iostream>
#include "opencv2/opencv.hpp"

int main(int argc, char** argv ) {

 if(argc != 2)
 {
 std::cerr << std::endl << "Usage: ./datacollector";
 std::cerr << " dataset_save_path" << std::endl;
 // std::cerr << " path_to_settings"; 
 // std::cerr << " path_to_ros2bag_1";
 // std::cerr << " (path_to_ros2bag_2 ... path_to_ros2bag_N) " << std::endl;
 return 1;
 }
}
', uri = "file:///home/localadmin/test/src/main.cpp", version = 0 } }}
[ERROR][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:734    "rpc"   "clangd"    "stderr"    "I[14:16:22.723] <-- initialized
I[14:16:22.723] unhandled notification initialized
I[14:16:22.723] <-- textDocument/didOpen
"
[ERROR][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:734    "rpc"   "clangd"    "stderr"    "I[14:16:22.724] Failed to find compilation database for /home/localadmin/test/src/main.cpp
I[14:16:22.724] Updating file /home/localadmin/test/src/main.cpp with command clangd fallback
[/home/localadmin/test/src]
/usr/lib/llvm-10/bin/clang /home/localadmin/test/src/main.cpp -fsyntax-only -resource-dir=/usr/lib/llvm-10/lib/clang/10.0.0
"
[ERROR][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:734    "rpc"   "clangd"    "stderr"    "I[14:16:22.994] --> textDocument/publishDiagnostics
"
[DEBUG][2022-10-24 14:16:22] .../vim/lsp/rpc.lua:388    "rpc.receive"   { jsonrpc = "2.0", method = "textDocument/publishDiagnostics", params = { diagnostics = { { code = "pp_file_not_found", message = "'opencv2/opencv.hpp' file not found", range = { ["end"] = { character = 29, line = 1 }, start = { character = 9, line = 1 } }, relatedInformation = {}, severity = 1, source = "clang" } }, uri = "file:///home/localadmin/test/src/main.cpp" }}
[TRACE][2022-10-24 14:16:22] .../lua/vim/lsp.lua:1052   "notification"  "textDocument/publishDiagnostics"   { diagnostics = { { code = "pp_file_not_found", message = "'opencv2/opencv.hpp' file not found", range = { ["end"] = { character = 29, line = 1 }, start = { character = 9, line = 1 } }, relatedInformation = {}, severity = 1, source = "clang" } }, uri = "file:///home/localadmin/test/src/main.cpp"}
[TRACE][2022-10-24 14:16:22] ...lsp/handlers.lua:519    "default_handler"   "textDocument/publishDiagnostics"   { ctx = '{
 client_id = 1,
 method = "textDocument/publishDiagnostics"
}', result = { diagnostics = { { code = "pp_file_not_found", message = "'opencv2/opencv.hpp' file not found", range = { ["end"] = { character = 29, line = 1 }, start = { character = 9, line = 1 } }, relatedInformation = {}, severity = 1, source = "clang" } }, uri = "file:///home/localadmin/test/src/main.cpp" }}
[INFO][2022-10-24 14:16:29] .../lua/vim/lsp.lua:1814    "exit_handler"  { { _on_attach = <function 1>, attached_buffers = { true }, cancel_request = <function 2>, commands = {}, config = { _on_attach = <function 3>, autostart = true, capabilities = { callHierarchy = { dynamicRegistration = false }, offsetEncoding = { "utf-8", "utf-16" }, textDocument = { codeAction = { codeActionLiteralSupport = { codeActionKind = { valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" } } }, dataSupport = true, dynamicRegistration = false, isPreferredSupport = true, resolveSupport = { properties = { "edit" } } }, completion = { completionItem = { commitCharactersSupport = false, deprecatedSupport = false, documentationFormat = { "markdown", "plaintext" }, preselectSupport = false, snippetSupport = false }, completionItemKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } }, contextSupport = false, dynamicRegistration = false, editsNearCursor = true }, declaration = { linkSupport = true }, definition = { linkSupport = true }, documentHighlight = { dynamicRegistration = false }, documentSymbol = { dynamicRegistration = false, hierarchicalDocumentSymbolSupport = true, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, hover = { contentFormat = { "markdown", "plaintext" }, dynamicRegistration = false }, implementation = { linkSupport = true }, publishDiagnostics = { relatedInformation = true, tagSupport = { valueSet = { 1, 2 } } }, references = { dynamicRegistration = false }, rename = { dynamicRegistration = false, prepareSupport = true }, signatureHelp = { dynamicRegistration = false, signatureInformation = { activeParameterSupport = true, documentationFormat = { "markdown", "plaintext" }, parameterInformation = { labelOffsetSupport = true } } }, synchronization = { didSave = true, dynamicRegistration = false, willSave = false, willSaveWaitUntil = false }, typeDefinition = { linkSupport = true } }, window = { showDocument = { support = false }, showMessage = { messageActionItem = { additionalPropertiesSupport = false } }, workDoneProgress = true }, workspace = { applyEdit = true, configuration = true, symbol = { dynamicRegistration = false, hierarchicalWorkspaceSymbolSupport = true, symbolKind = { valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 } } }, workspaceEdit = { resourceOperations = { "rename", "create", "delete" } }, workspaceFolders = true } }, cmd = { "clangd", "--background-index", "--suggest-missing-includes" }, cmd_cwd = "/home/localadmin/test", filetypes = { "c", "cpp", "objc", "objcpp" }, flags = {}, get_language_id = <function 4>, handlers = <1>{}, init_options = vim.empty_dict(), log_level = 2, message_level = 2, name = "clangd", on_attach = <function 5>, on_exit = <function 6>, on_init = <function 7>, root_dir = "/home/localadmin/test", settings = vim.empty_dict(), single_file_support = true, workspace_folders = <2>{ { name = "/home/localadmin/test", uri = "file:///home/localadmin/test" } }, <metatable> = <3>{ __tostring = <function 8> } }, handlers = <table 1>, id = 1, initialized = true, is_stopped = <function 9>, messages = { messages = {}, name = "clangd", progress = {}, status = {} }, name = "clangd", notify = <function 10>, offset_encoding = "utf-8", request = <function 11>, request_sync = <function 12>, requests = {}, rpc = { is_closing = <function 13>, notify = <function 14>, request = <function 15>, terminate = <function 16> }, server_capabilities = { codeActionProvider = { codeActionKinds = { "quickfix", "refactor", "info" } }, completionProvider = { resolveProvider = false, triggerCharacters = { ".", ">", ":" } }, declarationProvider = true, definitionProvider = true, documentFormattingProvider = true, documentHighlightProvider = true, documentLinkProvider = { resolveProvider = false }, documentOnTypeFormattingProvider = { firstTriggerCharacter = "
", moreTriggerCharacter = {} }, documentRangeFormattingProvider = true, documentSymbolProvider = true, executeCommandProvider = { commands = { "clangd.applyFix", "clangd.applyTweak" } }, hoverProvider = true, referencesProvider = true, renameProvider = { prepareProvider = true }, selectionRangeProvider = true, signatureHelpProvider = { triggerCharacters = { "(", "," } }, textDocumentSync = { change = 2, openClose = true, save = { includeText = false }, willSave = false, willSaveWaitUntil = false }, typeHierarchyProvider = true, workspaceSymbolProvider = true }, stop = <function 17>, supports_method = <function 18>, workspaceFolders = <table 2>, workspace_did_change_configuration = <function 19>, workspace_folders = <table 2>, <metatable> = { __index = <function 20> } } }
[DEBUG][2022-10-24 14:16:29] .../vim/lsp/rpc.lua:285    "rpc.send"  { id = 2, jsonrpc = "2.0", method = "shutdown"}
[ERROR][2022-10-24 14:16:30] .../vim/lsp/rpc.lua:734    "rpc"   "clangd"    "stderr"    "I[14:16:30.000] <-- shutdown(2)
I[14:16:30.000] --> reply:shutdown(2) 0 ms
"
[DEBUG][2022-10-24 14:16:30] .../vim/lsp/rpc.lua:388    "rpc.receive"   { id = 2, jsonrpc = "2.0"}
[DEBUG][2022-10-24 14:16:30] .../vim/lsp/rpc.lua:285    "rpc.send"  { jsonrpc = "2.0", method = "exit"}
[START][2022-10-24 14:18:47] LSP logging initiated
[INFO][2022-10-24 14:18:47] .../lua/vim/lsp.lua:1814    "exit_handler"  {} 

Olli
  • 375
  • 5
  • 15

1 Answers1

0

Given the file /home/localuser/Projects/SLAM3/Examples/Stereo-Inertial/stereo_inertial_bag.cc, the places clangd will look are:

/home/localuser/Projects/SLAM3/Examples/Stereo-Inertial/compile_commands.json
/home/localuser/Projects/SLAM3/Examples/Stereo-Inertial/build/compile_commands.json
/home/localuser/Projects/SLAM3/Examples/compile_commands.json
/home/localuser/Projects/SLAM3/Examples/build/compile_commands.json
/home/localuser/Projects/SLAM3/compile_commands.json
/home/localuser/Projects/SLAM3/build/compile_commands.json
/home/localuser/Projects/compile_commands.json
/home/localuser/Projects/build/compile_commands.json
etc.

It does not look at /home/localuser/SLAM3/MyProject/build because your source file is not in MyProject.

HighCommander4
  • 50,428
  • 24
  • 122
  • 194
  • Sorry, there was a typo in that first code block (fixed). There is no "MyProject" folder. compile_commands is in `/home/localuser/Projects/SLAM3/build/compile_commands.json` – Olli Sep 07 '22 at 08:05
  • 1
    @Olli Ok, in that case, I would expect clangd to find it. To try to diagnose the issue further, can you attach complete logs? – HighCommander4 Sep 07 '22 at 17:58
  • Hi, I've attached the full lsp logs to my original question, along with a simplified small one-file project to reproduce the issue. – Olli Oct 24 '22 at 11:31
  • 1
    @Olli: Here is the issue: `clangd version 10.0.0-4ubuntu1`. This is a very old clangd version (latest version is 15.0.3). The logic to look in `build` subdirectories was added in version 11 or 12 I believe. Newer versions can be obtained from https://github.com/clangd/clangd/releases. – HighCommander4 Oct 24 '22 at 23:31