CentOS系统升级GCC-8.2.0及GLIBC-2.31


背景

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

下载源码

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安装glibc-2.29_卓力特

Glibc 版本 not found

CentOs7升级gcc、glibc | PasseRR’s Blog

GCC编译环境升级部署_-lnss_test2-CSDN博客

CentOS7升级Glibc到2.28 - 风继续吹

CentOS 升级libc后导致中文乱码 locale: Cannot set LC_CTYPE to default locale: No such file or directory - jasondayee - 博客园

centos7 glibc2.17升级到glibc2.28_glibc 2.28-CSDN博客

centos7 升级 glibc && gcc – GarlicSpace


文章作者: NesTeaLin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 NesTeaLin !
  目录