我知道如果我将我的 c++ 程序链接到使用不同版本的 Visual Studio 构建的动态库 (DLL),由于二进制兼容性问题,它将无法工作。(我在 Boost 库和 VS 2005 和 2008 中体验过这一点)
但我的问题是:所有版本的 MSVS 都是这样吗?这也适用于静态库(LIB)吗?这也是 GCC 和 Linux 的问题吗?最后如何在 VS 中链接到使用 MinGW 构建的 DLL?
顺便说一句,除了跨平台或跨编译器,为什么同一编译器(VS)的两个版本不能兼容?
我知道如果我将我的 c++ 程序链接到使用不同版本的 Visual Studio 构建的动态库 (DLL),由于二进制兼容性问题,它将无法工作。(我在 Boost 库和 VS 2005 和 2008 中体验过这一点)
但我的问题是:所有版本的 MSVS 都是这样吗?这也适用于静态库(LIB)吗?这也是 GCC 和 Linux 的问题吗?最后如何在 VS 中链接到使用 MinGW 构建的 DLL?
顺便说一句,除了跨平台或跨编译器,为什么同一编译器(VS)的两个版本不能兼容?
你好。我知道如果我将我的 c++ 程序链接到使用不同版本的 Visual Studio 构建的动态库 (DLL),由于二进制兼容性问题,它将无法工作。(我在 Boost 库和 VS 2005 和 2008 中体验过这一点)
我不记得曾经见过 MS 更改 ABI,因此技术上不同版本的编译器将产生相同的输出(给定相同的标志(见下文))。
因此,我不认为这不是 Dev Studio 中的不兼容,而是 Boost 中的变化。
不同版本的 boost 不向后兼容(在二进制中,它们是向后兼容的源代码)。
但我的问题是:所有版本的 MSVS 都是这样吗?
我不相信有问题。现在,如果您使用不同的标志,您可以使目标文件不兼容。这就是为什么调试/发布二进制文件被构建到单独的目录中并链接到不同版本的标准运行时。
这也适用于静态库(LIB)吗?
您必须链接到正确的静态库。但是,一旦静态库在您的代码中,它就会卡在那里,所有已解析的名称将不会在以后重新解析。
这也是 GCC 和 Linux 的问题吗?
是的。GCC 在 ABI 中多次破坏了向后兼容性(有几次是故意的(有些是错误的))。这不是一个真正的问题,因为 Linux 代码通常作为源代码分发,您在平台上编译它就可以工作。
最后如何在 VS 中链接到使用 MinGW 构建的 DLL?
抱歉我不知道。
顺便说一句,除了跨平台或跨编译器,为什么同一编译器(VS)的两个版本不能兼容?
完全优化的代码对象可能会被更多地压缩,因此对齐方式不同。其他编译器标志可能会影响生成与其他二进制对象不兼容的代码的方式(更改调用函数的方式(堆栈上的所有参数或寄存器中的某些参数))。从技术上讲,只有使用完全相同的标志编译的对象才应该链接在一起(从技术上讲,它比这有点松散,因为很多标志不会影响二进制兼容性)。
请注意,某些库随同一个库的多个版本一起发布,这些版本以不同的方式编译。您通常通过最后的扩展名来区分库。在我的上一份工作中,我们使用了以下约定。
libASR.dll // A Sincgle threaded Relase version lib
libASD.dll // A Single threaded Debug version
libAMR.dll // A Multi threaded Release version
libAMD.dll // A Multi threaded Debug version
要回答您的部分问题,GCC/Linux 没有这个问题。至少,不那么频繁。libstdc++ 和 glibc 是 GNU 系统上的标准 C++/C 库,这些库的作者努力避免破坏兼容性。glibc 几乎总是向后兼容,但 libstdc++ 过去曾多次破坏 ABI,并且将来可能会再次破坏。
与 C 相比,用 C++ 编写稳定的 ABI是非常困难的,因为 C++ 中的自动特性带走了您维护 ABI 所需的一些控制。尤其是当您进入模板和内联函数时,其中一些代码会嵌入到您的应用程序中,而不是保留在共享库中。这意味着如果不重新编译应用程序,对象的结构永远不会改变。
实际上,这在 Windows 上并不是什么大问题。如果 Microsoft 只是让 MSI 安装程序知道如何在安装需要它们的应用程序时从 Windows 更新中获取 Microsoft 提供的 DLL,那么只需将可再发行组件添加到 InnoSetup 生成的安装程序就足够了。
如果构建得当,DLL 应该是编程语言和版本中立的。您可以链接到使用 VB、C、C++ 等构建的 DLL。
您可以使用依赖遍历器来检查 dll 中的导出函数。