在新版Linux系统下编译GCC 4.6.0

因为Ubuntu 22.04的GCC 11实在太新,跑SPEC2006跑不起来。为了跑SPEC2006我重新编译了一次GCC。但因为GCC 4.6.0也非常老旧在新的glibc下编译也出了不少问题,这里记录一下解决方案以便日后能用上。

首先是系统和编译器,已经装好一些基本的工具比如 build-essential

howard@Howard-Ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04 LTS
Release:	22.04
Codename:	jammy

howard@Howard-Ubuntu:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.2.0-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-11-gBFGDP/gcc-11-11.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-gBFGDP/gcc-11-11.2.0/debian/tmp-gcn/usr --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.2.0 (Ubuntu 11.2.0-19ubuntu1)

预期编译指令:

wget https://ftp.gnu.org/gnu/gcc/gcc-4.6.0/gcc-4.6.0.tar.gz
tar xvzf gcc-4.6.0.tar.gz
cd gcc-4.6.0
./configure --prefix=/home/howard/.local
make -j8
make install

1. 配置失败,找不到GMP/MPFR/MPC头文件

checking for the correct version of gmp.h... no
configure: error: Building GCC requires GMP 4.2+, MPFR 2.3.1+ and MPC 0.8.0+.

这个简单,把这三个库装好就行:

sudo apt install -y libgmp-dev libmpfr-dev libmpc-dev

2. 找不到 bits/libc-header-start.h

In file included from ../../.././libgcc/../gcc/tsystem.h:87:0, from ../../.././libgcc/../gcc/libgcc2.c:29:
/usr/include/stdio.h:27:36: fatal error: bits/libc-header-start.h: No such file or directory

这是因为编译gcc的时候也会编译32位的一部分二进制文件(上面输出能看到用了 -m32 参数),所以需要32位的对应头文件和库来成功编译。

sudo apt install -y gcc-multilib

3. linux-unwind.h 类型定义不完整

In file included from ../../.././libgcc/../gcc/unwind-dw2.c:333:0: ../../.././libgcc/../gcc/config/i386/linux-unwind.h:
In function ‘x86_fallback_frame_state’:
../../.././libgcc/../gcc/config/i386/linux-unwind.h:138:17: error: field ‘info’ has incomplete type
../../.././libgcc/../gcc/config/i386/linux-unwind.h:139:18: error: field ‘uc’ has incomplete type

这个就是新版libc更新后替换了原本一部分结构体定义的结果了。不过幸好的是它们是一一对应的只是换了个symbol,只需要对应地重命名就可以了:

sed -i 's/struct ucontext/ucontext_t/g' gcc/config/*/linux-unwind.h 
sed -i 's/struct siginfo/siginfo_t/g' gcc/config/*/linux-unwind.h
附注:你可能会在网上搜到一些用于这个的patch比如Gentoo社区的补丁,但我发现它们并没有完全替换所有的 linux-unwind.h 。所以还是用 sed 会比较方便。

4. 找不到 crti.o

/usr/bin/ld: cannot find crti.o: No such file or directory
collect2: ld returned 1 exit status
make[3]: *** [Makefile:804: libgcc_s.so] Error 1

上面这个错误文本可能不太好找到因为用了多线程编译。这个主要是编译寻找库的列表的问题。因为未知原因,即使文件在 /usr/lib/x86_64-linux-gnu/crti.o 并且 ld.so.conf.d 内指定了 /usr/lib/x86_64-linux-gnu/ 为包含目录,它仍旧报了这个错误。我们手动把它添加进 LD_INCLUDE_PATH :

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/

如果你的 LD_LIBRARY_PATH 本来是有定义一些别的目录的话,你可以把这个目录添加到它们前面:

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH
注意:只有原本这个变量非空才用这一个指令,因为如果原本变量为空的话,会赋值 LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/: (注意结尾冒号),然后gcc一个组件的配置就会失败,判定说 LD_LIBRARY_PATH 包含了当前目录。

5. 编译找不到gmp.h

In file included from ../.././gcc/tree.h:31:0,
                 from ../.././gcc/c-family/stub-objc.c:26:
../.././gcc/double-int.h:24:17: fatal error: gmp.h: No such file or directory
compilation terminated.
make[3]: *** [Makefile:1074: c-family/stub-objc.o] Error 1

应该是类似于上面的问题,我们可以找到 gmp.h 的位置,然后同样添加他们到头文件搜索列表中:

export C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu/
export CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu/

6. libjavaucontext 定义不完全

../../.././libjava/prims.cc: In function ‘void _Jv_catch_fpe(int, siginfo_t*, void*)’:
../../.././libjava/prims.cc:193:3: error: invalid use of incomplete type ‘struct _Jv_catch_fpe(int, siginfo_t*, void*)::ucontext’
../../.././libjava/prims.cc:193:3: error: forward declaration of ‘struct _Jv_catch_fpe(int, siginfo_t*, void*)::ucontext’
make[5]: *** [Makefile:9894: prims.lo] Error 1

这个也是libc的问题,实际上跟上面问题3是一样的,Gentoo社区有个补丁不过我们可以直接用sed替换:

# ref: https://gitweb.gentoo.org/proj/gcc-patches.git/plain/6.4.0/gentoo/97_all_libjava-ucontext.patch
sed -i 's/struct ucontext/ucontext_t/g' libjava/include/*-signal.h

7. 未定义 __cxa_call_unexpected

/usr/bin/ld: ./.libs/libgcj.so: undefined reference to `__cxa_call_unexpected' 
collect2: ld returned 1 exit status
make[5]: *** [Makefile:9412: gcj-dbtool] Error 1

这个还是glibc更新的问题。我们可以直接应用官方给的一个patch:

wget https://gcc.gnu.org/bugzilla/attachment.cgi?id=25901 -O a.patch
patch -p0 < a.patch

8. 数组长度为负数

size of array 'assertion_failed__1150' is negative

这个还是glibc更新的问题,不过这个不是GCC 4.6.0 而是编译GCC 7.5.0 出现的问题(使用GCC 11.3编译)。解决方法还是打patch。Patch的地址如下:

https://raw.githubusercontent.com/jjolly/spack/6f6a1d3e7d56a95c9a09fc1ec3e6767cd457c967/var/spack/repos/builtin/packages/gcc/glibc-2.31-libsanitizer-2-gcc-7.patch

总结

总结一下,这里是所有执行了的指令(在 gcc-4.6.0 目录下):

sudo apt install -y libgmp-dev libmpfr-dev libmpc-dev gcc-multilib
sed -i 's/struct ucontext/ucontext_t/g' gcc/config/*/linux-unwind.h
sed -i 's/struct ucontext/ucontext_t/g' libjava/include/*-signal.h
sed -i 's/struct siginfo/siginfo_t/g' gcc/config/*/linux-unwind.h
# 注意:下面第6行这个指令请看上面第4点的说明
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/
export C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu/
export CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu/
wget https://gcc.gnu.org/bugzilla/attachment.cgi?id=25901 -O- | patch -p0

执行完之后应该就可以编译了,如果还有别的问题多半是哪个库没装上,自行apt装一下就可以。

顺带一提,编译完gcc 4.6.0然后用它跑SPEC2006的时候还出现了一个错误:

../run_base_test_gcc43-64bit.0000/bwaves_base.gcc43-64bit: error while loading shared libraries:
libgfortran.so.3: cannot open shared object file: No such file or directory

解决方案是把刚才安装的动态链接库的文件目录添加进动态链接的搜索列表里(默认不在):

export LD_LIBRARY_PATH=~/.local/lib:~/.local/lib32:~/.local/lib64

参考: