记一次编译GCC的经历
背景
因为有在Linux环境编译C++程序的需求,故我于近日在电脑上安装了WSL。鉴于APT(Debian系Linux常用的包管理器)提供的GCC版本不一定为最新版(确切来说,APT会根据Linux发行版本来下载并安装某个版本的GCC,例如对Ubuntu Noble而言,从APT获取的最新版本GCC为13.2.0),我便尝试自己编译一套GCC工具链。
在编译之前,我发现GNU提供的GCC安装教程内容组织较为混乱,新手容易踩坑(羊头你这是生怕新手能顺利编译好GCC啊,你不会写教程就别写😠)。于是,在查阅了其他人编写的GCC编译教程后,我结合了我自己的(踩坑)经验,编写了这篇文章。
准备
Linux环境(我用的是WSL Ubuntu Noble)
畅通无阻的网络环境
先前的GCC编译器
一些其他的软件包
步骤
打开终端,先将本机上现有的软件包更新至最新:
sudo apt update && sudo apt upgrade
若遇到网络问题,则需要更改镜像源。本人推荐MirrorZ镜像源。具体修改方法参见镜像源提供的帮助信息,此处不再赘述。
更新完成后,根据此页面,我们需要安装编译GCC所需的软件包:
sudo apt install g++ libc6-dev python3 gnat gdc gm2 gawk binutils gzip bzip2 make tar perl libgmp-dev libmpfr-dev libmpc-dev libisl-dev zstd gettext autoconf m4 automake gperf dejagnu expect tcl autogen guile-3.0 flex texinfo texlive sphinx-common git ssh diffutils patch libtool bison byacc gfortran
随后,我们将GCC源代码clone至本地:
git clone https://gcc.gnu.org/git/gcc.git
读者可以自己修改存放GCC源代码的目录名称,只需在链接后面加上目录名称即可,例如gcc_src。这里我就用默认的gcc来指代GCC源代码目录了,以下同理。
若遇到网络问题,则同样可以从镜像源clone。只需把链接换成https://mirrors.cernet.edu.cn/gcc.git即可(此处以MirrorZ镜像源举例)。
接下来我们进入GCC源代码目录:
cd gcc
在配置GCC编译配置前,我们需要切换tag至某个release版本,否则编译产物将为当前最新的GCC开发版。当前最新的发行版GCC的版本号为14.2.0,因此我们执行此命令:
git checkout releases/gcc-14.2.0
最新发行版的版本号可在GCC官网查找。
这样就可以了。
可能读者知道GCC源代码里已经包含了自动安装依赖的脚本,即./contrib/download_prerequisites。我们还需要执行它吗?答案是不需要。我大致分析了脚本内容,发现这个脚本下载并安装的是这五个软件包:gmp、mpfr、mpc、isl及gettext,相关源代码可见此。而这些软件包,我们已经在前面安装过了,所以我们无需再安装一遍它们。
接下来,我们执行cd ..命令退出GCC源代码目录,创建一个存放GCC构建产物的目录(这里我就命名为gcc_build了),并进入其中:
mkdir gcc_build && cd gcc_build
在构建GCC之前,根据此页面,我们需要配置好GCC编译配置。这里给出我的编译配置,读者可以按需修改:
../gcc/configure --prefix=/usr/local/gcc-14.2.0 --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --enable-languages=c,c++,jit,lto --enable-bootstrap --enable-checking=release --enable-host-shared --enable-shared --enable-static --disable-multilib --with-build-config=bootstrap-lto --with-boot-ldflags=-static-libstdc++ --with-gnu-as --with-gnu-ld --with-stage1-ldflags=-static-libstdc++ --with-system-zlib --with-target-system-zlib=auto --enable-graphite --enable-lto --enable-vtable-verify --with-tune=generic --enable-threads=posix --enable-libgomp --enable-libatomic --enable-libstdcxx-debug --enable-libstdcxx-filesystem-ts --enable-libstdcxx-time --with-libiconv --with-default-libstdcxx-abi=new --enable-cet --enable-default-pie --enable-gnu-unique-object --enable-locale=gnu --enable-cxx-locale=gnu --enable-nls --without-included-gettext --enable-plugin --enable-linker-build-id --enable-link-serialization=2 --enable-fully-dynamic-string --without-cuda-driver
接下来就可以愉快地make了:
make -j$(nproc) profiledbootstrap
编译完成后,执行sudo make install,编译好的GCC便会安装至/usr/local/gcc-14.2.0。
接下来,我们可以选择替换掉系统原来安装的GCC:
sudo update-alternatives --install /usr/bin/gcc gcc /usr/local/gcc-14.2.0/bin/gcc 10 && sudo update-alternatives --install /usr/bin/g++ g++ /usr/local/gcc-14.2.0/bin/g++ 10
末尾的数字代表优先级,可以为任意值。值越大,则系统越倾向于选择其为默认GCC。
替换掉原来的GCC的好处是,我们可以直接运行gcc命令而无需添加目录前缀,使用起来会更方便。
我们再执行命令gcc -v,如果能看到如下所示的输出:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/gcc-14.2.0/libexec/gcc/x86_64-linux-gnu/14.2.0/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../gcc/configure --prefix=/usr/local/gcc-14.2.0 --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --enable-languages=c,c++,jit,lto --enable-bootstrap --enable-checking=release --enable-host-shared --enable-shared --enable-static --disable-multilib --with-build-config=bootstrap-lto --with-boot-ldflags=-static-libstdc++ --with-gnu-as --with-gnu-ld --with-stage1-ldflags=-static-libstdc++ --with-system-zlib --with-target-system-zlib=auto --enable-graphite --enable-lto --enable-vtable-verify --with-tune=generic --enable-threads=posix --enable-libgomp --enable-libatomic --enable-libstdcxx-debug --enable-libstdcxx-filesystem-ts --enable-libstdcxx-time --with-libiconv --with-default-libstdcxx-abi=new --enable-cet --enable-default-pie --enable-gnu-unique-object --enable-locale=gnu --enable-cxx-locale=gnu --enable-nls --without-included-gettext --enable-plugin --enable-linker-build-id --enable-link-serialization=2 --enable-fully-dynamic-string --without-cuda-driver
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 14.2.0 (GCC)
这就表示我们的替换已经生效了!
总结
编译GCC会锻炼耐力,原因有二:
GCC配置非常多,这便是在锻炼耐力与英语阅读理解能力(当然逃课办法是用ChatGPT,不过它可能会给出错误答案)。
GCC编译过程非常慢,短则半小时,长则好几个小时,期间还有可能发生意外(我遇到的意外有“找不到xxx.cc”,以及因内存不足,从而编译器进程被系统杀死等)导致编译失败,这便也是在锻炼耐力,即:有条不紊、镇定自若地处理错误,然后从头开始编译/配置(痛苦面具.jpg)之耐力。
不说了,好累!我要去休息一下!