为什么用VS2003编译的.lib文件无法与用VS2008编译的代码链接?

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编译时相同的调用约定?
更新,迄今为止回答的摘要:很可能微软会在每个Visual Studio主要版本之间更改C++(而不是C,只是C++)ABI。还可能存在其他导致不兼容性的库更改。最好的建议是为每个VS版本重新编译.lib文件。基本上,只需将其以源代码形式提供给用户,并让他们在本地使用他们安装的任何版本的VS进行编译即可。
通过使用以下建议,发现了基本问题:

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


2
问题是“它为什么不应该失败?” :) - JohnIdol
这种自然反应,对吧? - jakobengblom2
2个回答

3

C++ ABI没有标准。这意味着所有C++编译器都可以处理不同的ABI,包括来自同一编译器的不同版本。当他们找到改进链接步骤的方法时,就会进行这样的修改。但ABI涉及更多的内容。例如,vtable是如何由编译器生成的代码存储和处理的。如果发生变化,则在2008年生成的对象和代码将与期望在2003年执行的库不兼容。

因此,您现在可以理解为什么C++库要么附带源代码,要么附带编译在许多不同架构和编译器上的库。

通常,在编写库时,为了避免这些问题,您使用C语言进行开发,而不是C++。由于C具有标准化的ABI,因此您可以使用一个编译器编译它,然后使用符合该C ABI标准的任何C编译器链接该库。例如,实现字符串字符的方式是标准化的,可能永远不会移动(臭名昭著的以null结尾的字符串)。而std::string的实现则会从一个Gcc主要版本到另一个版本发生更改。


1
这绝对是一个好观点。它让使用MinGW编译的代码与任何类型的VS编译的代码之间的链接变得非常困难和烦人。我想我只是希望微软能在不同版本之间更加一致。实际上,净结果就是你必须在所有声明周围使用extern "C" {}来做__cdecl文件以实现可移植性。 - jakobengblom2

2
据我所知,这些问题是由 CRT 库引起的,它们随着主要版本的发布而改变,您不应该混合使用 CRT 类型(多线程、调试、发布、静态、动态等)。
通常,通过动态链接 CRT 可以将这些问题最小化。我在 VS2005 中重用 VS2003 库时取得了成功,但这很烦人,最好重新编译整个项目。有时,您可以使用 /NODEFAULTLIB 编译器标志来避免与某个导致问题的 CRT 库进行链接。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接