为什么依赖应用程序应该使用与动态库相同的编译器?

Coo*_*der 5 c++ qt abi linkage

最近我必须编译 Qt,并且说明明确提到我的应用程序应该使用与我编译 Qt 相同的编译器进行编译。现在我不明白其原因,想知道这是 Qt 特有的还是通用的 C++ 的东西?

lpa*_*app 6

介绍

使用不同编译器创建的目标文件和静态库,甚至使用同一编译器的明显不同版本创建的目标文件和静态库通常无法链接在一起。这个问题并不是 MinGW 特有的:许多其他编译器是相互不兼容的。如果可以的话,使用相同编译器的相同版本从源代码构建所有内容。

Dll 略有不同。有时,您可以将使用一种编译器构建的 DLL 链接到使用另一种编译器编译的应用程序。如果 DLL 是用 C 编写的,那么即使应用程序是用 C++ 编写的,这种方法也很有效。例如,MinGW C++ 程序通常链接到 Windows 提供的 C 运行时库。用 C++ 编写的 DLL 也可以工作,只要您仅通过使用 extern“C”声明的 C 接口与它们通信。否则,您可能会遇到链接器错误,因为不同的编译器以不同的方式处理 C++ 名称。

为什么不同的编译器可能无法互操作

有时人们想知道为什么编译器编写者不只是使用相同的名称修饰方案。这可能会使链接成功,但很可能会导致程序在调用 DLL 时崩溃。真正的链接兼容性需要一个通用的应用程序二进制接口,而名称修改只是众多考虑因素之一。以下是部分列表:--

如果同一系统的两个 C++ 实现使用不同的调用序列,或者在其他方面不兼容链接,则使用相同的类型签名编码将是不明智的。

实现者传统上故意使用不同的名称修改方案,他们认为在链接时“直接说不”比让一些简单的代码工作并让问题在运行时出现更好。

尽管 GNU g++ 现在可以链接 MSVC C++ 库,并且可以生成 MSVC++ 兼容的库/DLL,但这并不意味着由于 C++ 的动态特性,它们能够在运行时工作。一些可能的原因是:--

  • 简单的名称修改问题可以通过显式 .def 文件来规避。
  • 不同的结构对齐问题需要正确的编译器选项(-mms-bitfields,...)。
  • 底层异常和内存模型的根本冲突:--

MSVC DLL 中的 new/delete 或 malloc/free 不会与 Cygwin newlib new/delete 或 malloc/free 协作。根本无法释放使用不同的 new/malloc 在函数中分配的空间。

MSVC DLL 引发的异常不会被 Cygwin 可执行文件捕获,反之亦然。

慢速 GNU SJLJ 异常模型(在 GCC-3.x 及更早版本中使用)与 MSVC++ 模型兼容,但新的 DWARF2 模型(将由 GCC-4.x 使用)将不兼容。

可以在这里找到规范来源。