最近在 CentOS 7 服务器上写程序时没有 LSP 的帮助,感觉写起来很费劲,于是折腾了一下 clangd
使之能为 coc.nvim
所用。
基本环境要求
-
Anaconda/Miniconda 可以去各大镜像站下载安装包,然后直接
sh Anaconda_xxx.sh
进行安装。这里推荐使用 miniconda ,因为 Anaconda 内置的包太多,每次conda install
解析依赖冲突都会耗时 114514 年,而 miniconda 因为内置的包更少,依赖解析起来反倒更快。 -
Vim 及其插件 使用
conda
命令安装 Vim 8.0 或更高的版本1
conda install -c conda-forge vim
然后查看 vim 的版本号:
1 2 3 4 5 6 7 8
$ vim --version VIM - Vi IMproved 9.0 (2022 Jun 28, compiled Aug 31 2022 01:19:52) Included patches: 1-335 Compiled by conda@065326dfb3d2 Huge version without GUI. Features included (+) or not (-): +acl +file_in_path +mouse_urxvt -tag_any_white ... ...
是 9.0 ,说明安装成功。
然后安装
vim-plug
和coc.nvim
,直接 Follow 官网上的安装教程即可
安装 clangd
CentOS 7 的 yum 源里也有 llvm
和 clang
的包,但它们都没有提供 clangd
,那我们只能去自己安装了。
其实如果你使用 coc-clangd
的话,它会帮你下载 clangd
的可执行文件,但网上预编译的 clangd
没有对
CentOS 7 这种老平台适配,运行时会报这个经典错误
|
|
这是因为 CentOS 7 默认的 glibc
只有 2.17 ,而贸然升级 glibc
又是管理 Linux 服务器的大忌(各种程序会炸),
那就只能寻求别的办法了。
所幸 Anaconda 提供了 clangd
,我们只需要执行下面的命令即可
|
|
然后检查一下各个程序的版本
|
|
写一个 C 的 Hello world :
|
|
看能不能用 Clang 编译
|
|
看来是没问题的;那么 C++ 的 Hello world 呢?
|
|
使用 clang++
编译:
|
|
这又是一个很经典的错误,它表示 clang++
找不到头文件 iostream
,解决它的办不是添加 -I/usr/include/...
等参数,而是告诉 clang++
借用 gcc
工具链内的一些头文件和链接库,具体办法就是使用 --gcc-toolchain
这个参数,
官网1
上对这个参数的说明中表示
|
|
那就很好办了,直接指定 --gcc-toolchain=/usr
即可:
|
|
编译运行成功。
此时关于 Clang 的安装就完成了。
配置 coc.nvim
coc.nvim
的官网提供了 clangd
的配置模板,直接复制到 ~/.vim/coc-settings.json
里即可
|
|
此时,用 Vim 打开刚才写的 C Hello world main.c
应该已经可以提供补全了,如图所示
接下来配置 C++ 源文件的补全。如果不添加别的参数,那么打开刚刚的 C++ Hello world main.cpp
,应该会出现以下错误
这和之前直接用 clang++
编译时的错误一模一样,之前是通过给 clang++
加一个参数 --gcc-toolchain=/usr
来解决的,
那么一定有方法可以把编译参数传给 clang++
来让 clangd
正常工作。 clangd
官网上给出的解决方案是在 main.cpp
同目录下写一个配置文件让 clangd
来正确调用相关的程序,有三种格式可供选择:
-
compile_commands.json
这个就是用 json 的格式把编译时需要的命令和参数记录下来传给
clangd
,它需要把每个文件的编译命令都显式写出来, 我想没人会喜欢手写 json ,并且是如此啰嗦的 json , 下面是一个示例21 2 3 4 5 6 7
[ { "directory": "/public/home/xxx/tests/cxx", "arguments": ["/public/home/xxx/.miniconda/bin/clang++", "--gcc-toolchain=/usr", "main.cpp"], "file": "file.cc" }, ]
-
compile_flags.txt
这个文件的格式非常简单,把参数逐行写到这个文件里即可
1 2
--gcc-toolchain=/usr --std=c++11
然后
clangd
就能正常工作了。
-
.clangd
这个文件格式会稍微复杂一些,官网3上有详细的解释,这里给出一个可用的示例
1 2
CompileFlags: Add: [--gcc-toolchain=/usr]
将上述三个文件中的任意一个放到 main.cpp
的同目录下,用 Vim 打开 main.cpp
, LSP 应该能正常补全了
看起来效果不错,但总要写这些配置文件总让人不爽,倒不是说参数太长,而是连建个 Hello world 都要写个配置文件难免过于麻烦了,而且编译参数在 Makefile
里已经写过一遍,再写一遍岂不很累。有没有办法不用写这些配置,就把参数传给 clang++
?经过上网冲浪,在 vscode
和 coc-clangd
的配置里有个参数叫 --fallbackFlags
,它表示当
clangd
找不到上面 compile.json
、 compile_flags.txt
和 .clangd
中任意一个时所使用的参数。从 coc-clangd
的源码4里得知,
这个参数应该被放在 initializationOptions
下面。打开 ~/.vim/coc-settings.json
,加上这个参数:
|
|
删掉 compile.json
、 compile_flags.txt
和 .clangd
,然后打开 main.cpp
,补全依然正常工作,大功告成。
当然如果你需要为某个工程写特定的编译参数,那还是老老实实用那三个配置文件吧, initializationOptions
仅限简单场景使用。