由于符号与 abi::cxx11 引起的链接问题
Linking problems due to symbols with abi::cxx11?
我们最近因为GCC 5.1,libstdc++和Dual ABI而发现了一份报告。Clang似乎不知道GCC内联命名空间的变化,因此它基于一组命名空间或符号生成代码,而GCC使用另一组命名空间或符号。在链接时,由于缺少符号而出现问题。
如果我正确解析双 ABI 页面,它看起来像是转向_GLIBCXX_USE_CXX11_ABI
和abi::cxx11
,还有一些额外的困难。更多阅读内容,请访问红帽的博客GCC5和C++11 ABI,以及GCC-5.1和Two C++ ABI的案例。
下面是一台 Ubuntu 15 机器。机器提供 GCC 5.2.1。
$ cat test.cxx
#include <string>
std::string foo __attribute__ ((visibility ("default")));
std::string bar __attribute__ ((visibility ("default")));
$ g++ -g3 -O2 -shared test.cxx -o test.so
$ nm test.so | grep _Z3
...
0000201c B _Z3barB5cxx11
00002034 B _Z3fooB5cxx11
$ echo _Z3fooB5cxx11 _Z3barB5cxx11 | c++filt
foo[abi:cxx11] bar[abi:cxx11]
如何使用两种装饰(红帽博客称之为"共存")生成带有符号的二进制文件?
或者,我们有哪些选择?
我正在尝试为用户实现"它只是工作"。我不在乎是否有两个具有两种不同行为的弱符号(std::string
缺乏写入时复制,而std::string[abi:cxx11]
提供写入时复制)。或者,一个可以是另一个的别名。
在 Debian Bug 报告日志中有很多类似的错误:标记为 libstdc++-cxx11 的错误。他们的解决方案是在新的 ABI 下重建所有内容,但它没有处理混合/匹配编译器模化 ABI 更改的极端情况。
在苹果的世界里,我认为这接近于一个胖二进制。但我不确定在Linux/GCC世界中该做什么。最后,我们不控制发行版如何构建库,也不控制使用哪些编译器将应用程序与库链接。
免责声明,以下内容未经生产测试,使用风险
自负。您可以自己在双重 ABI 下发布您的库。这或多或少类似于OSX"胖二进制",但完全用C++构建。
最简单的方法是编译库两次:使用 -D_GLIBCXX_USE_CXX11_ABI=0
和 -D_GLIBCXX_USE_CXX11_ABI=1
。根据宏的值将整个库放在两个不同的命名空间下:
#if _GLIBCXX_USE_CXX11_ABI
# define DUAL_ABI cxx11 __attribute__((abi_tag("cxx11")))
#else
# define DUAL_ABI cxx03
#endif
namespace CryptoPP {
inline namespace DUAL_ABI {
// library goes here
}
}
现在,您的用户可以像往常一样使用CryptoPP::whatever
,这会映射到CryptoPP::cxx11::whatever
或CryptoPP::cxx03::whatever
,具体取决于所选的 ABI。
请注意,GCC 手册说此方法将更改标记的内联命名空间中定义的所有内容的损坏名称。根据我的经验,这不会发生。
另一种方法是如果_GLIBCXX_USE_CXX11_ABI
为非零,则用__attribute__((abi_tag("cxx11")))
标记每个类、函数和变量。此属性很好地为破坏器的输出添加了[cxx11]
。我认为使用命名空间也一样有效,并且需要对现有代码进行较少的修改。
理论上,您不需要复制整个库,只需要复制使用 std::string
和 std::list
的函数和类,以及使用这些函数和类的函数和类,等等递归。但在实践中,这可能不值得付出努力,尤其是在库不是很大的情况下。
这里有一种方法可以做到这一点,但它不是很优雅。我也不清楚如何使 GCC 自动化它,所以我不必做两次事情。
首先,将要转换为库的示例:
$ cat test.cxx
#include <string>
std::string foo __attribute__ ((visibility ("default")));
std::string bar __attribute__ ((visibility ("default")));
然后:
$ g++ -D_GLIBCXX_USE_CXX11_ABI=0 -c test.cxx -o test-v1.o
$ g++ -D_GLIBCXX_USE_CXX11_ABI=1 -c test.cxx -o test-v2.o
$ ar cr test.a test-v1.o test-v2.o
$ ranlib test.a
$ g++ -shared test-v1.o test-v2.o -o test.so
最后,看看我们得到了什么:
$ nm test.a
test-v1.o:
00000004 B bar
U __cxa_atexit
U __dso_handle
00000000 B foo
0000006c t _GLOBAL__sub_I_foo
00000000 t _Z41__static_initialization_and_destruction_0ii
U _ZNSsC1Ev
U _ZNSsD1Ev
test-v2.o:
U __cxa_atexit
U __dso_handle
0000006c t _GLOBAL__sub_I__Z3fooB5cxx11
00000018 B _Z3barB5cxx11
00000000 B _Z3fooB5cxx11
00000000 t _Z41__static_initialization_and_destruction_0ii
U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev
U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
和:
$ nm test.so
00002020 B bar
00002018 B __bss_start
00002018 b completed.7181
U __cxa_atexit@@GLIBC_2.1.3
w __cxa_finalize@@GLIBC_2.1.3
00000650 t deregister_tm_clones
000006e0 t __do_global_dtors_aux
00001ef4 t __do_global_dtors_aux_fini_array_entry
00002014 d __dso_handle
00001efc d _DYNAMIC
00002018 D _edata
00002054 B _end
0000087c T _fini
0000201c B foo
00000730 t frame_dummy
00001ee8 t __frame_dummy_init_array_entry
00000980 r __FRAME_END__
00002000 d _GLOBAL_OFFSET_TABLE_
000007dc t _GLOBAL__sub_I_foo
00000862 t _GLOBAL__sub_I__Z3fooB5cxx11
w __gmon_start__
000005e0 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
00001ef8 d __JCR_END__
00001ef8 d __JCR_LIST__
w _Jv_RegisterClasses
00000690 t register_tm_clones
00002018 d __TMC_END__
00000640 t __x86.get_pc_thunk.bx
0000076c t __x86.get_pc_thunk.dx
0000203c B _Z3barB5cxx11
00002024 B _Z3fooB5cxx11
00000770 t _Z41__static_initialization_and_destruction_0ii
000007f6 t _Z41__static_initialization_and_destruction_0ii
U _ZNSsC1Ev@@GLIBCXX_3.4
U _ZNSsD1Ev@@GLIBCXX_3.4
U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev@@GLIBCXX_3.4.21
U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev@@GLIBCXX_3.4.21
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- setlocale的C++土耳其字符串问题
- 如何重构类层次结构以避免菱形问题
- 基于boost的程序的静态链接——zlib问题
- 涉及STD :: __ CXX11名称空间的链接器错误 - 双ABI问题
- 由于符号与 abi::cxx11 引起的链接问题