【问题标题】:Can C++ libraries compiled with VC10 (sp1) be linked by code compiled with VC11?用 VC10 (sp1) 编译的 C++ 库可以通过用 VC11 编译的代码链接吗?
【发布时间】:2012-04-03 15:04:02
【问题描述】:

问题说明了一切。

我了解 VC11 目前仅处于测试阶段,但我要问的是:

  1. 尝试链接使用 vc10 编译的封闭源代码(如果可能,广泛使用)库的经验
  2. Microsoft 的规范明确指出,如果是或否,vc11 将能够与 vc10 库链接。

我说的只是 C++ 的情况。

【问题讨论】:

  • 是静态库还是动态库?​​
  • 我要的是所有情况,所以请随时解释在哪种情况下可以将这些二进制文件链接在一起。
  • @Klaim 我没有来自 Microsoft 的任何具体信息,但我不明白为什么您不能静态或动态链接到在 VC11 上使用 VC10 构建的库。对于静态链接,您需要包含头文件和库,对于动态链接,您需要 DLL:它们都不依赖于 Visual Studio 版本。
  • @Lirik 如果更改了 C++ ABI,生成的修饰符号名称可能会有所不同。由两个不同版本使用共享运行时构建的同上 DLL/EXE 可能会在不同的堆上分配和释放内存,因此您需要小心在它们之间交换对象的所有权(这可能包括 C++ 中的隐式销毁等)
  • @Link:您从来没有在为一个 MSVC 版本和另一个版本编译的 C++ 库之间链接(动态或静态)。标准库不兼容。另一方面,如果您提供两个运行时(或与 msvcrtXXX.lib 静态链接),C 库可能会正常工作。

标签: c++ visual-c++ compiler-construction linker


【解决方案1】:

您可能想阅读this answer 了解动态链接的情况。

关于静态链接,我认为您不能安全地将使用 VCx 编写的 C++ 库与使用 VCy 编译的代码链接起来。例如,STL 容器的实现会随着版本的变化而变化(即使在同一版本中,调试和发布模式之间也会发生变化,以及像 _HAS_ITERATOR_DEBUGGING 等设置)。

Quoting VC++ STL maintainer:

STL 从来没有也永远不会保证二进制兼容性 不同主要版本之间。我们正在使用链接器执行此操作 混合使用编译的目标文件/静态库时出错 不同的主要版本都是 VC10+ [...]

【讨论】:

  • 我明白这一点,但这只是答案的一部分。我问的是“一般”,那么如果你能添加细节更好。
  • @Klaim:我为静态链接添加了注释。
【解决方案2】:

这是一个响亮的不! VS的每个主要版本都有一个新版本的动态CRT,VS2008的名称是msvcr90.dll,VS2010的名称是msvcr100.dll,VS11的名称是msvcr110.dll。

当您从导出函数返回 C++ 对象(如 std::string)或返回任何需要被客户端代码删除的指针时,使用动态 CRT(/MD 编译选项)很重要。只有当客户端代码使用与 DLL 完全相同的 CRT 版本时,它才能正常工作。隐含的是,当这些代码块各自依赖于 msvcrXXX.dll 版本时,情况就不会如此,它们将不可避免地具有不共享相同堆分配器的不兼容 CRT 版本。

您可以编写与任何 CRT 版本一起安全使用的 DLL,但这需要仔细设计 API,以便不存在这些依赖项。 COM 自动化模型就是一个例子。

【讨论】:

    【解决方案3】:

    对于动态库,应该没有问题,因为它们遵循定义明确的 ABI。您可以随时从任何编译器链接到 dll。

    静态库比较棘手。据我所知,微软从未保证过这些的交叉编译器兼容性。特别是,已知链接时代码生成等功能会破坏早期版本之间的兼容性。 .lib 文件不像 DLL 那样具有单一的明确定义的格式。

    它可能会起作用,因为微软很少会破坏兼容性,除非他们必须这样做,但据我所知,它不能保证。

    当然,如果 DLL 公开的实际函数和类型不匹配,您就会遇到问题。

    在 VC11 中,几乎所有标准库数据结构的大小都发生了变化(微软终于采用了空基类优化,有效地减小了所有使用默认分配器的容器的大小。),所以试图将一个std::string 从一个用 VC10 编译的 DLL 传递到一个用 VC11 编译的模块中肯定会失败。

    【讨论】:

    • 对于动态库,我的理解是msvc9 vs msvc10不是这样,还是我遗漏了什么?
    • DLL 遵循非常特定的格式。他们必须这样做,因为它不仅仅是编译器使用的文件,它还打算由操作系统加载和调用。当您调用LoadLibrary 时,操作系统必须能够加载 DLL,无论是哪个编译器生成的。它必须能够在 DLL 中查找符号,等等。所以使用MSVC9和10一起构建的DLL应该没有问题。
    • 但是在接口中使用 C++ 标准库的 DLL 呢?如果类结构发生变化,即使您可以编译和链接,也会导致问题。
    • 哦,当然。我只是在考虑是否可以链接到由不同编译器生成的 dll(可以)。你是对的,如果 C++ 对象的结构发生变化,你就不能安全地跨 DLL 边界传递它们。
    【解决方案4】:

    我看不出它们不兼容的任何原因。无论您使用什么 C++ 编译器来生成 LIB 文件,只要它们遵循格式规范。如果您对格式的详细信息感兴趣,可以查看this question

    【讨论】:

    • 因为编译器(甚至相同的不同版本)可能不会生成相同的名称重整。例如,vc10 二进制文件不能被 vc9 链接(假设 C++,C 很好)。
    • 您通常不能在编译器之间混合 C++ 对象,例如您当然不能像您链接到的问题那样将 Mingw C++ 对象与 MSVC C++ 对象混合使用。一开始的异常处理机制是不同的(本机 Windows 异常机制 - SEH - 已获得专利,因此 GCC 使用了其他东西)并且损坏的符号名称也是使用不同的方案生成的。
    • 哪种格式规范?你知道.lib 文件的一个吗?据我所知,不存在规范。
    • @jalf,在我提到的问题中,有一个规范的链接:kishorekumar.net/pecoff_v8.1.htm
    • 简单反例:启用链接时代码生成。您的 .obj 文件将不再包含机器代码,因此将不符合此规范。 :)
    猜你喜欢
    • 2014-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    相关资源
    最近更新 更多