clangd 是一款 C/C++ language server,可以很方便地进行代码跳转、提示、补全等,本文总结在 alios 7 上安装 clangd 的一些经验
根据 clangd 官网安装指南,有 3 种方式安装 clangd:
- apt / yum 等系统包管理工具
- 下载预编译的 binary 文件
- 手动从源码编译
因为系统的包管理工具可能会引入各种奇奇怪怪的依赖,因此首先选择从 binary 安装
从 binary 安装 clangd
从 github 下载源码并解压,运行 clangd --version
,发现如下报错信息:
1
|
clangd_12.0.0/bin/clangd: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by clangd_12.0.0/bin/clangd)
|
此时发动 google 大法,搜索到博客 Install Clangd on CentOS 7,发现博主在从 binary 安装 clangd 的时候遇到同样 GLIBC 版本太旧的问题,且没有解决:(
既然此路不通,天真的我决定换一种方式,从编码编译安装,从此走上一条更艰难的道路。。
clangd 源码编译安装
首先选择一个你喜欢的目录,比如 ~/downloads
, 依次运行如下命令:
1
2
3
4
5
6
7
8
|
cd ~/downloads
git clone --depth=1 https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build && cd build
cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_INSTALL_PREFIX=~/tools/llvm -DCMAKE_BUILD_TYPE=Release ../llvm
make -j 16
make install
|
如果不出意外,编译好的二进制文件将会出现在 ~/tools/llvm
。在 ~/tools/llvm
下运行 clangd --version
,可以看到版本信息,之后就可以愉快地使用 clangd 了。
然而万事总怕意外,编译时发现系统 GCC 版本太旧,无法编译,此时继续 google,发现cmake可以用 -DCMAKE_C_COMPILER
选项制定编译器,于是又走上了升级 GCC 版本的不归路。
编译安装 GCC
为了不搞坏系统 GCC 配置,我选择从源码单独编译一个 GCC 版本,参考 GCC 安装指南,运行以下命令:
1
2
3
4
5
6
7
8
9
10
|
cd ~/download
wget http://ftp.gnu.org/gnu/gcc/gcc-6.2.0/gcc-6.2.0.tar.gz
tar -zxvf gcc-6.2.0.tar.gz
cd gcc-6.2.0
./contrib/download_prerequisites
cd ..
mkdir gcc-6.2.0-build && cd gcc-6.2.0-build
../gcc-6.2.0/configure --prefix=$HOME/GCC-6.2.0 --enable-languages=c,c++,fortran,go -enable-checking=release -disable-multilib
make
make install
|
以上命令会把 GCC-6.2.0 安装在 prefix 选项指定的 $HOME/GCC-6.2.0
目录,安装成功后,继续使用以下命令编译 llvm。
1
2
|
cd ~/downloads/llvm-project/build
cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_C_COMPILER=$HOME/GCC-6.2.0/bin/gcc -DCMAKE_INSTALL_PREFIX=~/tools/llvm -DCMAKE_BUILD_TYPE=Release ../llvm
|
其中 -DCMAKE_C_COMPILER
执行了我们刚刚编译好的 GCC。
不出意外,这次编译又失败了,报错 GLIBC 不存在,类似:
1
|
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found
|
摔,这不就是从 binary 安装时遇到的报错信息吗?折腾一大圈又回到最初的起点,继续 google 大法。
升级 GLIBC
发现博客 ,于是开始更新 GLIBC++,依次运行如下命令:
1
2
|
# 检查动态库
strings /usr/lib64/libstdc++.so.6 | grep GLIBC
|
输出类似:
1
2
3
4
5
6
7
8
|
...
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_FORCE_NEW
GLIBCXX_DEBUG_MESSAGE_LENGTH
|
总之,这里输出的动态库版本一定会比报错信息中的版本小,因为我们编译新版 GCC 时没有升级动态库。
首先找到编译GCC 时生成的动态库,运行 find ~/ -name "libstdc++.so*"
:输出以下信息:
1
2
3
4
|
.../downloads/build-gcc-6.2.0/prev-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
.../downloads/build-gcc-6.2.0/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.22 # 最新动态库
.../downloads/build-gcc-6.2.0/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so
.../downloads/build-gcc-6.2.0/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
|
后缀最长的libstdc++.so.6.xxx
就是最新动态库,运行以下命令替换动态库:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
sudo cp ~/downloads/build-gcc-6.2.0/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.22 /usr/lib64/libstdc++.so.6.0.22-my
cd /usr/lib64
# 先用ll 看一下里面有啥
ll libstdc++*
# 输出,其中 libstdc++.so.6.0.22-my 是刚复制过来的
lrwxrwxrwx 1 root root 30 Nov 29 11:59 libstdc++.so.6 -> libstdc++.so.6.19
-rwxr-xr-x 10 root root 995848 Jun 13 2018 libstdc++.so.6.0.19
-rwxr-xr-x 1 root root 11509888 Nov 27 17:31 libstdc++.so.6.0.22-my
# 删除原来的软连接,注意一定不要删掉原来的文件,只是删除软连接 libstdc++.so.6
sudo rm -f libstdc++.so.6
# 替换软连接
ln -s libstdc++.so.6.0.22-my libstdc++.so.6
# 查看替换结果
ll libstdc++*
lrwxrwxrwx 1 root root 30 Nov 29 11:59 libstdc++.so.6 -> libstdc++.so.6.22-my
-rwxr-xr-x 10 root root 995848 Jun 13 2018 libstdc++.so.6.0.19
-rwxr-xr-x 1 root root 11509888 Nov 27 17:31 libstdc++.so.6.0.22-my
|
这样动态库就更新成功了。
经过这样一番折腾,切到 ~/downloads/llvm-project/build
重新编译 llvm,应该可以成功了(反正我是成功了),编译过程较慢,需要耐心等一下。
将 clangd 加入 PATH
编译成功后,~/tools/llvm
目录应该有一大堆二进制文件,运行以下命令验证编译是否成功
1
2
3
4
5
6
|
cd ~/tools/llvm
clangd --version
# 输出如下信息表示编译成功
clangd version 14.0.0 (http://github.com/llvm/llvm-project.git 6fa8f7beb1928dfad291314c8baf16374a1cc145)
Features: linux
Platform: x86_64-unknown-linux-gnu
|
之后需要将路径加入到PATH,才能在命令行执行 clangd 命令。
用 vi 打开 ~/.bash_profile
,输入PATH=$PATH:$HOME/tools/llvm
,保存退出后执行 source ~/.bash_profile
,即可在命令行直接执行 clangd。
在 vscode 中使用 clangd
经过这么一大圈折腾,终于可以在vscode 中愉快滴使用 clangd 了,首先安装 clangd 插件,并加入如下配置:
1
2
3
4
5
6
7
8
|
"clangd.arguments": [
"--compile-commands-dir=${workspaceFolder}/build_debug",
"-j=12",
"--background-index",
"--clang-tidy",
"--log=verbose",
"--pretty",
],
|
注意,clangd 依赖 compile_commands.json 文件解析源码,因此需要在 --compile-commands-dir
选项配置你的文件路径。
如果你是用 cmake 构建项目,可以在cmake 时加入如下选项:
1
|
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1
|
即可生成 compile_commands.json 文件,其他构建方式自行google。
从此以后,程序员和 clangd 过上了幸福的生活。
总结
回顾整个安装过程,发现自己对 GCC 编译体系还是不够熟悉,明明可以在从 binary 安装时就更新 GLIBC 从而解决问题,硬是绕了这么一大圈,还是应该加强学习,埋头查报错信息不如仔细看看报错信息背后的知识体系,可能有事半功倍的作用。