背景
glibc 是 GNU 发布的 libc 库,即 c 运行库。glibc 是 linux 系统中最底层的 api,几乎其它任何运行库都会依赖于glibc。glibc除了封装 linux 操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX 通行的标准,可以想见其内容包罗万象。而就像其他的 UNIX 系统一样,其内含的档案群分散于系统的树状目录结构中,像一个支架一般撑起整个操作系统。在 GNU/Linux 系统中,其 C 函数库发展史点出了GNU/Linux 演进的几个重要里程碑,用 glibc 作为系统的 C 函式库,是 GNU/Linux 演进的一个重要里程碑。
而当前在面对 nodejs 18 时就出现了 glibc 版本过旧的问题导致不得不对其进行升级。
特别注意
错误地升级 glibc 会导致系统工具失效甚至系统崩溃,
请谨慎操作
以下全部操作都是用 root 账户进行的
推荐全程在 screen 中运行,防止意外断开造成不可意料的后果
glibc 不可用会导致:bash 无法使用、yum/rpm 无法使用、无法解析名称空间、无法切换用户等,基本相当于系统不可用。同样的,如果有其他工具服务依赖 glibc,也会因此造成不可用。
升级流程
1.安装Python-3.7.11
本次安装基于一键脚本实现 Python-3.7.11 版本安装。
创建脚本文件
vim py3_auto_install.sh
脚本内容
#!/bin/bash
# Author: nestealin
# Created: 2022-12-11
# Update: 2023-05-13 change openssl version from 1.1.1a to 1.1.1k
# Update: 2023-09-23 promt Python and Openssl version to variables
command=$1
install_script_dir="$( cd "$( dirname "$0" )" && pwd )"
packages_dir="$install_script_dir/packages"
PYTHON_VERSION="3.7.11"
PYTHON_MAIN_VERSION=$(echo "$PYTHON_VERSION" | cut -d. -f1-2)
OPENSSL_VERSION="1.1.1k"
# EnvPrepare
function Setup_Install_Env() {
yum install gcc zlib-devel make libffi-devel -y
yum install -y ca-certificates
[ ! -d $packages_dir ] && mkdir $packages_dir
echo -e "\033[32mpackages directory: $packages_dir\033[0m"
}
# Download Packages
function Download_Python_Package() {
cd $packages_dir
tarball="Python-${PYTHON_VERSION}.tar.xz"
if [ ! -f $tarball ]; then
echo "Downloading $tarball"
wget https://www.python.org/ftp/python/${PYTHON_VERSION}/$tarball
[ ! -f $tarball ] && echo -e "\033[31mfail to download $tarball\033[0m" && exit 1
fi
}
function Download_Openssl_Packages() {
cd $packages_dir
tarball="openssl-${OPENSSL_VERSION}.tar.gz"
if [ ! -f $tarball ]; then
echo "Downloading $tarball"
wget https://www.openssl.org/source/$tarball
echo "Downloading cacert.pem"
wget http://curl.haxx.se/ca/cacert.pem
[ ! -f $tarball ] && echo -e "\033[31mfail to download $tarball\033[0m" && exit 1
fi
}
function Download_Pip3_Package() {
cd $packages_dir
tarball="ez_setup.py"
if [ ! -f $tarball ]; then
echo "Downloading $tarball"
wget https://bootstrap.pypa.io/$tarball --no-check-certificate
[ ! -f $tarball ] && echo -e "\033[31mfail to download $tarball\033[0m" && exit 1
fi
}
function Install_Openssl() {
install_dir="/usr/local/openssl-${OPENSSL_VERSION}"
cd $packages_dir
tarball="openssl-${OPENSSL_VERSION}.tar.gz"
tar -zxvf $tarball
cd openssl-${OPENSSL_VERSION}
./config --prefix=$install_dir --openssldir=$install_dir
make -j `cat /proc/cpuinfo | grep -i name | wc -l` && make install
if [ -d $install_dir ]; then
mv $packages_dir/cacert.pem /usr/local/openssl-${OPENSSL_VERSION}/cert.pem
echo "/usr/local/openssl-${OPENSSL_VERSION}/lib" > /etc/ld.so.conf.d/openssl-${OPENSSL_VERSION}-x86_64.conf
ldconfig
[ ! -d $install_dir ] && echo -e "\033[31mfail to install $install_dir\033[0m" && exit 1
fi
}
function Install_Python3() {
install_dir="/usr/local/python-${PYTHON_VERSION}"
openssl_dir="/usr/local/openssl-${OPENSSL_VERSION}"
cd $packages_dir
tar xvf Python-${PYTHON_VERSION}.tar.xz
cd Python-${PYTHON_VERSION}
./configure --prefix=/usr/local/python-${PYTHON_VERSION} --enable-optimizations --with-openssl=$openssl_dir
make -j `cat /proc/cpuinfo | grep -i name | wc -l` && make install
if [ -d $install_dir ]; then
ln -s /usr/local/python-${PYTHON_VERSION} /usr/local/python3
ln -s /usr/local/python-${PYTHON_VERSION}/bin/python${PYTHON_MAIN_VERSION} /usr/bin/python3
ln -s /usr/local/python-${PYTHON_VERSION}/bin/pip3 /usr/bin/pip3
[ ! -d $install_dir ] && echo -e "\033[31mfail to install $install_dir\033[0m" && exit 1
fi
}
function Install_Pip3() {
install_dir="/usr/local/python-${PYTHON_VERSION}/bin"
cd $packages_dir
if [ -d $install_dir ]; then
$install_dir/python3 ez_setup.py
[ ! -d $install_dir ] && echo -e "\033[31mfail to install $install_dir\033[0m" && exit 1
fi
}
function Install_Virtualenv() {
install_dir="/usr/local/python-${PYTHON_VERSION}/bin"
if [ -d $install_dir ]; then
$install_dir/pip3 install virtualenv virtualenvwrapper
[ ! -d $install_dir ] && echo -e "\033[31mfail to install $install_dir\033[0m" && exit 1
fi
virtualenvwrapper_script="virtualenvwrapper.sh"
if [ -f $install_dir/virtualenvwrapper.sh ]; then
mkdir -p /data1/virtualpython/virtualenvs && mkdir /data1/virtualpython/PyEnv
mkdir -p /data1/virtualpython_others/virtualenvs && mkdir /data1/virtualpython_others/PyEnv
env=$(cat <<EOF >>~/.bashrc
# 为非root用户提供
if [ `id -u` != '0' ]; then
export WORKON_HOME=/data1/virtualpython_others/virtualenvs
export PROJECT_HOME=/data1/virtualpython_others/PyEnvs
source /usr/local/python-${PYTHON_VERSION}/bin/virtualenvwrapper.sh
fi
# 如果root用户添加如下:
export WORKON_HOME=/data1/virtualpython/virtualenvs
export PROJECT_HOME=/data1/virtualpython/PyEnvs
export VIRTUALENVWRAPPER_PYTHON=/usr/local/python-${PYTHON_VERSION}/bin/python${PYTHON_MAIN_VERSION}
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/python-${PYTHON_VERSION}/bin/virtualenv
source /usr/local/python-${PYTHON_VERSION}/bin/virtualenvwrapper.sh
EOF
)
$env
source ~/.bashrc
[ ! -f $install_dir/virtualenvwrapper.sh ] && echo -e "\033[31mfail to install virtualenvwrapper.sh\033[0m" && exit 1
fi
}
# HELP,-p|--python-only 仅安装python,默认项 , -v|--with-virtualEnv 虚拟环境
function help()
{
echo -e "\033[31musage: $0 Options: [-d|-p] [-v]\033[0m"
echo -e "\033[31mOPTIONS:\033[0m"
echo -e "\033[31m -d|-p|--python-only install python only, Default option\033[0m"
echo -e "\033[31m -v|--with-virtualEnv instal python with virtualEnv\033[0m"
}
case $command in
(-d|-p|--python-only)
Setup_Install_Env
Download_Openssl_Packages
Install_Openssl
Download_Python_Package
Download_Pip3_Package
Install_Python3
Install_Pip3
;;
(-v|--with-virtualEnv)
Setup_Install_Env
Download_Openssl_Packages
Install_Openssl
Download_Python_Package
Download_Pip3_Package
Install_Python3
Install_Pip3
Install_Virtualenv
;;
(-h|--help|help)
help
;;
(*)
echo "Error command"
help
;;
esac
执行安装
chmod +x py3_auto_install.sh
./py3_auto_install.sh -d
2.升级make-4.3
在阿里云镜像上找到想要升级的 make 版本,这里以 4.3
为例
wget https://mirrors.aliyun.com/gnu/make/make-4.3.tar.gz tar -zxf make-4.3.tar.gz
cd make-4.3/
mkdir build
cd build
../configure --prefix=/usr && make && make install
make -v
3.升级gcc-8.2.0
安装依赖
# 未安装c编译器报错
# no acceptable C compiler found in $PATH
yum -y install bison wget bzip2 gcc gcc-c++ glibc-headers
下载源码
# 下载并解压
wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-8.2.0/gcc-8.2.0.tar.gz --no-check-certificate
tar xf gcc-8.2.0.tar.gz
cd gcc-8.2.0
# 下载gmp mpfr mpc等供编译需求的依赖项
./contrib/download_prerequisites
mkdir build
cd build
编译安装
../configure --prefix=/usr/local/gcc-8.2.0 --enable-bootstrap --enable-checking=release --enable-languages=c,c++ --disable-multilib
make -j `cat /proc/cpuinfo | grep "model name" | wc -l`
make install
sudo ln -sv /usr/local/gcc-8.2.0/include/ /usr/include/gcc
编译参数释义:
../configure
: 跨上一级文件夹编译器配置;--prefix=/usr/local/gcc-8.2.0
: 指定安装目录;--enable-checking=release
: 在编译器中执行内部一致性检查;--enable-languages=c,c++
: 指定支持的语言;--disable-multilib
: 禁止编译适用于多重架构体系的库,就是 X86 X64 兼容之类的;
更新环境
移除旧版本
yum -y remove gcc g++
配置新版本全局可用
ln -s /usr/local/gcc-8.2.0/bin/gcc /usr/bin/gcc
ln -s /usr/local/gcc-8.2.0/bin/g++ /usr/bin/g++
更新动态库
# 查看当前的动态库
strings /usr/local/gcc-8.2.0/lib64/libstdc++.so.6 | grep CXXABI
# 更改动态库
cp /usr/local/gcc-8.2.0/lib64/libstdc++.so.6.0.25 /usr/lib64/
ldconfig
# 查看更新后的默认动态库
strings /usr/lib64/libstdc++.so.6 | grep CXXABI
版本检查
# 查看安装库
cd /usr/lib64 && ll libstdc++*
# 或者gcc --version
gcc -v
4.升级glibc-2.31
下载源码
- 官方下载地址: http://ftp.gnu.org/gnu/glibc/
- 阿里云镜像站: gnu-glibc安装包下载_开源镜像站-阿里云
wget https://mirrors.aliyun.com/gnu/glibc/glibc-2.31.tar.gz
tar -zxf glibc-2.31.tar.gz
cd glibc-2.31/
# 检查依赖的,没有更新的都yum -y install一下,之前装过的就不 用了
cat INSTALL | grep -E "or newer|or later"
编译安装
# 修改 scripts/test-installation.pl 避免引发安装问题
sed -e '128s/.*/ \&\& \$name ne "nss_test1" \&\& \$name ne "nss_test2" \&\& \$name ne "libgcc_s") {/' scripts/test-installation.pl > tmpfile && mv tmpfile scripts/test-installation.pl
mkdir build
cd build
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin --disable-sanity-checks --disable-werror --enable-obsolete-nsl
make -j `cat /proc/cpuinfo | grep "model name" | wc -l`
make install
make localedata/install-locales -j `cat /proc/cpuinfo | grep "model name" | wc -l`
编译参数释义:
../configure
: 跨上一级文件夹编译器配置;--prefix=/usr
: 指定安装目录,切勿修改;--disable-profile
: 关掉 profiling 信息相关的库文件编译;--enable-add-ons
: 指示 glibc 使用附加的 NPTL 包作为线程库;--with-headers=/usr/include
: 指示 glibc 按照这个目录中的内核头文件编译自己,从而精确的知道内核的特性以根据这些特性对自己进行最佳化编译;--with-binutils=/usr/bin
: 保证在编译 glibc 时不会用错 Binutils;
如果出现如下报错,可以忽略:
版本检查
# 检查
ldd --version
strings /lib64/libc.so.6 | grep GLIBC
至此,如果没有出现其他报错,则代表升级完成。
可能出现的问题
1.glibc在make install时出现”cannot find -lnss_test2”报错
/bin/ld: cannot find -lnss_test2
collect2: error: ld returned 1 exit status
Execution of gcc failed!
The script has found some problems with your installation!
Please read the FAQ and the README file and check the following:
- Did you change the gcc specs file (necessary after upgrading from
Linux libc5)?
- Are there any symbolic links of the form libXXX.so to old libraries?
Links like libm.so -> libm.so.5 (where libm.so.5 is an old library) are wrong,
libm.so should point to the newly installed glibc file - and there should be
only one such link (check e.g. /lib and /usr/lib)
You should restart this script from your build directory after you've
fixed all problems!
Btw. the script doesn't work if you're installing GNU libc not as your
primary library!
make[1]: *** [Makefile:120: install] Error 1
make[1]: Leaving directory '/tmp/glibc-2.31'
make: *** [Makefile:12: install] Error 2
这个报错网上说可以忽略,但实际上在机器作为 jenkins slave 时会因为环境问题导致无法被 master 接管,在条件允许的情况下应该考虑解决这个错误。
当然,也可以在编译时想办法消除该告警,可以参考如下操作。
解决方式
在 glibc 源码目录下修改 scripts/test-installation.pl
文件约 128 行内容:
参考如下操作:
cd /tmp/glibc-2.31
sed -i '128s/.*/ \&\& \$name ne "nss_test1" \&\& \$name ne "nss_test2" \&\& \$name ne "libgcc_s") {/' scripts/test-installation.pl
然后清理编译数据重新执行编译即可
cd /tmp/glibc-2.31
rm -rf build
mkdir build
cd build
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin --disable-sanity-checks --disable-werror --enable-obsolete-nsl
make -j `cat /proc/cpuinfo | grep "model name" | wc -l`
make install
make localedata/install-locales
2.系统登陆后出现”cannot change locale”
在忽略”cannot find -lnss_test2”报错,升级完 glibc 以后,每次在登录操作系统后都会出现一个提示:
-bash: warning: setlocale: LC_TIME: cannot change locale (en_US.UTF-8)
以上提示可以有三种解决方式,推荐使用”解决方式3“。
解决方式
- (临时)解决方式1: 在区域文件中添加 LC_TIME,具体为编辑文件
/etc/locale.conf
,命令:
vi /etc/locale.conf
内容为:
LANG="en_US.UTF-8"
LC_TIME="POSIX"
重新登陆后告警消失。
- (临时)解决方式2: 但是如果你已经删除了编译 glibc 的 build 目录或者不知道 build 的目录在哪里,请按照以下步骤:
查看 libc.so.6 软连接指向
ls -la /lib64/libc.so.6
# >>> 终端输出
/lib64/libc.so.6 -> libc-2.14.so
查看 locale-archive 归档文件目录
strings /lib64/libc.so.6 | grep locale-archive
# >>> 终端输出
/usr/local/glibc-2.14/lib/locale/locale-archive
这个目录是在升级 libc 的时候 build 的目录
添加软链接
ls -la /usr/local/glibc-2.14/lib/locale/locale-archive
发现文件并不存在,那么
ln -s /usr/lib/locale/locale-archive /usr/local/glibc-2.14/lib/locale/locale-archive
重新执行 locale
已经正常了 !
- (永久,推荐)解决方式3: 如果你还没有删除 glibc 的编译目录,则进入 glibc 的编译目录,也就是 build 目录执行
make localedata/install-locales
即可解决。
cd /tmp/glibc-2.31/build
make localedata/install-locales -j `cat /proc/cpuinfo | grep "model name" | wc -l`
注: 在主机没有重 CPU 任务负载时,建议增加
-j
参数提高编译效率,该步骤非常耗时。
# 省略过程输出
...
zh_CN.GB18030... done
zh_CN.GBK... done
zh_CN.UTF-8... done
zh_CN.GB2312... done
zh_HK.UTF-8... done
zh_HK.BIG5-HKSCS... done
zh_SG.UTF-8... done
zh_SG.GBK... done
zh_SG.GB2312... done
zh_TW.EUC-TW... done
zh_TW.UTF-8... done
zh_TW.BIG5... done
zu_ZA.UTF-8... done
zu_ZA.ISO-8859-1... done
done
done
done
done
done
done
done
make[2]: Leaving directory '/tmp/glibc-2.31/localedata'
make[1]: Leaving directory '/tmp/glibc-2.31'
待编译完成后即可解决该问题。
3.升级glibc后系统命令无法使用
如果 glibc 挂了会导致系统很多命令不可用
ls ls: error while loading shared libraries: /lib64/libc.so.6: invalid ELF header
可以使用一个正常的 libc 进行恢复,注意此时 ln 命令已经不可用,但 sln 还可以使用
sln /lib64/libc-2.17.so /lib64/libc.so.6
4.glibc安装时出现动态库报错undefined reference to '_nsl_default_nss@GLIBC_PRIVATE'
这个看下nis/Makefile
71 ifeq ($(build-obsolete-nsl),yes)
72 libnsl-routines += nss-default
在编译阶段 configure
增加 --enable-obsolete-nsl
参数即可
# configure --help
--enable-obsolete-nsl build and install the obsolete libnsl
library and depending NSS modules
按照下面格式重新调整一下,重新编译就可以了
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin --disable-sanity-checks --disable-werror --enable-obsolete-nsl
5.升级glibc后yum执行无任何反应
原因
- 可能是因为 rpm 数据库有问题导致卡死。
解决方式
rm -f /var/lib/rpm/__db.00*
rpm --rebuilddb
yum clean all
rm -f /var/lib/rpm/__db.00*
: 删除 rpm 数据库文件;rpm --rebuilddb
: 重建 rpm 数据库;yum clean all
: 清理可能的缓存;
然后你的 yum 应该能用了。
6.遇到 lib64/libstdc++.so.6: undefined symbol: libiconv
原因
- libstdc++ 版本不匹配。
解决方式
将 libstdc++ 的软连接改回老版本
cd /lib64
rm -rf libstdc++.so.6
ln -s libstdc++.so.6.0.19 libstdc++.so.6
7.遇到 Error: /usr/lib64/libstdc++.so.6: version CXXABI_1.3.*' not found
原因
- libstdc++ 版本不够新
解决方式
首先找到你的 gcc
源码编译文件夹,比如我的在 /tmp/gcc-8.2.0
,然后将最新的 libstdc++.so.6 复制到 /usr/lib64/
cd /tmp/gcc-8.2.0/build/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs
cp libstdc++.so.6.0.25 /usr/lib64/
cd /usr/lib64
rm -rf libstdc++.so.6
ln -s libstdc++.so.6.0.25 libstdc++.so.6
rm -rf libstdc++.so.6
: 删除老的软连接;ln -s libstdc++.so.6.0.25 libstdc++.so.6
: 将新版本的 libstdc++.so.6.0.25 软连接到 libstdc++.so.6;
Reference
CentOs7升级gcc、glibc | PasseRR’s Blog
GCC编译环境升级部署_-lnss_test2-CSDN博客