由于符号与abi :: cxx11链接问题?

我们最近因为GCC 5.1,libstdc ++和Dual ABI而发现了一个报告。 看来Clang并不知道GCC内联命名空间的变化 ,所以它根据一组命名空间或符号生成代码,而GCC使用另一组命名空间或符号。 在链接时,由于缺less符号而出现问题。

如果我正确parsingDual ABI页面,它看起来像在_GLIBCXX_USE_CXX11_ABIabi::cxx11上旋转,还有一些额外的困难。 在GCC5和C ++ 11 ABI以及GCC-5.1和两个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] 

如何使用两种装饰符号(红帽博客称之为“共存”)来生成带有符号的二进制文件?

或者,我们有什么select?


我正试图实现一个“它只是为了”用户。 我不在乎两个不同的行为是否有两个弱符号( std::string缺lesscopy-on-write,而std::string[abi:cxx11]提供了copy-on-write)。 或者,一个可以是另一个的别名。

Debian在Debian Bug报告日志中有一堆相似的错误:标签为libstdc ++ – cxx11的错误 。 他们的解决scheme是在新的ABI下重build所有的东西,但是它并没有处理混合/匹配编译器模块化ABI变化的情况。

在苹果的世界里,我认为这是接近一个胖二进制。 但是我不确定在Linux / GCC世界中该做什么。 最后,我们不控制发行版如何构build库,而且我们也不控制使用什么编译器将应用程序链接到库。

Solutions Collecting From Web of "由于符号与abi :: cxx11链接问题?"

免责声明,以下未经生产测试,使用风险自负。

你可以自己释放你的双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::whateverCryptoPP::cxx11::whatever还是CryptoPP::cxx03::whatever取决于所选的ABI。

请注意,GCC手册说这个方法会改变在标记的内联命名空间中定义的所有东西的错位名称。 根据我的经验,这不会发生。

另一种方法是使用__attribute__((abi_tag("cxx11")))标记每个类,函数和变量,如果_GLIBCXX_USE_CXX11_ABI非零。 该属性很好地将[cxx11]添加到了demangler的输出中。 我认为使用一个命名空间也可以,但是对现有的代码只需要很少的修改。

理论上你不需要复制整个库,只需要复制使用std::stringstd::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