CentOS 7运行clangd 16

微软官方的VSCode C++插件是单线程模式,在扫描大型工程的时候速度特别慢。所以我一直用vscode-clangd插件。

但是clangd的最低要求是glibc 2.18。在一些比较老的系统上,比如CentOS 7,只有glibc 2.17。这会导致新版的clangd无法启动:

1
./bin/clangd: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by ./bin/clangd)

CentOS官方源里只有clangd 7,版本太老,无法运行vscode-clangd插件。

我折腾了好几天,试着找到了一种相对简单的方法,足够让clangd和vscode-clangd插件跑起来,也不破坏系统glibc,也不编译LLVM或GCC。

本文使用的系统是CentOS 7(VMWare Player 17),clangd版本为16.0.2

原理解释

对原理不感兴趣的可以直接跳过这部分。

我在网上找到的方法大致分为三种:

  1. 升级系统的glibc。这种方法比较危险,很容易导致系统无法启动。
  2. 自己编译clangd。且不谈编译得到的clangd能否正确支持VSCode。这需要用cmake 3.x编译LLVM工具链。然而,CentOS 7只自带cmake 2.x。所以你首先要升级cmake等工具链。而且自己编译的clangd依然要依赖于glibc,本质上还是没解决问题。
  3. 使用容器或虚拟机在CentOS 8里看代码。这样写代码和跑代码的环境不一致,也很不方便。

根据官方的说法,clangd不会引入对glibc 2.17的支持,所以如果想用官方提供的binary,glibc 2.18是绕不开的。

但clangd除了glibc 2.18,没有其它的运行库依赖。可以用ldd命令列出clangd需要的动态运行库。看上去列出了一大堆,其实都是glibc的库:

1
2
3
4
5
6
7
8
9
10
[yaland@localhost clangd_16.0.2]$ ldd -r bin/clangd
bin/clangd: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by bin/clangd)
linux-vdso.so.1 => (0x00007ffde5be4000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f6cac8ab000)
librt.so.1 => /lib64/librt.so.1 (0x00007f6cac6a3000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f6cac49f000)
libm.so.6 => /lib64/libm.so.6 (0x00007f6cac19d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6cabdcf000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6cacac7000)
symbol __cxa_thread_atexit_impl, version GLIBC_2.18 not defined in file libc.so.6 with link time reference (bin/clangd)

所以理论上,除了glibc 2.18,其它任何东西都不需要自己重新编译。

单独替换libc.so的版本不行。我试过用LD_LIBRARY_PATH强制加载新版本的libc.so这一个文件,会报一些莫名其妙的错误。因为glibc里的各种库(包括加载程序使用的ld.so)是一个整体,不同版本的是不兼容的。

此外,ld.so搜索glibc库文件的路径是写死在代码里的。所以你必须要指定一个目录,把glibc编译和安装进去,它才能正常使用。

因此我的方法是:编译一个仅用于运行clangd的glibc 2.18,安装到自己的目录里,然后让clangd在运行时动态链接上去。

执行过程

需要安装GCC、GNU make等编译工具。一般这些都是系统自带的。如果没有的话也可以通过yum安装。

CentOS 7自带GNU Make 3.82和GCC 4.8.5。

编译GLIBC 2.18

GNU官网下载glibc速度很慢。我这里用的是清华的镜像。

注意:本过程不需要root权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 下载
wget https://mirrors.tuna.tsinghua.edu.cn/gnu/glibc/glibc-2.18.tar.gz

# 解压
tar -zxf glibc-2.18.tar.gz
cd glibc-2.18

# 创建一个build目录方便编译
mkdir build
cd build

# prefix选择一个自己的目录
# glibc之后会被安装到这个目录
../configure --prefix=/home/yaland/mylibc

# 编译和安装
make -j4 && make install

你可以验证一下你的glibc是否安装成功:

1
2
3
4
5
# 跳转到你刚才选择的glibc 2.18安装目录
cd /home/yaland/mylibc/

# 检查glibc版本
./bin/ldd --version

它应该输出如下内容:

1
2
3
4
5
ldd (GNU libc) 2.18
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

用自己的ld.so运行clangd

在编译好的glibc的lib目录下有个ld-2.18.so,用它运行clangd:

1
/home/yaland/mylibc/lib/ld-2.18.so  /path/to/clangd

clangd已经可以正常启动了:

image-20230722114601766

你可以把这行命令写成可执行的shell脚本,就可以供VSCode插件使用。

参考文章

GLIBCs not found on host · Issue #16 · clangd/vscode-clangd

安装clangd:‘GLIBC_2.18‘ not found解决 - 李响Superb的技术博客 - 51CTO博客

Compile and install GLIBC 2.18 in CentOS 7

关于不同版本 glibc 更换的一些问题-Pwn-看雪-安全社区|安全招聘|kanxue.com

c - Can LD_PRELOAD be used to load different versions of glibc? - Stack Overflow


CentOS 7运行clangd 16
https://yalandhong.github.io/2023/07/23/cpp/centos7_clangd/
作者
Yaland Hong
发布于
2023年7月23日
许可协议