GCC 源码编译安装(离线,普通用户)
gcc 的非 root 用户离线编译安装比其他的软件的源码安装都要复杂:因为它有依赖,在服务器上无法通过联网下载,要提前下载依赖的压缩包,而且gcc的编译时间很长。
安装过程主要参考CentOS7 离线升级安装gcc到6.3.0 和Linux 非root安装GCC9.1.0
下载依赖
在官网或者镜像网站下载 gcc-11.4.0.tar.gz,传到服务器上解压为
~/tmp/gcc-11.4.0
进入
~/tmp/gcc-11.4.0
子目录,需要解决下载依赖的问题。在可以联网的情况下,直接执行自带的下载依赖的脚本./contrib/download_prerequisites
。如果服务器无法联网,则需要手动下载处理查看上述脚本,找到四个必要的依赖 gmp,mpfr,mpc,isl 以及对应的具体版本,例如 gcc-11.4.0 需要的四个依赖版本及其下载地址如下(不同版本的gcc对应的依赖版本也不一样)
1
2
3
4
5
6gmp='gmp-6.1.0.tar.bz2'
mpfr='mpfr-3.1.6.tar.bz2'
mpc='mpc-1.0.3.tar.gz'
isl='isl-0.18.tar.bz2'
base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'用脚本中提供的链接下载对应的压缩包,上传到目录
~/tmp/gcc-11.4.0
中,无需解压把脚本中实际下载命令对应的行注释掉,然后执行
./contrib/download_prerequisites
,因为这个脚本在下载压缩包之外还干了别的事,不能整个绕过
源码编译与安装
返回
~/tmp/gcc-11.4.0
的上一层目录,创建专门的编译目录~/tmp/gcc-11.4.0-build
,进入这个编译目录在编译目录中依次执行如下命令进行编译(编译过程很长,最好开一个后台任务或者用
screen
,tmux
之类的工具,避免编译被中断),这里没有选择将高版本gcc安装到~/.local
,而是创建了一个单独的目录进行安装(必须使用完整的绝对路径,否则会报错。编译的目录占用空间比较大,约6G)1
2../gcc-11.4.0/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --prefix=$HOME/opt/gcc-11.4.0
make -j4然后安装到本地
1
make install
编译过程中可能遇到如下问题(编译过程中的报错信息可能长达几千行,必须找到第一个报错才有实际价值)
1
#error "Unable to find a suitable type for HOST_WIDE_INT"
这是因为某些环境变量被提前设置了,在编译之前撤销下面这些相关的环境变量定义即可
1
unset LIBRARY_PATH CPATH C_INCLUDE_PATH PKG_CONFIG_PATH CPLUS_INCLUDE_PATH INCLUDE
安装配置
安装完成并不代表高版本gcc已经可以使用了,事实上,如何让非标准路径下的高版本gcc和标准路径下的低版本gcc共存才是最大的问题: 我们既希望新程序使用高版本gcc编译,使用对应的库,也希望依赖低版本gcc所对应库的程序仍然可以正常运行,这有点麻烦。
可能涉及的环境变量包括:
PATH
LIBRARY_PATH
LD_LIBRARY_PATH
C_INCLUDE_PATH
和CPLUS_INCLUDE_PATH
首先需要修改PATH
以找到正确的gcc/g++ 1
2which gcc
which g++
可以将高版本gcc所对应路径添加到PATH
的最前面,例如在~/.bashrc
添加
1
export PATH="$HOME/opt/gcc-11.4.0/bin:$PATH"
在编译时,编译器通常会自动找到配套的标准库头文件和库文件,但是在运行时存在一个问题: 用新版本gcc编译产生的可执行文件找不到正确的libstdc++等动态库,运行时报错。
可以通过ldd
命令来查看可执行程序实际找到的动态库路径
1
ldd ./a.out
可以通过设置环境变量LD_LIBRARY_PATH
来指定动态库的搜索路径,例如在~/.bashrc
添加
1
export LD_LIBRARY_PATH="$HOME/opt/gcc-11.4.0/lib64:$LD_LIBRARY_PATH"
但是上述操作仍然可能存在隐患,gcc的版本冲突可能产生在某些环节中产生问题,尤其是对于LD_LIBRARY_PATH
的修改可能影响其它程序的运行。
为了找到正确的动态库,更保守的方法是在编译时将对应的路径以RPATH的方式提供给二进制程序,例如
1
g++ -Wl,-rpath=$HOME/opt/gcc-11.4.0/lib64 main.cpp
cmake配置
cmake也需要处理上面的两个问题:找不到正确的编译器,找不到正确的动态库(编译时,运行时)。
除了上面的做法,下面再介绍一些仅局限于cmake范围内,对系统影响更小的做法。
对于编译器的查找,可以通过环境变量CC
和CXX
来指定,例如
1
2export CC=$HOME/opt/gcc-11.4.0/gcc
export CXX=$HOME/opt/gcc-11.4.0/g++
也可以在cmake命令中加上CMAKE_C_COMPILER
和CMAKE_CXX_COMPILER
选项来指定(优先级比CC
和CXX
更高),例如
1
cmake -S . -B build -DCMAKE_C_COMPILER=$HOME/opt/gcc-11.4.0/gcc -DCMAKE_CXX_COMPILER=$HOME/opt/gcc-11.4.0/g++
或者直接写入CMakeLists.txt中 1
2set(CMAKE_C_COMPILER "${GCC_PATH}/bin/gcc")
set(CMAKE_CXX_COMPILER "${GCC_PATH}/bin/g++")
对于动态库的查找,可以通过设置RPATH的方式,并不需要手动设置gcc的编译参数,cmake已经提供了RPATH相关变量
(但是拆分成了编译时和安装时两种情况),例如在CMakeLists.txt中添加
1
2set(CMAKE_BUILD_RPATH "${GCC_PATH}/lib64")
set(CMAKE_INSTALL_RPATH "${GCC_PATH}/lib64")
这里的修改最好放在
project
命令之前。