gcc降级编译
本来想写一大堆,后来发现这件事情在理论上是不可行的,然后就放弃了。
首先的原因是了解到作为gcc的C++标准库,libstdc++
是后向兼容的(这里的“后”指时间上的“过去”),也就是说,新版本libstdc++
支持旧版本编译出来的程序,而反过来不行。这是因为libstdc++
库是以一种类似于增量更新的方式实现的,使用strings
指令查看libstdc++.so
文件可以发现,它包含了从最早版本以来一系列的符号支持,这也正是其后向兼容的原因。
由于没有前向兼容,导致过去的gcc不是适应未来的编译环境。以我的体验为例,用gcc 8.4.1编译gcc 4.9.4,前者的libstdc++
的ABI
应用二进制接口版本是CXXABI_1.3.9
,而后者的只有CXXABI_1.3.8
。
而问题正是出在这里。由于gcc和libstdc++
属于紧密耦合的关系,gcc会使用自带的libstdc++
而不是当前系统的版本来提供运行环境。使用了gcc 8.4.1编译的gcc 4.9.4自然是按照前者的运行库,使用了CXXABI_1.3.9
;而当gcc 4.9.4运行的时候,从自己的libstdc++
库里一翻,只支持到CXXABI_1.3.8
,啪的一下就因为找不到符号报错了,很快啊。
当然这个可以通过使用LD_PRELOAD
强行让gcc 4.9.4使用系统libstdc++
库来解决这个问题,但是后面还有更麻烦的。我前几年编译gcc的文档里提到过,gcc的编译是自举的,相当于先编译gcc核心-编译c++库-再编译gcc扩展这个流程。
然而,使用LD_PRELOAD
只是解决了第二步中的一个问题,重点在于libstdc++
在版本更新的时候,可能不止更新ABI,还更新了上层的API,可能编着编着发现函数不见了,或者签名改了,直接报错中断,问题还没等到链接阶段就已经出现了。要解决这个问题约等于更改gcc对应的libstdc++
库依赖,这严重违反了两者现有的紧密依赖的特点。这也正是我选择放弃降级编译gcc最主要的原因。
最后的结论是,CentOS 8是个什么垃圾东西,CentOS 7+devtoolset它不香吗