Centos 7 升级GLIBC 2.37
机房有些2016年前的服务器,因为硬件比较老,尝试装新系统发现各种问题,无奈装回centos7 , 但是现在的很多软件都是依赖新版的glibc,centos 7的 glibc还是2.17,无法运行编译搞了一台,效率太低,所以才有这个文档。
1. 升级 GCC
# 下载
wget https://mirrors.aliyun.com/gnu/gcc/gcc-10.1.0/gcc-10.1.0.tar.gz
tar -zxvf gcc-10.1.0.tar.gz
cd gcc-10.1.0
# 安装依赖(bzip2 用于解压 .tar.bz2)
yum -y install bzip2 gcc-c++
# 自动下载 gmp/mpfr/mpc/isl
./contrib/download_prerequisites
# 编译安装
mkdir build && cd build
../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --prefix=/usr
make -j$(nproc)
make install
验证:
gcc -v
2. 升级 make
wget https://mirrors.aliyun.com/gnu/make/make-4.4.tar.gz
tar -zxvf make-4.4.tar.gz
cd make-4.4
mkdir build && cd build
../configure --prefix=/usr && make -j$(nproc) && make install
验证:
make -v
3. 升级 binutils
wget https://mirrors.aliyun.com/gnu/binutils/binutils-2.30.tar.gz
tar -zxvf binutils-2.30.tar.gz
cd binutils-2.30
./configure --prefix=/usr
make -j$(nproc) && make install
验证(注意:没有 binutils 这个可执行文件!):
ld -v # GNU ld (GNU Binutils) 2.30
as --version # GNU assembler (GNU Binutils) 2.30
4. 升级 bison(含 m4 依赖)
bison 依赖 GNU M4,如果系统没有需要先装 m4。
4.1 安装 m4(如已安装可跳过)
wget https://mirrors.aliyun.com/gnu/m4/m4-1.4.18.tar.gz
tar -zxvf m4-1.4.18.tar.gz
cd m4-1.4.18
./configure --prefix=/usr && make -j$(nproc) && make install
验证:
m4 --version # GNU M4 1.4.18
4.2 安装 bison
wget https://mirrors.aliyun.com/gnu/bison/bison-3.0.1.tar.gz
tar -zxvf bison-3.0.1.tar.gz
cd bison-3.0.1
./configure --prefix=/usr && make -j$(nproc) && make install
验证:
bison --version # GNU Bison 3.0.1
5. 升级 glibc(⚠️ 高风险操作)
5.1 前提:理解危险
glibc 是系统中最底层的库:
/lib64/libc.so.6— C 标准库,所有程序依赖它/lib64/ld-linux-x86-64.so.2— 动态链接器,加载程序的入口
在运行中的系统上直接 make install 替换 glibc,等于飞机飞行中换引擎。
LFS 官方教程是在 chroot 环境 中安装,而不是在宿主机上直接覆盖。
5.2 查看依赖
cd glibc-2.37
cat INSTALL | grep -E "newer|later"
glibc 2.37 依赖:
- GNU make 4.0+
- GCC 6.2+
- GNU binutils 2.25+
- GNU bison 2.7+
- GNU sed 3.02+
- Python 3.4+
- GNU gettext 0.10.36+
5.3 正确安装方式
方式一:安装到独立目录(--prefix=/opt/glibc)
如果只是想在系统上装一个新版 glibc 作为工具链的一部分(而非替换系统 glibc),直接指定独立 prefix:
cd /srv/glibc-2.37
mkdir build && cd build
../configure --prefix=/opt/glibc \
--disable-profile \
--enable-add-ons \
--with-headers=/usr/include \
--with-binutils=/usr/bin
make -j$(nproc)
make install
安装后的目录结构:
/opt/glibc/
├── bin/ # ldd, locale, localedef 等工具
├── include/ # 头文件
├── lib/ # 静态库、crt*.o
├── lib64/ # libc.so.6, ld-linux-x86-64.so.2, libm, libpthread 等
├── sbin/ # ldconfig, zic 等
└── share/ # locale 数据、man
系统 /lib64 完全不受影响,新旧 glibc 各自独立。
如何使用这个独立 glibc:
直接运行已有程序(验证链接)
# 方法一:用新 glibc 的 ld.so 显式启动
/opt/glibc/lib64/ld-linux-x86-64.so.2 \
--library-path /opt/glibc/lib64 \
/bin/ls
# 方法二:设置 LD_LIBRARY_PATH
LD_LIBRARY_PATH=/opt/glibc/lib64 /bin/ls
编译时链接新 glibc
# 方法一:指定动态链接器和 rpath(推荐,固化进 ELF)
gcc -Wl,-rpath,/opt/glibc/lib64 \
-Wl,-dynamic-linker,/opt/glibc/lib64/ld-linux-x86-64.so.2 \
-o myapp myapp.c
# 方法二:用 ld.so 包装编译(适合一次性测试)
/opt/glibc/lib64/ld-linux-x86-64.so.2 \
--library-path /opt/glibc/lib64 \
gcc -o myapp myapp.c
# 方法三:--sysroot(编译整个工具链时常用)
gcc --sysroot=/opt/glibc -o myapp myapp.c
# --sysroot 会在所有搜索路径前自动加 /opt/glibc 前缀:
# 头文件: /opt/glibc/usr/include
# 库文件: /opt/glibc/lib64 或 /opt/glibc/usr/lib64
# 动态链接器: 自动指向 /opt/glibc/lib64/ld-linux-x86-64.so.2
验证编译产物
# 看链接了哪个 libc
ldd ./myapp
# libc.so.6 => /opt/glibc/lib64/libc.so.6 ← 新 glibc
# 看用的是哪个 ld.so
readelf -l ./myapp | grep interpreter
# [Requesting program interpreter: /opt/glibc/lib64/ld-linux-x86-64.so.2]
# 不设 LD_LIBRARY_PATH 也能跑(因为 rpath 固化进去了)
./myapp
实战:用新 glibc 运行 Qwen Code
Qwen Code 是 Node.js 应用,Node 本身动态链接 glibc。让 Qwen Code 跑在新 glibc 上:
# 环境信息(宿主机)
# Qwen Code: /soft/soft/node-v26.5.1/bin/qwen
# Node.js: /soft/soft/node-v26.5.1/bin/node
# 新 glibc: /opt/glibc/lib64/
方法一:LD_LIBRARY_PATH(最简单,临时用)
LD_LIBRARY_PATH=/opt/glibc/lib64 qwen
# 或者显式指定 node
LD_LIBRARY_PATH=/opt/glibc/lib64 /soft/soft/node-v26.5.1/bin/node \
/soft/soft/node-v26.5.1/lib/node_modules/@qwen-code/qwen-code/cli-entry.js
方法二:ld.so 显式启动(无需设环境变量)
/opt/glibc/lib64/ld-linux-x86-64.so.2 \
--library-path /opt/glibc/lib64 \
/soft/soft/node-v26.5.1/bin/node \
/soft/soft/node-v26.5.1/lib/node_modules/@qwen-code/qwen-code/cli-entry.js
方法三:包装脚本(固化配置)
# 创建 ~/bin/qwen-new,写入:
cat > ~/bin/qwen-new << 'EOF'
#!/bin/bash
export LD_LIBRARY_PATH=/opt/glibc/lib64:$LD_LIBRARY_PATH
exec /soft/soft/node-v26.5.1/bin/node \
/soft/soft/node-v26.5.1/lib/node_modules/@qwen-code/qwen-code/cli-entry.js "$@"
EOF
chmod +x ~/bin/qwen-new
# 以后直接用
qwen-new
验证是否跑在新 glibc 上:
# 看 node 进程链接的 libc
LD_LIBRARY_PATH=/opt/glibc/lib64 ldd /soft/soft/node-v26.5.1/bin/node | grep libc
# libc.so.6 => /opt/glibc/lib64/libc.so.6 ← 新 glibc
方式二:chroot(LFS 官方方式)
LFS(Linux From Scratch)的核心思路:在宿主机上构建一套完整的新工具链,安装到一个独立分区或目录,然后 chroot 进去,在那个隔离环境中完成最终构建。这样新 glibc 安装时不会影响宿主机的运行。
# ============================================
# 阶段一:准备工作(在宿主机上)
# ============================================
# 假设目标分区挂载在 /mnt/lfs
export LFS=/mnt/lfs
# 创建目录结构
mkdir -pv $LFS/{bin,etc,lib,lib64,sbin,usr,var}
mkdir -pv $LFS/tools
# 关键:为 chroot 环境建立 ld.so 软链
# (此时 lib64/ 是空的,先指向宿主机的 ld.so 让程序能跑)
case $(uname -m) in
x86_64) mkdir -pv $LFS/lib64 ;;
esac
# ============================================
# 阶段二:安装 glibc 到目标分区(仍在宿主机上)
# ============================================
cd /srv/glibc-2.37
mkdir build && cd build
../configure --prefix=/usr \
--disable-profile \
--enable-add-ons \
--with-headers=/usr/include \
--with-binutils=/usr/bin
make -j$(nproc)
# 关键:DESTDIR 指定安装目标,不碰宿主机的 /lib64
make install DESTDIR=$LFS
# 此时 glibc 文件在:
# $LFS/usr/bin/ — 工具(ldd、locale 等)
# $LFS/lib64/ — libc.so.6、ld-linux-x86-64.so.2 等
# $LFS/usr/include/ — 头文件
# $LFS/usr/lib64/ — 静态库
# ============================================
# 阶段三:chroot 进去(隔离环境,安全操作)
# ============================================
# 挂载内核虚拟文件系统
mount -v --bind /dev $LFS/dev
mount -v --bind /dev/pts $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run
# 进入 chroot
chroot "$LFS" /usr/bin/env -i \
HOME=/root \
TERM="$TERM" \
PS1='(lfs chroot) \u:\w\$ ' \
PATH=/usr/bin:/usr/sbin \
/bin/bash --login
# ============================================
# 阶段四:在 chroot 内完成收尾
# ============================================
# 更新动态链接器缓存
ldconfig
# 验证
ldd --version
/lib64/libc.so.6
三种方式对比:
| ❌ 必踩坑操作 | ✅ 独立 prefix | ✅ LFS chroot | |
|---|---|---|---|
| configure | --prefix=/usr |
--prefix=/opt/glibc |
--prefix=/usr |
| install | 直接覆盖 | 直接安装 | DESTDIR=$LFS |
| 安装位置 | 宿主机 /lib64/ |
/opt/glibc/ |
$LFS/lib64/ |
| 系统 glibc | 被覆盖,半砖 | 不受影响 | 不受影响 |
| 适用场景 | — | 工具链开发 | 构建独立 Linux 系统 |
总结:
--prefix换成系统之外的路径,或者加DESTDIR重定向,核心都是让新 glibc 不要覆盖宿主机的/lib64/。
5.4 踩坑记录:--prefix=/usr 直接覆盖的后果及恢复
症状:make install 过程中 libc.so.6 已替换但 ld.so 未更新,导致:
gcc: relocation error: /lib64/libc.so.6: symbol __tunable_get_val,
version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2
cp: relocation error: /lib64/libpthread.so.0: symbol __libc_dl_error_tsd,
version GLIBC_PRIVATE not defined in file libc.so.6
所有动态链接命令(cp、ls、gcc)全部崩溃。
救命步骤:
你当前的 bash 进程(在安装前已启动)还能用,用 sln 补齐:
cd /srv/glibc-2.37/build
# 1. 先恢复 ld.so(最重要!)
sln elf/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
# 2. 再补齐其他库(用 copy_sln.txt 批量操作)
sln libc.so /lib64/libc.so.6
sln nptl/libpthread.so /lib64/libpthread.so.0
sln math/libm.so /lib64/libm.so.6
sln dlfcn/libdl.so /lib64/libdl.so.2
sln rt/librt.so /lib64/librt.so.1
sln login/libutil.so /lib64/libutil.so.1
sln resolv/libresolv.so /lib64/libresolv.so.2
sln nss/libnss_files.so /lib64/libnss_files.so.2
sln nss/libnss_dns.so /lib64/libnss_dns.so.2
# 3. 收尾
make install && ldconfig
5.5 验证
# 版本
/lib64/libc.so.6 # 应显示 GNU C Library stable release version 2.37
ldd --version # 同上
# 库文件(应该是实体文件,不是软链)
ls -la /lib64/ld-linux-x86-64.so.2
ls -la /lib64/libc.so.6
# 检查系统正常
ldd /bin/ls
ls /
常见错误速查
| 错误 | 原因 | 解决 |
|---|---|---|
binutils -v 找不到命令 |
binutils 是工具集名,不是可执行文件 | 用 ld -v / as --version |
bison configure 报 no acceptable m4 |
缺少 GNU M4 | 先编译安装 m4 |
glibc make install 报 __tunable_get_val relocation error |
libc 已更新但 ld.so 未更新 | 用 sln 补齐 ld.so |
bzip2: Cannot exec |
未安装 bzip2 | yum install -y bzip2 |
no acceptable C compiler |
未装 gcc-c++ | yum install -y gcc-c++ |
6. RPM 封装
编译一次非常耗时,将产物打包成 RPM 可在同版本 CentOS 7 上一键安装。
6.1 前置条件
# 安装打包工具
yum install -y rpm-build rpmdevtools
# 创建 rpmbuild 目录结构
rpmdev-setuptree
# 生成目录:~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
6.2 通用打包方法
核心思路:用 make install DESTDIR=/tmp/pkg-XXX 收集文件清单(不覆盖系统),然后写 spec 用 rpmbuild 打包。
# 1. 收集文件(以 glibc 为例)
cd /srv/glibc-2.37/build
rm -rf /tmp/pkg-glibc
make install DESTDIR=/tmp/pkg-glibc
# 2. 删除污染文件
rm -f /tmp/pkg-glibc/usr/share/info/dir
# 3. 生成文件清单(包含软链接)
files=$(find /tmp/pkg-glibc -not -type d \
| sed 's|^/tmp/pkg-glibc||' \
| grep -v '^/usr/share/info/dir$' \
| sort)
# 4. 写入 spec 的 %files 段
6.3 spec 关键要点
⚠️ Provides/Conflicts 必须写在 %description 之前
RPM 的 preamble(Name, Version, Provides, Conflicts 等)必须在 %description 之前,否则会被忽略。
Name: glibc
Version: 2.37
Provides: rtld(GNU_HASH) # ✅ 在 %description 前面
Conflicts: glibc-common < 2.30
%description # ← preamble 在此结束
GNU C Library 2.37...
glibc 特殊处理
glibc 替换系统最底层库,需要声明大量 Provides 和 Obsoletes:
rtld(GNU_HASH):最关键!几乎所有系统包都依赖它,RPM 不会自动从ld-linux-x86-64.so.2检测到这个标记,必须手动声明glibc-common/headers/devel:替代旧的子包,Obsoletes自动卸载旧版本libcidn.so.1,libnss_nis.so.2,libnss_nisplus.so.2:glibc 2.34+ 中已移除的库,旧glibc-devel依赖它们,需要声明空 Provideslocale-archive:需要从编译 VM 的/usr/lib/locale/locale-archive手动拷贝进 buildroot,make install DESTDIR不会生成它%post脚本:必须用localedef重新注册 locale 数据
%post
if [ -x /usr/bin/localedef ] && [ -f /usr/share/i18n/locales/zh_CN ]; then
/usr/bin/localedef -i zh_CN -f UTF-8 zh_CN.utf8 2>/dev/null || true
fi
exit 0
gcc 特殊处理
libgcc_s.so.1()(64bit):CentOS 7 的 RPM 自动检测会跳过这个库,必须手动声明所有 GCC_ 版本标记Obsoletes:声明替代旧的libstdc++、libgcc、libgomp- 部分组件失败:
make install时 libgfortran 可能因 SIGSTKSZ 宏兼容性报错,用make -k install(忽略错误继续)仍能收集 1500+ 文件,核心的 cc1/cc1plus/gcc/g++ 都在
Provides: libgcc_s.so.1()(64bit)
Provides: libgcc_s.so.1(GCC_3.0)(64bit)
Provides: libgcc_s.so.1(GCC_3.3)(64bit)
Provides: libgcc_s.so.1(GCC_3.3.1)(64bit)
Provides: libgcc_s.so.1(GCC_3.4)(64bit)
Provides: libgcc_s.so.1(GCC_4.2.0)(64bit)
Obsoletes: libstdc++ < 10
Obsoletes: libgcc < 10
Obsoletes: libgomp < 10
make 特殊处理
CentOS 7 的 make 有 Epoch 1,必须声明 Epoch: 1,否则 RPM 认为 1:3.82 > 4.4。
Name: make
Epoch: 1
Version: 4.4
bison 特殊处理
make install 因 SIGSTKSZ 兼容性失败,二进制文件不会进入 DESTDIR。需要从编译 VM 的 /usr/bin/bison 手动拷贝,并创建 yacc -> bison 软链接。
m4 特殊处理
m4 源码同样不兼容 glibc 2.37 的 SIGSTKSZ。直接从系统 /usr/bin/m4 和 /usr/share/man/man1/m4.1 手动收集即可。
6.4 构建命令
# 每个包执行(以 glibc 为例)
cd ~/rpmbuild/SPECS
rpmbuild -bb --noclean --buildroot /tmp/pkg-glibc glibc.spec
# --noclean 防止 buildroot 被清理(方便重试)
# -bb 只构建二进制 RPM,不构建 SRPM
6.5 安装(⚠️ 注意事项)
# 首次安装:一次安装全部(RPM 会自动处理依赖和顺序)
rpm -Uvh --replacefiles ./*.rpm
重要规则:
| ❌ 禁止 | ✅ 正确做法 |
|---|---|
rpm -Uvh ./*.rpm 在已安装后再次全部重装 |
只重装变化的单个包 |
yum install glibc-langpack-zh 或任何 yum install glibc-* |
locale 问题用 localedef 修复 |
make install 替换 glibc 中途 kill rpm 进程 |
先用 kill -9 + rm -f /var/lib/rpm/__db.* + rpm --rebuilddb 恢复 |
为什么不能重装全部: glibc 的 %post 运行 ldconfig,六个 RPM 同时触发可能导致死锁。
为什么不能 yum install glibc-*: yum 源里是 CentOS 7 的 glibc 2.17,会覆盖工具链的 2.37。
6.6 locale 修复
如果安装后 locale -a 只有 C 和 POSIX:
# 原因:locale-archive 注册信息与目标系统不匹配
localedef -i zh_CN -f UTF-8 zh_CN.utf8
locale -a | grep zh_CN # 验证
新版 glibc RPM 的
%post已自动执行此步骤。
6.7 RPM 打包踩坑速查
| 错误 | 原因 | 解决 |
|---|---|---|
Installed (but unpackaged) file(s) found |
buildroot 里有文件未在 %files 中列出 |
补全文件清单或用 --noclean 保留 buildroot 排查 |
| Provides 不生效 | 写在了 %description 之后 |
移到 %description 前面 |
glibc-common < 2.30 冲突 |
用了 Conflicts |
改用 Obsoletes + Provides |
rtld(GNU_HASH) 缺失 |
RPM 不自动检测 ld.so 的这个标记 | 手动添加 Provides: rtld(GNU_HASH) |
libgcc_s.so.1 缺失 |
CentOS 7 RPM 不自动检测 libgcc_s | 手动添加所有版本标记 |
make-3.82 比 make-4.4 新 |
系统 make 有 Epoch 1 | spec 添加 Epoch: 1 |
| 重装全部 RPM 后卡死 | 多个 glibc %post 并发死锁 | 只重装变化的单个包;如果已卡死:kill -9 rpm 进程 → rm -f /var/lib/rpm/__db.* → rpm --rebuilddb |
locale 报"无法将 LC_ALL 设置为默认的语区" |
locale-archive 注册不匹配 | localedef -i zh_CN -f UTF-8 zh_CN.utf8 |
7. 验证:实战安装 Qwen Code CLI
在升级后的 CentOS 7(glibc 2.37 + gcc 10.1.0)上安装 Qwen Code 验证工具链可用性:
# 安装 Qwen Code(Node.js 应用,依赖 glibc)
curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.sh | bash
# 加载环境变量
source ~/.bashrc
# 验证版本
qwen -v
# 输出: 0.21.10
# 启动正常
qwen
Qwen Code 是 Node.js 应用,Node 二进制动态链接 glibc。能在 glibc 2.37 上正常安装和运行,说明工具链 ABI 兼容正常,
libc.so.6、libpthread.so.0、libdl.so.2、libstdc++.so.6等关键库工作正常。
写到最后:
如果有不想麻烦折腾编译的朋友,我这里有封装好的: https://download.csdn.net/download/dzminglong/93261163
更多推荐


所有评论(0)