二进制兼容性
通常,使用 IBM® Open XL C/C++ for AIX® 17.1.0 构建的 C++ 对象是与通过 xlclang++调用的基于 Clang 的 IBM XL C/C++ for AIX 16.1.0 构建的 C++ 对象兼容的二进制对象。
例外情况是,使用 选项 IBMXL C/C++ for AIX16.1.0-qpdf1 创建的对象文件需要重新编译,因为这些对象文件调用的PDF库与本编译器使用的库不同。有关更多信息,请参阅概要文件引导优化 (PGO) 主题。
std 库 libc++,并且会导致破坏 C++ 二进制兼容性。 因此,使用 IBM Open XL C/C++ for AIX 17.1.0 构建的 C++ 对象文件无法与 IBM XL C/C++ for AIX 16.1.0 或更低发行版 (由 xlC调用) 的基于 XL 的前端生成的 C++ 对象文件直接互操作。 您必须使用 IBM Open XL C/C++ for AIX 17.1.0 重新编译经典程序,以成功解决此类二进制不兼容性和链接对象文件。使用 IBM Open XL C/C++ for AIX 17.1.0 构建的 C 对象是与使用 IBM XL C/C++ for AIX 16.1.0 或更低发行版构建的 C 对象兼容的二进制对象,当具有外部链接的符号名称仅包含美元符号和基本字符集中的字符时。
与经典 XL C++ 对象文件的兼容性
- 使用 IBM Open XL C/C++ for AIX构建的 C++ 对象文件。 这些对象文件利用 C++ 运行时库
libc++.a,libc++abi.a和libunwind.a提供的接口,这些接口分别来自libc++.rte,libc++abi.rte和libunwind.rte文件集。 - 使用 IBM XL C/C++ for AIX 16.1.0的基于 Clang 的前端构建的 C++ 对象文件。 这些对象文件利用来自
libc++.rte文件集的 C++ 运行时libc++.a提供的接口。
- 使用 IBM XL C/C++ for AIX 16.1.0 或更低发行版的基于 XL 的前端构建的 C++ 对象文件。 对象文件利用来自
xlC.rte文件集的 C++ 运行时libC.a提供的接口。
不同的管理名称
使用 libc + + ABI 和 libC ABI 中的不同名称管理方案来管理 C++ 函数和其他实体的名称,以防止链接不兼容的代码。 libc + + ABI 使用 Itanium C++ ABI 规范中定义的 CXA 管理方案,而 libC ABI 使用 IBM 专有管理方案。 因此,这些 ABI 中 C++ 函数的对应符号不同; 例如, C++ 函数 func() 的符号在 libc + + ABI 中是 _Z4funcv ,而在 libC ABI 中是 func__Fv 。 在 CXA 管理方案中,管理的名称具有 _Z 前缀。
不同的对象模型和布局
C++ 对象模型和布局在 libc + + ABI 和 libC ABI 之间有所不同。 从另一个 C++ ABI 中编译的代码中的一个 C++ ABI 访问 C++ 对象会导致未定义的行为,除非类型遵循与 C 兼容的规则。
不同的异常处理
异常处理的实现在 libc + + ABI 和 libC ABI 之间有所不同。 当从 libc + + ABI 端抛出异常并通过 libC ABI 端捕获或解除时,存在异常处理限制,反之亦然。 有关详细信息,请参阅异常兼容性。
由于这些差异, libc + + ABI 和 libC ABI 不兼容,可以视为不同的语言,即使这两种语言都称为 C++。但是,它们仍然可以在同一应用程序中共存,但存在限制。 在这种情况下,可以存在不同 C++ 运行时在同一流程空间中共存而不相互交互的实例。 例如,输入和输出分别进行缓冲,并且对其他运行时不可见。
使用共存共享对象构建的库
- 库中的 libc + + ABI 或 libC ABI 共享对象互斥。
- 提供 C++ API 面的库中的每个共享对象仅支持 libc + + ABI 和 libC ABI 中的一个。
- 从这些 ABI 导出的符号是不连接的。
- 在 libc + + ABI 与 libC ABI 之间没有交叉引用。
如果 libc + + ABI 和 libC ABI 共享对象具有交叉引用,或者如果存在引用两种类型共享对象的符号的可执行文件,那么共享对象将与生成的可执行文件链接。 这将导致两个不同的 C++ 运行时实现共存于同一个进程空间中,这可能会导致意外行为。 要确认可执行文件的装入依赖关系,请对可执行文件使用 ldd 命令。
asm 标签将函数名映射到不同的名称。 在以下示例中,名称 externCFunctionV2 用于 libc + + ABI 中的 externCFunction 函数,其原始名称 externCFunction 用于 libC ABI 中。#if defined(_AIX) && defined(__clang__)
extern "C" void externCFunction(void) asm("externCFunctionV2");
#else
extern "C" void externCFunction(void);
#endif仅从这些共享对象中导出期望的符号,并确保在共享对象中的 C++ ABI 中导出的符号不重叠。 要了解如何导出符号,请参阅 Symbol exports and visibilities。 如果不再需要旧的 C++ ABI 来链接新应用程序,但您希望保留装入兼容性,那么可以使用 strip -e 命令将共享对象设置为仅装入。
与共享对象不同,导出符号由导出列表或属性可视性控制,在同一归档库中同时具有 libc + + ABI 和 libC ABI 的静态归档成员可能会导致意外行为。 例如, libc + + ABI 和 libC ABI 的静态构造函数都由生成的可执行文件执行,这可能是不可期望的。 建议不要在同一归档库中同时包含 libc + + ABI 和 libC ABI 的静态归档成员,除非对行为有很好的理解。
以下示例显示如何从单个源构建双 ABI 库以同时支持 libc + + ABI 和 libC ABI:
$ cat build_example.sh
#!/usr/bin/ksh
rm -f xlc.shr.o ibmclang.shr.o libfunc.a xlc.a.out ibmclang.a.out
xlC -qmkshrobj func.cpp -o xlc.shr.o -bE:xlc.exp
ibm-clang++_r -shared func.cpp -o ibmclang.shr.o -bE:ibmclang.exp
ar -v -q libfunc.a xlc.shr.o ibmclang.shr.o
xlC main.cpp -o xlc.a.out libfunc.a -blibpath:.:/usr/lib
ibm-clang++_r main.cpp -o ibmclang.a.out libfunc.a -blibpath:.:/usr/lib
$ cat func.hpp
#include <iostream>
#if defined(_AIX) && defined(__clang__)
extern "C" void bar(void) asm("bar2");
#else
extern "C" void bar(void);
#endif
void func(void);
$ cat func.cpp
#include "func.hpp"
#if defined(_AIX) && defined(__clang__)
#define BUILD_COMPILER "build compiler is ibm-clang++_r"
#else
#define BUILD_COMPILER "build compiler is xlC"
#endif
void func(void)
{
std::cout << "func(): " << BUILD_COMPILER << std::endl;
}
extern "C" void bar(void)
{
std::cout << "bar(): " << BUILD_COMPILER << std::endl;
}
$ cat main.cpp
#include "func.hpp"
int main() {
func();
bar();
return 0;
}
$ cat xlc.exp
#!
func__Fv
bar
$ cat ibmclang.exp
#!
_Z4funcv
bar2
$ build_example.sh
$ xlc.a.out
func(): build compiler is xlC
bar(): build compiler is xlC
$ ibmclang.a.out
func(): build compiler is ibm-clang++_r
bar(): build compiler is ibm-clang++_r
$
在此示例中,使用 xlC 或 ibm-clang++_r 命令构建的 main 程序可以从 dual-ABI 库调用 func 和 bar 函数。 libfunc.a 中的共享对象 ibmclang.shr.o 是使用 IBM Open XL C/C++ 编译器构建的。 共享对象可以由 IBM Open XL C/C++ for AIX 和 IBM XL C/C++ for AIX 16.1.0的基于 Clang 的前端使用。 由于 ibmclang.shr.o 依赖于 IBM Open XL C/C++ 编译器的 C++ 运行时,因此基于 Clang 的 IBM XL C/C++ for AIX 16.1.0 前端生成的应用程序需要在系统上提供相应版本的 IBM Open XL C/C++ for AIX 运行时。 同样, ibmclang.shr.o 也可以使用基于 Clang 的前端 IBM XL C/C++ for AIX 16.1.0 进行构建,并由 IBM Open XL C/C++ for AIX 和基于 Clang 的前端 IBM XL C/C++ for AIX 16.1.0使用。xlc.a.out 和 ibmclang.a.out 的输出:$ ldd xlc.a.out
xlc.a.out needs:
...
/usr/lib/libC.a(shr.o)
...
/usr/lib/libC.a(shrcore.o)
/usr/lib/libC.a(ansi_32.o)
/usr/lib/libC.a(ansicore_32.o)
$ ldd ibmclang.a.out
ibmclang.a.out needs:
...
/usr/lib/libc++.a(shr2.o)
/usr/lib/libc++abi.a(libc++abi.so.1)
/usr/lib/libunwind.a(libunwind.so.1)
/usr/lib/libc++.a(libc++.so.1)
...
$根据输出, xlc.a.out 依赖于经典 XL C/C++ 编译器的 C++ 运行时 (即 libC.a) ,但它不依赖于 Open XL C/C++ 编译器的 C++ 运行时 (即 libc++.a, libc++abi.a和 libunwind.a)。 另一方面, ibmclang.a.out 具有对 libc++.a, libc++abi.a和 libunwind.a 的依赖关系,但不具有对 libC.a的依赖关系。