在这种情况下,我有一个使用最近的GCC(4.3.3)的C++代码库,但我需要链接一个使用GCC 3.2.3构建的旧库.没有更新版本的库,我不能没有它,它是封闭源,所以它无法重建.
这似乎是一个问题,因为GCC 4.3.3和3.2.3之间存在ABI不兼容性,所以我试图看看我的选择是什么来解决这个问题.
一些额外的细节:
我到目前为止尝试过:
我阅读了这个页面:http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html这似乎表明可以在应用程序中混合使用C++ ABI版本来满足库之间不同的依赖关系.但是,这似乎并没有很好地工作,除非我遗漏了一些东西.
有任何想法吗?
我正在阅读Itanium ABI,上面写着
当且仅当指针相等时,两个 type_info 指针才指向等效类型描述。实现必须满足此约束,例如通过使用符号抢占、COMDAT 部分或其他机制。
有谁知道在流行平台(例如使用 GCC 和 GNU binutils 的 Linux)上使用动态加载库时如何在实践中实现这一点的具体细节?它有多可靠?
另外,我的印象是,typeidMSVC 中的比较是(是?)使用对损坏的符号名称进行运行时字符串比较来实现的,因为不能保证满足此要求。现在还是这样吗?是否存在技术平台限制阻止 MSVC 使用与 Itanium ABI 平台上使用的相同技术?
编辑还有一个问题:跨模块边界(在任一 ABI 中)捕获异常是否也依赖于 RTTI 信息,或者除了运行时的等效机制之外是否还涉及另一种机制dynamic_cast?
假设我有一个 C++ DLL。AFAIK,C++ 没有广泛采用的 ABI 标准,因此为了确保它工作并且不依赖于目标应用程序的编译器,我需要将我的库包装在 C 接口中。
有没有什么工具可以自动生成这样的界面?如果他们可以围绕 C 接口生成包装器,看起来好像它们是原始的 C++ 对象,那也会很好,例如
Foo* f = new Foo(); // FooWrapper* fw = Foo_create();
f->bar("test"); // Foo_bar(fw, "test")
Run Code Online (Sandbox Code Playgroud)
转换为使用生成的 C ABI 在我的库中调用的 C 函数。我知道 C++ 是相当复杂的语言,并不是所有的东西都可以很容易地包装在 C 接口中,但我想知道是否有任何这样的解决方案甚至支持 C++ 语言的一个子集(也许在一些手动编写的 IDL/ XML 文件)?
假设C库必须与应用程序代码共享结构的细节,并且必须保持API和ABI向后兼容性.它试图通过检查传递给它的结构的大小来做到这一点.
比如说,需要更新以下结构.在库版本1中,
typedef struct {
int size;
char* x;
int y;
} foo;
Run Code Online (Sandbox Code Playgroud)
在库的第2版中,它更新为:
typedef struct {
int size;
char* x;
int y;
int z;
} foo_2;
Run Code Online (Sandbox Code Playgroud)
现在,库版本2想要检查应用程序是将新的foo_2还是旧的foo作为参数arg传递给函数.它假定应用程序已设置arg.size为sizeof(foo)或sizeof(foo_2)尝试确定应用程序代码是否为版本2.
if(arg.size == sizeof(foo_2)) {
// The application groks version 2 of the library. So, arg.z is valid.
} else {
// The application uses of version 1 of the library. arg.z is not valid.
}
Run Code Online (Sandbox Code Playgroud)
我想知道为什么这不会失败.在GCC 4.6.3,与-O3标志,无论是sizeof(foo)和sizeof(foo_2) …
由于系统标头中的类型更改,我在 Linux 上遇到了可移植性问题。siginfo_t 类型已从命名结构 (struct siginfo) 更改为未命名结构。对我来说,这在 RHEL6 和 RHEL7 之间发生了变化。
我们在一些地方使用了ACE,他们在一些公开的接口中使用了 siginfo_t。结果是在 RHEL7 上编译的代码不会链接到在 RHEL6 上构建的库。暂时,我需要支持这个。
在 RHEL6 中,一个问题函数被输入为:
ACE_Event_Handler::handle_signal(int, siginfo*, ucontext*)
Run Code Online (Sandbox Code Playgroud)
在 RHEL7 中,它看起来像这样:
ACE_Event_Handler::handle_signal(int, siginfo_t*, ucontext*)
Run Code Online (Sandbox Code Playgroud)
它们被分解成不同的符号,导致链接期间失败或运行时符号查找失败。
一个相对简单的解决方案是使用函数别名。但是,我不想修改头文件。我有点挣扎,因为这是一个虚拟成员函数。
我尝试在基于 RHEL7 的 ACE 版本上的 Event_Handler.cpp 中执行此操作:
struct siginfo;
ACE_Event_Handler::handle_signal(int, siginfo*, ucontext*)
__attribute__((
alias("_ZN17ACE_Event_Handler13handle_signalEiP9siginfo_tP8ucontext")
));
Run Code Online (Sandbox Code Playgroud)
有了这个,GCC 抱怨该函数没有被声明。我最终能够完成这项工作,但只有通过这个丑陋的黑客:
extern "C" int _ZN17ACE_Event_Handler13handle_signalEiP7siginfoP8ucontext()
__attribute__((
alias("_ZN17ACE_Event_Handler13handle_signalEiP9siginfo_tP8ucontext")
));
Run Code Online (Sandbox Code Playgroud)
需要'extern "C"' 以防止重新修改损坏的名称。
有没有更优雅的方法来实现这一点而不会遇到编译器投诉?
是否通过不透明指针将 C++ 库包装到 C 提供了稳定的 ABI 接口?我很清楚 ABI 接口以及为什么 c++ 没有稳定的接口。这与名称修改和许多其他事情有关。我知道 C 在这部分非常稳定。与 C++ 相比,将 C 库包装成各种其他语言也很容易。这两个是为我的库制作 ac API 的驱动力。
将 C++ 库包装为 C 时,底层代码仍然是 C++。我的情况是 C++,带有 boost 共享 ptr 和其他依赖项。
那么既然底层代码是C++,那么ABI的稳定性是如何实现的。或者换句话说,共享库(.so、.dll 等)中仍然编译了 C++ 的东西。
我想知道它是如何工作的。也许有人可以为我提供一个很好地解释这些东西的例子。
使用 GCC 时,考虑到我有时在发布时编译相同的库,有时在调试时编译相同的库,ABI 是否保证兼容?
(同时使用相同的编译器)
我有一个可执行文件和一些共享对象(有些依赖于其他对象),我希望能够交换发布/调试共享对象,而无需重新编译所有内容,而只重新编译感兴趣的共享对象。
这是可能的,还是在某些情况下我可能会以这种方式获得一些未定义的行为?(假设我的代码被严格打包,并在发布和调试中填充)
编辑:
我将详细说明我们看到的问题。我们有一个自定义版本intrusive_ptr,在调试模式下,我们有自己intrusive_ptr的一个成员,即 a boost::intrusive_ptr,而在发布中,我们只使用boost::intrusive_ptr. 我们的 APIintrusive_ptr与 相同boost::intrusive_ptr,并且我们在类中没有任何虚函数。
我们看到的是:
如果我们使用所有调试库或所有发布库,则一切正常。如果我们将调试可执行文件与发布库混合使用,则会发生内存泄漏,intrusive_ptr并且不会释放对象。
我们intrusive_ptr和的大小boost::intrusive_ptr在调试和发布中都是相同的(我们的类不会在顶部添加任何大小开销)。
所以我想知道是什么导致了泄漏,ABI 差异是唯一想到的事情。
想法?
我在 Rust 中包装了一个低级别的 ABI,利用了naked函数特性。这是我的代码和相关的反汇编
#![feature(asm)]
#![feature(naked_functions)]
struct MyStruct {
someVar: i64, // not important
// ...
}
impl MyStruct {
#[naked]
extern "C" fn wrap(&self) {
unsafe {
asm!("NOP" :::: "volatile");
// not sure if the volatile option is needed, but I
// figured it wouldn't hurt
}
}
}
Run Code Online (Sandbox Code Playgroud)
用LLDB反汇编:
ABIWrap`ABIWrap::{{impl}}::wrap:
* 0x100001310 <+0>: movq %rdi, -0x10(%rbp)
* 0x100001314 <+4>: movq %rsi, -0x8(%rbp)
* 0x100001318 <+8>: movq -0x10(%rbp), %rax
* 0x10000131c <+12>: movq -0x8(%rbp), %rcx
* 0x100001320 …Run Code Online (Sandbox Code Playgroud) 我很困惑与问候如何编译和链接处理的事实,在电话会议上要求ER功能的依靠,如果函数使用静脉阻塞或NRVO不同.
这可能是我的误解,但我的假设是通常没有RVO或NRVO
std::string s = get_string();
Run Code Online (Sandbox Code Playgroud)
如果get_string不执行N?RVO但是如果get_string执行N?RVO调用代码什么也不做,并且s由函数get_string构造到位,则涉及从get_string的结果移动构造s .
编辑:这是我如何设想get_string调用程序操作,如果没有N?RVO:
现在还有RVO
abi ×10
c++ ×7
gcc ×4
c ×3
api ×2
wrapper ×2
alias ×1
attributes ×1
compilation ×1
itanium ×1
legacy ×1
nrvo ×1
rtti ×1
rust ×1
rvo ×1
shared-ptr ×1
visual-c++ ×1
x86 ×1