Ubuntu 22.04 中默认的 gcc 是 11.3,由于一些缘由需要安装一个老版本的 gcc。在 http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-4.9.4/ 上下载了 gcc 4.9.4,是 gcc4 的最后版本。本以为解压后直接 ./configure && make 就行,结果遇到了许多问题。第一,应该运行 ./contrib/download_prerequisites 下载依赖的包,它会自动下载如下依赖包并把它们解压好备用,不用自己额外操作。然后才是 configure 和 make。
cloog-0.18.1.tar.gz
gmp-4.3.2.tar.bz2
isl-0.12.2.tar.bz2
mpc-0.8.1.tar.gz
mpfr-2.4.2.tar.bz2
问题一
最初用的 configure 选项是
./configure --prefix=/opt/gcc-4.9.4 --disable-multilib --enable-languages=c,c++,fortran --build=x86_64-linux CFLAGS=-march=znver3 CXXFLAGS=-march=znver3
结果其中的 -march=znver3 本是想着根据 AMD CPU的架构提高下性能,谁知道会造成后面类似 xgcc: error: unrecognized command line option -V xgcc: fatal error: no input files 错误提示,不过这只是表象,这句本身实则并不是错误而是在用编译出的 xgcc 尝试可用的版本参数 -v, -V 等,但却很迷惑人。最终错误在哪儿也没完全清楚,感觉似乎是编译出的gcc用 -march=znver3 参数时出的问题。总之,不要用这个参数就是了,于是 configure 如下
/configure --prefix=/opt/gcc-4.9.4 --disable-multilib --enable-languages=c,c++,fortran --build=x86_64-linux
其中 --enable-languages 如果不指定会编译出一大堆语言,没必要。
问题二
../.././gcc/reload1.c: In function ‘void init_reload()’:
../.././gcc/reload1.c:89:24: error: use of an operand of type ‘bool’ in ‘operator++’ is forbidden in C++17
89 | (this_target_reload->x_spill_indirect_levels)
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
该错误是由于某些语法在 c++17 标准中不在允许,而 gcc 11.3 版本默认好像是用的 C++17 标准,所以有如上错误。最初想在 configure 时通过 CXXFLAGS 指定更低的标准列如 -std=c++03,不过发现这同样会带来后面的一些问题,由于后面还会使用较高标准。而且我们发现 host-x86_64-linux/gcc 下的 Makefile 里根本没有使用我指定的 -std 选项,估计也是这个缘由吧。实则这个这在这一处出现,可以直接切换到 host-x86_64-linux/gcc 目录下,把出错的那个命令加上 -std=c++03 参数后重新执行一下就行了。然后再回到顶层目录接着 make 即可。
问题三
接下来出现的一系列编译错误和 https://blog.csdn.net/tuibianhuaisheng/article/details/115399019 这里的情况几乎一样
(1) ucontext
./md-unwind-support.h: 在函数‘x86_64_fallback_frame_state’中:
./md-unwind-support.h:65:47: 错误: dereferencing pointer to incomplete type
sc = (struct sigcontext *) (void *) &uc_->uc_mcontext;
^
make[3]: *** [../.././libgcc/shared-object.mk:14:unwind-dw2.o] 错误 1
cd /home/XXXX/software/gcc-4.9.4/x86_64-linux/libgcc
报错是在第65行,不过要该第61行:
struct ucontext *uc_ = context->cfa; => struct ucontext_t *uc_ = context->cfa;
(2) 致命错误: sys/ustat.h

参考 https://reviews.llvm.org/D47165
- 把文件 sanitizer_common/sanitizer_common_syscalls.inc 中两处的
#if !SANITIZER_ANDROID改为#if !SANITIZER_LINUX && !SANITIZER_ANDROID。 - 将文件 sanitizer_common/sanitizer_platform_limits_posix.cc 中包含
ustat的两行注释掉。
(3) assertion_failed__931

根据数字 931 把文件 sanitizer_common/sanitizer_platform_limits_posix.cc 中的第 931 行注释掉。
(4) handler_stack 问题
最初的错误忘了保留了,网上找到了类似的如下

参考 https://reviews.llvm.org/D35246
- sanitizer_common/sanitizer_linux.h 文件中
struct sigaltstack;这行去掉,之后两处出现的struct sigaltstack都换成void。 - sanitizer_common/sanitizer_linux.cc 文件中两处出现的
struct sigaltstack都换成void。 - sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc 中的
struct sigaltstack handler_stack;换成stack_t handler_stack;。 - tsan/rtl/tsan_platform_linux.cc 文件中
__res_state *statp = (__res_state*)state;换成struct __res_state *statp = (struct __res_state*)state;。
(5) SIGSEGV 问题

在文件 libsanitizer/asan/asan_linux.cc 中添加头文件 #include <signal.h> 即可。
解决掉上述问题后装上了 gcc 4.9.4。最后配置一下 module 文件如下:
#%Module1.0
proc ModulesHelp { } {
puts stderr "GNU C/C++/Fortran Compiler"
puts stderr "See http://gcc.gnu.org/"
}
#conflict compiler/gcc
set GCC_HOME /opt/gcc-4.9.4
prepend-path PATH ${GCC_HOME}/bin
prepend-path INFOPATH ${GCC_HOME}/share/info
prepend-path LIBRARY_PATH ${GCC_HOME}/lib64:${GCC_HOME}/lib/gcc/x86_64-linux/4.9.4
prepend-path LD_LIBRARY_PATH ${GCC_HOME}/lib64:${GCC_HOME}/lib/gcc/x86_64-linux/4.9.4
prepend-path MANPATH ${GCC_HOME}/share/man
prepend-path C_INCLUDE_PATH ${GCC_HOME}/include/c++/4.9.4:${GCC_HOME}/include/c++/4.9.4/x86_64-linux:/usr/include/x86_64-linux-gnu
prepend-path CPLUS_INCLUDE_PATH ${GCC_HOME}/include/c++/4.9.4:${GCC_HOME}/include/c++/4.9.4/x86_64-linux:/usr/include/x86_64-linux-gnu
注意其中 include 最后还加上了系统的 路径,否则 times.h 等文件会找不到。
吐槽一下
简书也真够坑人的,不知道什么缘由,贴的代码无法保存。编辑的时候预览没问题,不过查看历史版本,某段代码之后就根本不保存,发布完这部分内容也没有!注意还不是说只有它认为有问题的代码部分无法保存,而是从那个地方起后面的都无法保存!无奈,只能把无法保存的代码截图贴上了,真是够气人的!
