为什么在VS2003中编译的.lib无法与使用VS2008编译的代码链接?

时间:2009-08-13 13:59:23

标签: visual-studio-2008 visual-studio-2003 calling-convention lnk2001

我们尝试将使用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编译相同的调用约定的其他库?

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

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

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

2 个答案:

答案 0 :(得分: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++/x.x/bits/basic_string文件中的basic_string类)

答案 1 :(得分:2)

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

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