Is it safe to link C++17, C++14, and C++11 objects询问如何链接使用不同语言标准编译的对象,而乔纳森·韦克利(Jonathan Wakely)在该问题上的出色回答解释了gcc / libstdc ++所做出的ABI稳定性承诺,以确保这项工作可行。
还有一点可以在gcc版本之间进行更改-通过-fabi-version
的语言ABI。假设,为简单起见,我有三个目标文件:
foo.o
,使用gcc 6.5 c ++ 14编译bar.o
,使用gcc 7.4 c ++ 14编译quux.o
,使用gcc 8.3 c ++ 17编译全部带有各自的默认语言ABI(即10、11和13)。从库的角度来看,根据链接的答案将这些对象链接在一起是安全的。但是从语言ABI的角度来看是否存在可能出错的事情?我有什么需要注意的吗?大多数语言ABI更改似乎都不会引起问题,但是12种空类类型的调用约定更改可能吗?
答案 0 :(得分:10)
大多数语言的ABI更改似乎不会引起问题,但是对于12种空类类型的调用约定更改可能会发生吗?
更改空类的调用约定可能会在x86-64上引起问题。这是一个示例:
def.hpp :
@ViewChild
one.cpp :
component.ts
two.cpp :
struct Empty { };
struct Foo {
char dummy[16];
int a;
Foo() : a(42) { }
};
void fn(Empty, Foo);
现在,如果您使用A ++分别为11和12的G ++ 8进行编译,例如:
#include "def.hpp"
int main() {
fn(Empty(), Foo());
}
结果#include <stdio.h>
#include "def.hpp"
void fn(Empty e, Foo foo) {
printf("%d\n", foo.a);
}
将不会打印预期的g++ -c -fabi-version=11 one.cpp
g++ -c -fabi-version=12 two.cpp
g++ one.o two.o
。
原因是旧的ABI(11)为堆栈上的a.out
保留了空间,而新的ABI(12)则没有。因此,42
的地址在主叫方和被叫方之间将有所不同。
(注意:我包含了Empty()
,所以foo
是通过堆栈而不是寄存器传递的。如果Foo::dummy
是通过寄存器传递的,那将没有问题。)>
答案 1 :(得分:4)
它们中的大多数会以较小的方式更改修饰,这可能会在链接时导致一些未定义的引用,或者由于相同的源代码会产生两个具有不同名称的等效符号而导致一些代码膨胀,因此链接器不会合并它们。 / p>
对于12种空类类型的调用约定可能会更改吗?
是的,当然可以。如果您的非最终参数为空类型,则将影响该函数的ABI,并且差异可能导致不确定的行为(实际上,访问堆栈上的垃圾或参数获取错误的值)。