解决高版本GCC引用低版本GCC编译的动态库的方法

概述

当你的项目打算从低版本的GCC(如GCC4)升级后,你可能会遇到GCC undefined references with abi:cxx11之类的问题,究其原因是GCC5.1开始,STL标准库中的std::string和一些标准库被新的方法实现,但由于其std::basic_string影响较大,因此很多库都会或多或少受影响。如果你需要使用的库恰好是GCC4编译的,那么,除了使用新版本GCC重新编译库之外,只能通过GLIBCXX_USE_CXX11_ABI的方式解决了。

使用重新编译的方式解决

以源码方式使用新版本GCC重新编译动态库,并使用新的动态库,这种方式最优。

强制使用CXX11编译

我们可以在编译期指定GLIBCXX_USE_CXX11_ABI宏,让编译器强制使用C++11所使用的接口。

CMAKE

对于CMAKE来说,我们需要在CMakeList.txt添加:

1
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)

或者在调用cmake命令时传入:

1
cmake -DCMAKE_CXX_FLAGS='-D_GLIBCXX_USE_CXX11_ABI=0' path/to/your/project

Makefile

对于Makefile来说,我们同样也是在合适的地方添加宏,最终的效果是:

1
g++ $^ -std=c++14 -D_GLIBCXX_USE_CXX11_ABI=0 $(INCLUDE) $(LIB) -o $@

局限性

但是该方法只能说是权宜之计,因为其有一个很明显的局限性,如果你的程序同时使用了多个动态库,这些动态库如果都是使用GCC4编译的那没有什么问题,但如果这些动态库中存在有使用高版本编译的动态库时,则可能会出现新的问题。


2023/10/17 补充

检查符号是否正确

当使用一个动态链接库时,我们可能会发现明明成功引用但仍然报出undefined reference异常,这个时候就需要小心不同的GCC版本编译的符号名称是否一致的问题了。

有效的解决方式是使用:

1
nm -D *.so | grep 符号

来确定符号的全称,然后将符号全称拷贝下来,使用c++fit命令解析,看和头文件是否一致。

1
c++filt *

如果不一致那么可能就需要你针对实际情况进行解决了。