我知道如果我将我的c ++程序链接到使用不同版本的Visual Studio构建的动态库(DLL),由于二进制兼容性问题,它将无法工作。 (我在Boost图书馆和VS 2005和2008中经历过这个)
但我的问题是:对于所有版本的MSVS都是如此吗?这是否也适用于静态库(LIB)?这是GCC& S的一个问题吗? Linux也是?最后如何在VS中链接到使用MinGW构建的DLL?
除了跨平台或交叉编译器之外,为什么同一个编译器(VS)的两个版本不能兼容?
答案 0 :(得分:2)
您好。我知道如果我将我的c ++程序链接到使用不同版本的Visual Studio构建的动态库(DLL),由于二进制兼容性问题,它将无法工作。 (我在Boost图书馆和VS 2005和2008中经历过这个)
我不记得曾经看过MS改变ABI,因此技术上不同版本的编译器会产生相同的输出(给定相同的标志(见下文))。
因此我认为这不是Dev Studio中的不兼容性,而是Boost的变化 不同版本的boost不向后兼容(二进制,源向后兼容)。
但我的问题是:对于所有版本的MSVS都是如此吗?
我不相信有问题。现在,如果使用不同的标志,则可以使对象文件不兼容。这就是为什么调试/发布二进制文件被构建到单独的目录中并链接到标准运行时的不同版本。
这是否也适用于静态库(LIB)?
您必须链接到正确的静态库。但是一旦静态库出现在你的代码中,那么所有已解析的名称都将在以后重新解析。
GCC是一个问题吗? Linux也是?
是。海湾合作委员会已经在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
答案 1 :(得分:0)
如果构建正确,DLL应该是编程语言和版本中立的。您可以链接到使用VB,C,C ++等构建的DLL。
您可以使用dependency walker检查dll中的导出函数。
答案 2 :(得分:0)
要回答部分问题,GCC / Linux没有这个问题。至少,不是经常。 libstdc ++和glibc是GNU系统上的标准C ++ / C库,这些库的作者努力避免破坏兼容性。 glibc几乎总是向后兼容,但libstdc ++过去几次破坏了ABI,可能在将来再次破坏。
与C相比,C ++中编写稳定的ABI很难非常,因为C ++中的自动功能会消除维护ABI所需的一些控制。特别是一旦进入模板和内联函数,其中一些代码嵌入到您的应用程序中,而不是保留在共享库中。这意味着在不需要重新编译应用程序的情况下,对象的结构无法更改。
在实践中,它在Windows上并不是一个大问题。如果微软只是让MSI安装程序知道如何在安装需要它的应用程序时从Windows Update获取Microsoft提供的DLL,那就太棒了,但只需将可再发行组件添加到InnoSetup生成的安装程序就可以了。