本来想写一大堆,后来发现这件事情在理论上是不可行的,然后就放弃了。

首先的原因是了解到作为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它不香吗

标签: none

添加新评论