centos7 配置 vscode+clangd 环境
背景
工作中的项目基于 C 语言,代码量庞大,并基于 vscode 的 C/C++ 插件实现代码跳转。
开发过程中发现代码补全,跳转等功能存在问题,经常出现匹配不上或者跳转不准确的问题。每次重新加载工程项目或者更新协议后需要重新更新缓存,更新总是会卡住,就算不卡住也要耗费四五个小时,严重影响了开发效率。
针对以上问题,有几个处理办法:
- 换个 IDE,弃用 vscode
- 弃用微软的 C/C++ 插件,选用 clangd 插件进行代码分析。相比于 C/C++,clangd具有全项目索引、代码跳转、变量重命名、更快的代码补全、提示信息、格式化代码等功能,内存占用和资源占用上也更具优势。
笔者选取了第二种方式,并开始了漫漫的踩坑之路。
首先,centos7 不提供 clangd 的 yum 包安装。然后,clangd 属于 llvm 的组件之一,llvm 官方并没有提供 centos7 的 pre-build binary,需要通过源码编译。
以下环境配置基于 GCC 7.1.0 + LLVM-12.0,其他版本尚未测试。
升级 cmake 版本
编译 llvm 需要 cmake 3.13 以上。
# 卸载旧有 cmake 版本
$ sudo yum remove cmake -y
# 从官网下载 cmake 源码进行编译
$ wget https://cmake.org/files/v3.15/cmake-3.15.0.tar.gz
$ tar xvf cmake-3.15.0.tar.gz
$ cd cmake-3.15.0
$ ./configure --prefix=/usr/local/cmake
$ make -j && make install
# 创建软连接
$ sudo ln -s /usr/local/cmake/bin/cmake /usr/bin/cmake
# 配置环境变量
$ vim /etc/profile
export CMAKE_HOME=/usr/local/cmake
export PATH=$PATH:$CMAKE_HOME/bin
# 检查 cmake 版本
$ cmake --version
升级 GCC 版本
为了不影响系统 GCC 配置(毕竟机器上还跑着其他 GCC 的项目),可以从源码单独编译一个 GCC 版本。
# 最好选择 7.1 版本以上的,llvm推荐采用
$ cd ~/packages
$ wget http://ftp.gnu.org/gnu/gcc/gcc-7.1.0/gcc-7.1.0.tar.gz
$ tar -zxvf gcc-7.1.0.tar.gz
# 编译安装
$ cd gcc-7.1.0
$ ./contrib/download_prerequisites
$ cd ..
$ mkdir gcc-7.1.0-build && cd gcc-7.1.0-build
$ ../gcc-7.1.0/configure --prefix=$HOME/packages/GCC-7.1.0 --enable-languages=c,c++,fortran,go -enable-checking=release -disable-multilib
# 这一步耗时较久,请耐心等待
$ make -j
$ make install
GCC 安装目录在 $HOME/packages/GCC-7.1.0。
升级 GLIBC
# 检查动态库
strings /usr/lib64/libstdc++.so.6 | grep GLIBC
clangd-12.0 需求 GLIBC >= v3.4.20,这里输出的版本号应该是不符合的。
# 找到编译 GCC 时生成的动态库
$ find ~/packages/gcc-7.1.0-build -name libstdc++.so*
/data/home/user00/packages/gcc-7.1.0-build/prev-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
/data/home/user00/packages/gcc-7.1.0-build/prev-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.23
/data/home/user00/packages/gcc-7.1.0-build/prev-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so
/data/home/user00/packages/gcc-7.1.0-build/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
/data/home/user00/packages/gcc-7.1.0-build/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.23
/data/home/user00/packages/gcc-7.1.0-build/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so
/data/home/user00/packages/gcc-7.1.0-build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
/data/home/user00/packages/gcc-7.1.0-build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.23
/data/home/user00/packages/gcc-7.1.0-build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so
# 替换动态库
# 1. 检查当前动态库
$ ll /usr/lib64/libstdc++*
lrwxrwxrwx 1 root root 18 Jun 19 2018 /usr/lib64/libstdc++.so.5 -> libstdc++.so.5.0.7
-rwxr-xr-x 1 root root 830776 Mar 6 2015 /usr/lib64/libstdc++.so.5.0.7
lrwxrwxrwx 1 root root 30 May 20 09:57 /usr/lib64/libstdc++.so.6 -> /usr/lib64/libstdc++.so.6.0.19
-rwxr-xr-x 1 root root 995840 Jan 9 2020 /usr/lib64/libstdc++.so.6.0.19
# 2. 复制动态库
$ sudo cp /data/home/user00/packages/gcc-7.1.0-build/stage1-x86_64-pc-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.23 /usr/lib64/
# 3. 删除软链,只删除软链!!不要动 libstdc++.so.6.0.19
$ sudo rm -f /usr/lib64/libstdc++.so.6
# 4. 创建新的软链
$ sudo ln -s /usr/lib64/libstdc++.so.6.0.23 /usr/lib64/libstdc++.so.6
# 5. 再次检查当前动态库
$ ll /usr/lib64/libstdc++*
lrwxrwxrwx 1 root root 18 Jun 19 2018 /usr/lib64/libstdc++.so.5 -> libstdc++.so.5.0.7
-rwxr-xr-x 1 root root 830776 Mar 6 2015 /usr/lib64/libstdc++.so.5.0.7
lrwxrwxrwx 1 root root 30 May 20 09:57 /usr/lib64/libstdc++.so.6 -> /usr/lib64/libstdc++.so.6.0.23
-rwxr-xr-x 1 root root 995840 Jan 9 2020 /usr/lib64/libstdc++.so.6.0.19
-rwxr-xr-x 1 root root 11410559 May 20 09:56 /usr/lib64/libstdc++.so.6.0.23
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBC
编译安装 llvm-clang
# 获取源码
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/llvm-project-12.0.0.src.tar.xz
$ tar xvf llvm-project-12.0.0.src.tar.xz
$ cd llvm-project-12.0.0.src && mkdir build && cd build
# 注意指定 gcc 和 g++ 路径
$ cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_C_COMPILER=$HOME/packages/GCC-7.1.0/bin/gcc -DCMAKE_CXX_COMPILER=$HOME/packages/GCC-7.1.0/bin/c++ -DCMAKE_INSTALL_PREFIX=~/packages/llvm -DCMAKE_BUILD_TYPE=Release -std=c++11 ../llvm
# -j 指定并行编译,最好只指定核数的一半,不然会卡死
$ make -j4
$ make install
# 创建软链
$ sudo ln -s /data/home/user00/packages/llvm/bin/clangd /usr/bin/clangd
# 查看版本号
$ clangd --version
clangd version 12.0.0
vscode 配置 clangd
应用商店中安装 clangd 插件。
注意 C/C++ 插件和 clangd 插件不能同时启用,需要先禁用 C/C++ 插件。
clangd是基于 compile_commands.json
文件来完成对项目的解析,所以需要针对项目生成 compile_commands.json
文件。生成方法有以下三种:
(1) 如果通过 cmake 方式编译项目,在 CMakeLists.txt 文件中 添加 set(CMAKE_EXPORT_COMPILECOMMANDS ON)
,之后 cd build && cmake ..
,可以发现在 build 目录下已经生成了 compile_commands.json
文件
(2) 如果是基于 make 方式来编译,那么可以先安装 pip install compiledb
,之后在当前目录下运行 (a) compiledb -n make -C build (b) compiledb make -C build 这两个命令中的其中一个来生成 compile_commands.json 文件,其中前者不会执行真正的 make 编译命令。
$ pip install compiledb
$ compiledb -n make -C build
(3) 如果是基于其他方式,可以使用 https://github.com/rizsotto/Bear 项目中的方式来生成对应的 compile_commands.json 文件