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" {}