4

在尝试将使用 Visual Studio Express 2008 编译的一组代码与使用 Visual Studio 2003 编译的 .lib 链接时,我们刚刚获得了一次有趣的体验。全部使用 C++。准确地说,是在VS2003中编译成.lib的SystemC 2.2.0内核,在VS2008中编译的SystemC模型。

在链接时,我们不断收到错误,即在链接期间未找到 SystemC.lib 文件(即在 VS2003 中编译)中的一些符号。我们得到的错误是这样的(在一些变体中):

SystemC.lib(sc_port.obj) : error LNK2001: unresolved external symbol "public: vo
id __thiscall std::_String_base::_Xran(void)const " (?_Xran@_String_base@std@@QB
EXXZ)

从各种线索中挖掘,事实证明 .lib 期望找到的函数是这样的:

Undecoration of :- "?_Xran@_String_base@std@@QBEXXZ"
is :- "public: void __thiscall std::_String_base::_Xran(void)const "

虽然 VS2008 试图链接的库文件 (libcpmt.lib) 使用了不同的调用约定:

Undecoration of :- "?_Xran@_String_base@std@@SAXXZ"
is :- "public: static void __cdecl std::_String_base::_Xran(void)"

我试图弄清楚为什么会发生这种不兼容,但最后我放弃了,在 VS2008 中重新编译了完全相同的 Visual Studio 项目,并使用了 SystemC.lib 而不是 VS2003 中的那个。现在,一切都很顺利。

所以这里的基本问题是:从 VS2003 到 VS2008 发生了什么变化,会导致某些函数改变它们的调用约定?是否有一些魔术标志可以给 VS2008 中的链接器以使用其他库,其中函数具有与 VS2003 编译中相同的调用约定?

更新,到目前为止的答案摘要:微软很可能将 C++(不是 C,只是 C++)ABI 从 Visual Studio 的一个主要版本更改为下一个。库中还可能存在其他导致不兼容的更改。最好的建议是为每个版本的 VS 重新编译 .lib。本质上,只需将其以源代码形式发送给用户,并让他们使用他们碰巧安装的任何版本的 VS 在本地编译它。

通过使用以下建议发现了基本问题:

请注意,这些问题没有回答这个问题:

4

2 回答 2

3

C++ ABI 没有标准。这意味着所有 c++ 编译器都可以处理不同的 ABI,并且包括来自同一编译器的不同版本。对于来自 Gcc 的 2 个不同的主要版本,您可能会遇到相同的问题。当他们找到改进链接步骤的方法时,可能会发生这种修改。

但 ABI 涉及的远不止这些。例如,编译器生成的代码在后台存储和处理 vtable 的方式。如果它发生变化,您在 2008 年生成的对象和代码将与预期在 2003 年完成的方式的库不兼容。

至此,您可以理解为什么 c++ 库要么与它们的源代码一起发布,要么在许多不同的架构和编译器上编译。

通常在编写库时,为了避免此类问题,您使用 C 语言而不是 C++ 开发它。由于 C 带有标准化的 ABI,您可以使用一个编译器对其进行编译,然后将该库与任何尊重 C ABI 标准的 C 编译器链接。例如,字符串的实现方式是标准的,可能永远不会移动(臭名昭著的空终止字符串)。虽然 std::string 实现从一个 Gcc 主要版本更改为另一个(只需查看 /usr/include/c++/xx/bits/basic_string 文件中的 basic_string 类)

于 2009-08-13T14:25:11.900 回答
2

据我所知,这些问题是由于 CRT 库而发生的,它们会随着主要版本而变化,您不应该混合 CRT 类型(多线程、调试、发布、静态、动态等)。

通常可以通过与 CRT 动态链接来最小化它们,我在 VS2005 中成功地重用了 VS2003 库,但这很烦人,最好重新编译整个东西。有时您可以通过使用/NODEFAULTLIB编译器标志来避免链接到导致问题的某个 CRT 库。

于 2009-08-13T15:39:25.310 回答