reddit / emacs

C/C++, clangd and eglot -- not finding definitions

hangingpawns · 2022-10-04 06:09
I am having trouble getting eglot to work. With lsp-mode, I have no problem, but I am trying eglot since it's lightweight and going to be included in emacs by default. Here's the problem. I'm trying to find definitions for a struct, but eglot can't find it. ​ file.cpp has a function function (struct type\_t \*t1, ...) { type\_t \*temp = t1; // this line here } ​ When I do xref-find-definition for type\_t, it simply shows me the "struct type\_t \*t1" in the file above. type\_t is defined in another header, which this file includes. Why can't eglot/xref jump to the definition in the file that defines type\_t? lsp-mode, there's no issue at all. (I am compiling my code with bear to get a compile\_commands.json file). ​ What am I missing?
whatacold · 2022-10-04 07:25
~~Did you have a `compile_commands.json` for the project?~~ Sorry, I just read it again that you have it. Would you copy & paste all your file contents in the post? Update: If it's a big project, maybe you can create a demo project temporarily to see how it works.
whatacold · 2022-10-04 07:39
Run `M-x eglot-events-buffer` to open the events buffer, then type `M-x xref-find-definitions` and see if there are messages between the LSP server and eglot there.
ambihelical · 2022-10-04 15:17
How are you configuring eglot?
hangingpawns · 2022-10-04 17:09
I'm not doing much because the readme said just do M-x eglot and it will figure out which language server to invoke and what your project hierarchy is. I does spit out a message saying it started the clangd server. ​ \[eglot\] Connected! Server \`clangd' now managing \`(c-mode c++-mode)' buffers in project \`dynamic\_scheduler'.
hangingpawns · 2022-10-04 17:11
\[eglot\] Connected! Server \`clangd' now managing \`(c-mode c++-mode)' buffers in project \`dynamic\_scheduler'. &#x200B; I see that in the \*messages\* buffer. &#x200B; In the eglot-events-buffer, i see a lot of stuff like this: &#x200B; \[stderr\] I\[10:08:41.985\] <-- textDocument/hover(3)\[stderr\] I\[10:08:41.986\] <-- textDocument/documentHighlight(4)\[stderr\] I\[10:08:41.986\] --> reply:textDocument/hover(3) 0 ms\[stderr\] I\[10:08:41.986\] --> reply:textDocument/documentHighlight(4) 0 ms\[server-reply\] (id:3) Tue Oct 4 10:08:41 2022:(:id 3 :jsonrpc "2.0" :result nil)\[server-reply\] (id:4) Tue Oct 4 10:08:41 2022:(:id 4 :jsonrpc "2.0" :result \[\])\[stderr\] I\[10:08:41.992\] --> reply:textDocument/signatureHelp(2) 10 ms\[server-reply\] (id:2) Tue Oct 4 10:08:41 2022:(:id 2 :jsonrpc "2.0" :result (:activeParameter 0 :activeSignature 0 :signatures \[\]))
hangingpawns · 2022-10-04 22:42
Is there something I should be configuring?
whatacold · 2022-10-05 01:17
Did you see something (**textDocument/definition**) like the below request & response: ``` [client-request] (id:8) Wed Oct 5 09:13:54 2022: (:jsonrpc "2.0" :id 8 :method "textDocument/definition" :params (:textDocument (:uri "file:///home/hgw/test/eglot-try/c-cpp/hello.cpp") :position (:line 8 :character 20))) [server-reply] (id:8) Wed Oct 5 09:13:54 2022: (:id 8 :jsonrpc "2.0" :result [(:range (:end (:character 13 :line 2) :start (:character 7 :line 2)) :uri "file:///home/hgw/test/eglot-try/c-cpp/hello.h")]) ```
whatacold · 2022-10-05 01:19
It should work out of the box. My suggestion is that you play it with a demo project first, as LSP is tricky sometimes.
hangingpawns · 2022-10-05 03:57
\[client-request\] (id:2) Tue Oct 4 20:51:48 2022: (:jsonrpc "2.0" :id 2 :method "textDocument/signatureHelp" :params (:textDocument (:uri "file:///Users/myname/openmpi/src/server/mpi\_server.c") :position (:line 149 :character 4))) \[client-request\] (id:3) Tue Oct 4 20:51:48 2022: (:jsonrpc "2.0" :id 3 :method "textDocument/hover" :params (:textDocument (:uri "file:///Users/myname/openmpi/src/server/mpi\_server.c") :position (:line 149 :character 4))) \[client-request\] (id:4) Tue Oct 4 20:51:48 2022: (:jsonrpc "2.0" :id 4 :method "textDocument/documentHighlight" :params (:textDocument (:uri "file:///Users/myname/openmpi/src/server/mpi\_server.c") :position (:line 149 :character 4))) \[stderr\] I\[20:51:48.498\] <-- textDocument/signatureHelp(2) \[stderr\] I\[20:51:48.501\] <-- textDocument/hover(3) \[stderr\] I\[20:51:48.501\] <-- textDocument/documentHighlight(4)mpi
ambihelical · 2022-10-05 05:17
There can be. I've never had it work out of the box for the C++ projects I've worked on because of the following problems: 1. compile\_commands.json was in a strange place. For example, cmake projects will plop it in the build directory, but clangd doesn't know about it. A symlink (for linux) or .clangd (for windows) can adjust for that. You can symlink it into the root of your project so clangd can find it from any source directory. Alternatively, .clangd at the root of the project can provide it's location. 2. I work on embedded projects with cross-compilation, and clangd needs to be told to use the compiler tool in compile\_commands.json to find header files in the toolchain I'm using. This requires flag be passed to clangd. So this requires using executable-find to find the path to clangd and adding a few terms to eglot-server-programs list. 3. Calling eglot-ensure seems to be needed, so there's usually some configuration for that. I call that on a hook. Here's my complete configuration, fwiw: ;; polyglot language server interface (use-package eglot :after no-littering :general (:keymaps 'eglot-mode-map "<f6> x" #'eglot-rename "C-<tab>" #'complete-symbol "<f6> c" #'eglot-code-actions) :init (setq eglot-ignored-server-capabilities '( :documentHighlightProvider) eglot-send-changes-idle-time 3 ;; be slower sending changes eglot-extend-to-xref t ;; external files ok eglot-events-buffer-size 100000) ;; smaller events buffer ;; windows eglot has a bug with eglot-extend-to-xref. See issue 715 (when (eq window-system 'w32) (setq eglot-extend-to-xref nil)) :config ;; configure clangd for c++ and c (when-let* ((clangd (seq-find #'executable-find '("clangd" "clangd-6.0"))) ;; this has to match the tool string in compile-commands.json ;; clangd will then use these tools to get system header paths (init-args "--query-driver=/**/*")) (add-to-list 'eglot-server-programs `((c++-mode c-mode) ,clangd ,init-args))) :hook ((rust-mode c++-mode c-mode) . eglot-ensure)) On the other hand, rust-mode really does work out of the box, but I believe I did need to call eglot-ensure for that too, so that may be all you need if you don't have any of the problems I listed.
ambihelical · 2022-10-05 05:40
There's also a hidden buffer (starts with space character) which is named something like `*EGLOT (project-name/c++-mode) stderr*` which will tell you useful things, including if your compile\_commands.json file got loaded. You should see something like "Loaded compilation database from ..." after it dumps some information about clangd and LSP startup. And then it will list errors parsing your files.
whatacold · 2022-10-05 06:05
Sounds like eglot didn't ask for the definition. And by a quick look at the source code, I found that eglot will "inject" itself to the `xref-backend-functions` variable, so type `C-h v xref-backend-functions` to see if there is `eglot-xref-backend` in it. Mine is ``` xref-backend-functions is a variable defined in ‘xref.el’. Its value is (eglot-xref-backend ggtags--xref-backend t) ... ```
whatacold · 2022-10-05 06:17
Cool, good to know it. And there is a accompany stdout buffer like ` *EGLOT (<project-name>/c++-mode) output*`
hangingpawns · 2022-10-05 06:28
Thanks for this! When I try it, I get this error: \>Debugger entered--Lisp error: (void-function use-package) edit: I installed the use-package package, and put (require 'use-package) in my init. Now, I get this error: Debugger entered--Lisp error: (error "use-package: Unrecognized keyword: :general") Any advice?
ambihelical · 2022-10-05 14:41
Hmmm meant it as an example for reference. But if you want to use it take the general section out they are just key bindings. Also remove the :after line as this references another package. It doesn't sound like there is any problem loading clangd from your previous comments, so my configuration probably won't help you unless you do cross compilation. It sounds to me like clangd isn't finding your compile_commands.json or there is some problem with the information in the file. You can check that by looking at the eglot stderr buffer I referred to in another comment to this post.