C++ ABI 问题定位解决
当编译链接时遇到报错undefined reference to “std::__cxx11 ***”,那基本就是遇到了C++ ABI问题了。所谓ABI,是指应用程序二进制接口(Application Binary Interface, ABI)。
1、ABI 问题的出现
在GCC 5.1 版本发布的libstdc++中,添加了包含std::string和std::list的新的实现方法的ABI。而由于std::basic_string被广泛使用着,因此有很多标准库都会受影响。为了实现与现存代码兼容,libstdc++的库名没有进行修改,而且老的实现也依然保留着与新的实现并存。并存是怎么实现的呢,就是在内联命名空间中定义了新的实现,因此新、旧实现在链接时就有不同的名字,比如 新版本的std::list被定义为了std::__cxx11::list。也正是因为新的实现有不同的名字,使得新、旧实现能够在同一个库中并存。
2、ABI 问题的解决
2.1 GLIBCXX_USE_CXX11_ABI
当你升级GCC版本后,如果把整个代码都全部重新编译一遍,那么你基本上不会遇到ABI问题的。但是如果你还依赖于其他第三方编译出来的动态库,而它们是用老版本的GCC(如:GCC 4.8)编译出来的,那么就有可能会遇到ABI的问题。这个时候,在编译的时候添加一个定义-D_GLIBCXX_USE_CXX11_ABI=0,那么应该就不会有什么问题了。
2.2 本地GCC版本冲突
稳住,别慌。如果明明别人提供第三方库也是GCC 5.3 编译的,你本地也是指定的GCC 5.3版本,但是还是有ABI问题,那我猜你是不是本地默认的GCC版本是4.x,或者你链接了libstdc++.a静态库?我就遇到了这个情况。
我本地默认GCC版本是4.8,在另一个目录/buildtools/gcc5.3安装了GCC 5.3。在编译时指定了CMAKE_CXX_COMPILER为GCC5.3的对应目录。但是编译时依然会报ABI的问题。被这个问题折磨了一天后,又和第三方对齐了一下cmake版本,然后将cmake升级为最新版本,它居然多了个报警:
CMake Warning at CMakeLists.txt:75 (add_executable):
Cannot generate a safe linker search path for target MyBinary because
files in some directories may conflict with libraries in implicit
directories:
link library [libstdc++.a] in /build_tools/gcc-5.3.21/lib64 may be hidden by files in:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5
Some of these libraries may not be found correctly.
仔细看看这个报警,说的是某些目录中的文件可能与隐式目录中的库冲突,指定的GCC 5.3目录下的库可能被系统目录下GCC 4.8的库隐藏。也就是说我明明指定的是GCC 5.3,但实际链接时却链接到了GCC 4.8上面,也因此导致ABI问题的出现。当我们把/usr/lib/gcc目录挪走之后,链接就没有问题了。
困扰了我好几天的问题因此解决。
侵删