为什么在 VS2003 中编译的 .lib 无法与 VS2008 编译的代码链接?
我们刚刚尝试将一组使用 Visual Studio Express 2008 编译的代码与使用 Visual Studio 2003 编译的 .lib 链接起来,这是一次有趣的经历。全部用 C++ 编写。 准确的说,是在VS2003中编译成.lib的SystemC 2.2.0内核,以及一个SystemC模型这是在VS2008中编译的。
链接时,我们不断收到错误,链接期间未找到 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 中的 SystemC.lib。 现在,事情进展顺利。
所以这里的根本问题是:从 VS2003 到 VS2008 发生了什么变化,导致某些函数改变其调用约定? 是否有一些神奇的标志可以给予 VS2008 中的链接器以使用其他库,其中函数具有与 VS2003 编译中相同的调用约定?
更新,到目前为止的答案摘要:Microsoft 很可能将 C++(不是 C,只是 C++)ABI 从 Visual Studio 的一个主要版本更改为下一个版本。 库中还可能存在其他导致不兼容的更改。 最好的建议是为每个版本的 VS 重新编译 .lib。 本质上,只需将其以源代码形式发送给用户,并让他们使用他们碰巧安装的任何版本的 VS 在本地编译它。
通过使用以下建议发现了基本问题:
请注意,这些问题没有回答此问题:
We just had an interesting experience in trying to link a set of code compiled using Visual Studio Express 2008 with a .lib compiled with Visual Studio 2003. All in C++. To be precise, it was the SystemC 2.2.0 kernel that was compiled in VS2003 into a .lib, and a SystemC model which was compiled in VS2008.
When linking, we kept getting the error that a few symbols from the SystemC.lib file (i.e., compiled in VS2003) were not found during linking. The error we get getting was this (in a few variants):
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)
Digging on from various leads, it turned out that the function the .lib expected to find was this:
Undecoration of :- "?_Xran@_String_base@std@@QBEXXZ"
is :- "public: void __thiscall std::_String_base::_Xran(void)const "
While the library file that VS2008 was trying to link with (libcpmt.lib) used a different calling convention:
Undecoration of :- "?_Xran@_String_base@std@@SAXXZ"
is :- "public: static void __cdecl std::_String_base::_Xran(void)"
I tried to figure out why this incompatibility happened, but in the end I gave up, recompiled the exact same visual studio project in VS2008, and used that SystemC.lib instead of the one from VS2003. Now, things worked perfectly.
So the fundamental question here is: what has changed from VS2003 to VS2008 that would cause some functions to change their calling conventions? And is there some magic flag to give to the linker in VS2008 to use some other library where the functions have the same calling convention as in the VS2003 compile?
Update, summary of answers so far: It is very likely that Microsoft changes the C++ (not C, just C++) ABI from one major version of Visual Studio to the next. There can also be other changes in the libraries that cause incompatibilities. The best advice is to recompile the .lib for each version of VS. Essentially, just ship it in source to the users and have them compile it locally using whatever version of VS they happen to have installed.
The basic issue was discovered by using the advice in:
Note that these questions did not answer this issue:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
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 类)
There is no standard for the C++ ABI. Which means that all the c++ compiler could handle a different ABI from one to the other, and that includes different version from the same compiler. You could have the same issue with 2 different major release from Gcc.
Such modification could happen when they find a way to improve linking step.
But ABI involve much more that that. For instance the way vtable are stored and handle behind the hood by the code generated by the compiler. If it changes, your objects and your code generated in 2008 won't be compatible with the library expecting the way it is done in 2003.
At this point you could understand why c++ libraries are either shipped with their source code or shipped compiled on many different architecture and compilers.
Usually when writing a library, in order to avoid such issues, you develop it in C langage, not c++. As C comes with a standardised ABI, you are able to compile it with one compiler and then link that library with any C compiler wich respect that C ABI standard.
For instance the way character string is implemented is standard and will probably never move (the infamous null terminated string).
While std::string implementation changes from one Gcc major release to the other (just have a look in the basic_string class from /usr/include/c++/x.x/bits/basic_string files)
据我所知,这些问题是由于 CRT 库而发生的,它们随着主要版本的变化而变化,并且您不应该混合 CRT 类型(多线程、调试、发布、静态、动态等)。
通常它们可以通过与 CRT 动态链接来最小化,我在 VS2005 中成功地重用了 VS2003 库,但这很烦人,最好重新编译整个东西。
有时,您可以使用 /NODEFAULTLIB 编译器标志来避免与某个导致问题的 CRT 库链接。
As far as I know these problems happen because of the CRT library, they change with major releases and you shouldn't mix CRT types(multi-threaded, debug, release, static, dynamic, etc).
Usually they can be minimized by linking dynamically with CRT, I had success reusing VS2003 libraries in VS2005 but it's annoying, it's better to just recompile the whole thing.
Sometimes you can get away by using the /NODEFAULTLIB compiler flag to avoid linking with a certain CRT library that's causing problems.