最近,在 Linux 下应用 CMake 编译程序的时候遇到一个问题,特此做一个记录。
事件是这样的,我编译的程序应用了 2 个第三方库,在写好 CMakeLists 后,启动编译,而后就报链接谬误,始终报一堆找不到定义。
相似这样的一堆:
‘***** std::__cxx11 *******’未定义的援用
我仔细检查代码和 CMakeLists,各种批改尝试无果。最初,在共事和搜索引擎的帮忙下终于找到问题所在了。
问题出在我应用的 GCC 和第三方库编译的时候应用的 GCC 版本差别太大,两者的 ABI 不兼容。
参考 GCC 提供的手册 <Dual ABI>,事件就清晰了。
在 GCC5.1 公布的 libstdc++ 中,增加了新的个性,其中包含了 std::string 和 std::list 的新实现。新的实现使得两者都合乎了 C ++11 的规范。然而,为了与现存代码兼容,libstdc++ 保留了老的实现,与新实现并存。具体怎么实现的呢?相比于老的实现,GCC5.1 增加了__cxx11 命名空间,在新的实现中的 string 和 list,实际上是 std::__cxx11::string 和 std::__cxx11::list。新旧 ABI 不兼容。
那么,问题怎么解决呢?
也很简略,就是对立你的程序和第三方库应用的实现版本。如果你有第三方库源码,那对立从新编译下就行。如果第三方库是曾经编译好的那也没关系,GCC 为咱们提供了一个抉择新旧实现的宏定义 -D_GLIBCXX_USE_CXX11_ABI。
-D_GLIBCXX_USE_CXX11_ABI=0 示意应用旧的实现
-D_GLIBCXX_USE_CXX11_ABI=1 示意应用新的实现
按需增加到 CMakeLists 中就能够了。