背景
项目基于 C 语言,代码量庞大,并基于 vscode 的 C/C++ 插件实现代码跳转。
开发过程中发现代码补全,跳转等功能存在问题,经常出现匹配不上或者跳转不准确的问题。每次重新加载工程项目或者更新协议后需要重新更新缓存,更新总是会卡住,就算不卡住也要耗费四五个小时,严重影响了开发效率。
针对以上问题,有几个处理办法:
- 换个 IDE,弃用 vscode
- 弃用微软的 C/C++ 插件,选用 clangd 插件进行代码分析。相比于 C/C++,clangd具有全项目索引、代码跳转、变量重命名、更快的代码补全、提示信息、格式化代码等功能,内存占用和资源占用上也更具优势。
笔者选取了第二种方式,并开始了漫漫的踩坑之路。
首先,开发机(DevCloud) 基于 tLinux 2.2(centos 7),不提供 clangd 的 yum 包安装。然后,clangd 属于 llvm 的组件之一,llvm 官方并没有提供 centos7 的 pre-build binary,需要通过源码编译。
以下环境配置基于 GCC 7.1.0 + LLVM-12.0,其他版本尚未测试。
升级 cmake 版本
编译 llvm 需要 cmake 3.13 以上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| # 卸载旧有 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 版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| # 最好选择 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
1 2
| # 检查动态库 strings /usr/lib64/libstdc++.so.6 | grep GLIBC
|
clangd-12.0 需求 GLIBC >= v3.4.20,这里输出的版本号应该是不符合的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| # 找到编译 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| # 获取源码 $ 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
文件。生成方法有以下三种:
如果通过 cmake 方式编译项目,在 CMakeLists.txt
文件中 添加 set(CMAKE_EXPORT_COMPILECOMMANDS ON)
,之后 cd build && cmake ..
,可以发现在 build
目录下已经生成了 compile_commands.json
文件
如果是基于 make 方式来编译,那么可以先安装 pip install compiledb
,之后在当前目录下运行(1) compiledb -n make -C build
(2) compiledb make -C build
这两个命令中的其中一个来生成 compile_commands.json
文件,其中前者不会执行真正的make编译命令。
1 2
| $ pip install compiledb $ compiledb -n make -C build
|
如果是基于其他方式,可以使用 https://github.com/rizsotto/Bear
项目中的方式来生成对应的 compile_commands.json
文件
参考资料
- centos升级和安装cmake - 知乎
- 在 alios7 上安装 clangd - 知乎
- 使用clangd替代c/c++配置vscode c++项目 - 知乎
- LLVM+Clang+centos编译第一个openmp程序_静坐思己过的博客-程序员宝宝 - 程序员宝宝
- llvm编译失败几句话总结 - voyage1969 - 博客园
- How to choose llvm prebuild version under centos7.2 - Questions - Apache TVM Discuss