使用 cquery: C++ language server - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MaskRay
V2EX    Vim

使用 cquery: C++ language server

  •  7
     
  •   MaskRay 2017-12-09 13:00:30 +08:00 6252 次点击
    这是一个创建于 2862 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原文 https://maskray.me/blog/2017-12-03-c++-language-server-cquery

    C++代码索引工具现状

    Tag system 流派

    clang 流派

    • clang-tags荒废。
    • YouCompleteMe不够好用,因为只处理单一 translation unit,无法查找引用。
    • clangd最有前景,有大厂大项目愿意采用,Xcode 使用。但目前尚无存储系统,因此无法处理多 translation units。作为clang-tools-extra一部分,而 clang+llvm 构建 /贡献门槛高([https://reviews.llvm.org/])。对于这类工具类应用,贡献难易程度是个重要因素。目前有尝试引入存储模型(MarkZ3),但目前设计较为复杂,而实际上不带 garbage collection 的std::vector(cquery 风格)足够应对大部分使用场景。很担心他们走上歧路。
    • Google Kythe,(mostly) language-agnostic,概念复杂,配置困难。不重视 language server protocol,当前仅提供ReferencesProvider,HoverProvider,DefinitionProvider,且交互使用可能有极大延迟。大多数人并不在意 C++ Haskell Python 代码间无缝跳转。
    • rtags可以查找引用,但每个 translation unit 6 个文件info,symbols,symnames,targets,tokens,usrs(过多),没有使用 in-memory 索引,查找引用请求会读项目所有 translation units 的文件。导致性能低下https://github.com/Andersbakken/rtags/issues/1007
    • cquery现阶段的妥协。主要数据结构为不带 garbage collection(变量 /函数 /类型等的 id 不会回收)的std::vector(src/indexer.h)。有一些 Emacs 用户积极贡献code navigation 功能

    IDE(Any sufficiently complicated IDE contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of C++.)

    cquery 安装、配置

    https://github.com/jacobdufault/cquery。Arch Linux 可用aur/cquery-git

    • 构建 language server 可执行文件
    • 编辑器安装 language client 插件
    • 配置 language client,打开 C++文件时运行 language server 可执行文件,通过 stdio 用JSON-RPC 2.0通信
      • 光标移动时向 language server 发送textDocument/hover请求,language server 返回变量 /函数声明信息
      • 查找定义发送textDocument/definition请求
      • 查找引用发送textDocument/references请求
      • 查找当前文档定义的符号(通常是顶层的 outline)发送textDocument/documentSymbol请求
      • 查找项目定义的符号(只查找 outline 的也很有用)发送workspace/symbol请求
      • 补全textDocument/completion
      • 文档编辑操作发送textDocument/didChange

    Emacs

    安装lsp-mode,参照https://github.com/jacobdufault/cquery/wiki/Emacs配置。lsp-mode 会设置xref-backend-functions,把以下函数

    • xref-find-definitions (默认M-.),对应textDocument/definition
    • xref-find-references (默认M-?),对应textDocument/references
    • xref-find-apropos (默认M-?),对应workspace/symbol
    • lsp-imenu 对应textDocument/documentSymbol
    • LSP 生态系统解决的一大痛点是以前对于不同语言,要使用不同工具,设置不同快捷键。用了 language client 就可以统一了。

    定向到 lsp-mode 中的处理函数,发送textDocument/definition等请求并渲染。

    如果使用helm,可以考虑安装helm-xrefxref-show-xrefs-function会使用helm-xref-show-xrefs。但目前有两个 issues 影响了我的使用体验:

    注意协议中定义返回结果为Location[] | null,只含位置信息,不包含代码行内容,如果要显示行内容。若文件在某个 buffer 内,则显示该 buffer 相应行;若未打开则需要打开该文件。

    Emacs Lisp dynamic scoping 使得我们可以很容易复用已有代码。可以基于 evil-jumps 做一个用于 xref 的 jump list。我喜欢 xref jump list 和正常 jump list 分离。因为查找定义 /引用后会进行一些局部跳转,喜欢有快捷键回到定义 /引用跳转前的位置。并且需要能双向移动,不能只是 jump stack,xref.el用 ring buffer 实现的是 stack。

    (defmacro my-xref//with-evil-jumps (&rest body) "Make `evil-jumps.el' commands work on `my-xref--jumps'." (declare (indent 1)) `(let ((evil--jumps-window-jumps ,my-xref--jumps)) ,@body)) (with-eval-after-load 'evil-jumps (evil-define-motion my-xref/evil-jump-backward (count) (my-xref//with-evil-jumps (evil--jump-backward count) (run-hooks 'xref-after-return-hook))) (evil-define-motion my-xref/evil-jump-forward (count) (my-xref//with-evil-jumps (evil--jump-forward count) (run-hooks 'xref-after-return-hook)))) 

    最近的新包https://github.com/emacs-lsp/lsp-ui包含 code lens、flycheck 等功能,以及一个基于quick-peekfind-{definitions,references,apropos}

    https://github.com/MaskRay/Config/blob/master/home/.emacs.d/layers/%2Bmy/my-code/funcs.el

    Neovim

    参照https://github.com/autozimu/LanguageClient-neovim/wiki/cquery

    nn <leader>ji :Denite documentSymbol<cr> nn <leader>jI :Denite workspaceSymbol<cr> " 终端限制,<C-,>不可用。ord(`,`) & 64 为 0 无法表示 nn <M-,> :Denite references<cr> nn <silent> <C-j> :MarkPush<cr>:call LanguageClient_textDocument_definition()<cr> 

    不清楚怎么把定义 /引用改造成使用可双向移动的 jump list。

    生成compile_commands.json

    CMake

    % mkdir build % (cd build; cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=YES ..) % ln -s build/compile_commands.json 

    Build EAR

    Bear is a tool that generates a compilation database for clang tooling. It can be used for any project based on Makefile.

    bear make # generates compile_commands.json 

    Ninja

    ninja -t compdb rule_names... > compile_commands.json 

    问题

    • Task lists https://github.com/jacobdufault/cquery/issues/30 Polish before publishing (to GitHub Marketplace)
    • 需要一个妥善的 on-disk storage。很多轻量级数据库不支持或有较难处理的问题(如果有需求把现在 in-memory+JSON 改成有其他存储模型)。注记,SQLITE_ENABLE_LOCKING_STYLE、flock 很难。

    其他

    索引 Linux kernel

    wget 'https://git.archlinux.org/svntogit/packages.git/plain/trunk/config?h=packages/linux' -O .config yes '' | make config bear make -j bzImage modules 

    生成 3GiB 文件。

    索引 llvm,du -sh => 1.1GB,索引完内存占用 2G。

    查看 LSP requests/responses

    sudo sysdig -As999 --unbuffered -p '%evt.type %evt.buffer' "proc.pid=$(pgrep -fn build/app) and fd.type=pipe" | egrep -v '^Content|^$' 

    生成compile_commands.json,参考https://github.com/jacobdufault/cquery/wiki

    希望有朝一日 Debug Protocol 也能获得重视,https://github.com/Microsoft/vscode-debugadapter-node/blob/master/protocol/src/debugProtocol.ts,让realgud轻松一点。

    和 YouCompleteMe 等项目一样,cquery 默认下载prebuilt clang+llvm,即.h .so .a。用户不需要编译完整的 llvm,开发门槛比 clangd 低。

    感谢 ngkaho1234。

    18 条回复    2018-05-14 14:55:10 +08:00
    glacier2002
        1
    glacier2002  
       2017-12-09 16:30:09 +08:00
    完全没看懂。。。。
    htfy96
        2
    htfy96  
       2017-12-09 16:40:07 +08:00 via Android
    cquery 感觉的确是现代的方案…时间不太够只能维护下 cquery-git 了
    forestyuan
        3
    forestyuan  
       2017-12-09 21:46:23 +08:00
    这是来推广的吗?
    MaskRay
        4
    MaskRay  
    OP
       2017-12-10 05:41:07 +08:00
    @glacier2002 原文有,容改了……困
    MaskRay
        5
    MaskRay  
    OP
       2017-12-10 05:42:15 +08:00   1
    @forestyuan 是的。希望能找到更多有 C/C++代需求的 geek 用目。很多 code assistant 功能靠 clangd 大教堂模式是搞不好的
    YeT9
        6
    YeT9  
       2017-12-10 10:23:58 +08:00
    Ray 教授啊!火钳流明~资瓷一个~
    congeec
        7
    congeec  
       2017-12-10 11:18:29 +08:00
    cquery 目前 hover definition 不能显示函数签名,跟 YouCompleteMe 比还差好多。不过能重构,也是的
    ivechan
        8
    ivechan  
       2017-12-10 15:48:00 +08:00
    之前试用了一下 clangd, 实在太难用了,有时候性能极差,还不如直接用 fzf ack 这类工具。
    skt041959
        9
    skt041959  
       2017-12-10 16:54:48 +08:00
    LanguageClient-neovim 是 rust 写的,没法编译。试了一下 vim-lsp 好像不会用。有其他支持的 vim/neovim LSP plugin 么?
    bookit
        10
    bookit  
       2017-12-10 20:03:44 +08:00
    善,哪一天能赶上 vax 就好了。
    autozimu
        11
    autozimu  
       2017-12-11 10:49:49 +08:00   1
    @skt041959 什么是没法编译?

    大多数情况应该是不需要编译的, 已经有编译好的 binaries 了呀
    congeec
        12
    congeec  
       2017-12-11 12:46:26 +08:00
    @autozimu 谢谢你的作品
    ivechan
        13
    ivechan  
       2017-12-22 15:27:20 +08:00
    之前看了但是还没尝试, 今天去尝试了一下, 在 vim 下体验比其他的好。谢谢。
    5thcat
        14
    5thcat  
       2018-01-06 01:52:11 +08:00
    非常感谢! 终于找到了失散多年的阅读代码工具!
    skt041959
        15
    skt041959  
       2018-01-08 13:23:44 +08:00
    @autozimu #11 之前理解错了,以为必须编译 rust 才能用。其实不用编译,直接用 python 的就可以了
    bef0rewind
        16
    bef0rewind  
       2018-01-26 09:40:55 +08:00
    很有意思的项目啊
    f2ed
        17
    f2ed  
       2018-04-18 17:38:07 +08:00
    我用的 vscode-cquery,表示 C++符号经常找不到啊,c 语言还可以
    MaskRay
        18
    MaskRay  
    OP
       2018-05-14 14:55:10 +08:00
    原都已半年了……我在用自己的 fork https://github.com/MaskRay/ccls

    移除了不必要的第三方依
    import_pipeline.cc 比原的多,效果更好(index merge, id map 都是 cquery 中不妥的,我上移除了)
    mem index 有少量提升

    https://github.com/autozimu/LanguageClient-neovim/issues/293 自定 cross reference 能支持就最好了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2778 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 14:50 PVG 22:50 LAX 07:50 JFK 10:50
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86