协议缓冲区 + 压缩库 zlib = 未解决的外部符号问题。

3

我的程序(VS 2010)使用启用了HAVE_ZLIB选项的Google缓冲协议。我编译了最新版本的zlib并在项目中添加了.lib,但在链接时仍然出现以下错误:

1>libprotobuf.lib(gzip_stream.obj) : 错误 LNK2001: 未解析的外部符号 _inflateEnd 1>libprotobuf.lib(gzip_stream.obj) : 错误 LNK2001: 未解析的外部符号 inflateInit2 1>libprotobuf.lib(gzip_stream.obj) : 错误 LNK2001: 未解析的外部符号 _inflate 1>libprotobuf.lib(gzip_stream.obj) : 错误 LNK2001: 未解析的外部符号 deflateInit2 1>libprotobuf.lib(gzip_stream.obj) : 错误 LNK2001: 未解析的外部符号 _deflate 1>libprotobuf.lib(gzip_stream.obj) : 错误 LNK2001: 未解析的外部符号 _deflateEnd

我使用了dumpbin.exe /all zlib.lib,它说:

File Type: LIBRARY

....

245 public symbols

....

 4DBE __imp__inflateInit2_@16
 4DBE _inflateInit2_@16

此外,此列表中还有其他未解决的符号。

那么问题出在哪里呢?为什么链接器找不到这些函数?

更新:重新编译zlib后,现在是__imp__inflateInit2_@4


在构建zlib时(可能使用/Gz编译器开关),您似乎将__stdcall设置为默认的调用约定,而调用代码期望使用老旧的__cdecl - Igor Tandetnik
@Igor Tandetnik:刚刚检查了设置,那里是“__cdecl”,命令行参数中没有“/Gz”选项。 - fogbit
1
dumpbin说了算。@16是stdcall名称修饰的明显标志。还有一件事要检查:也许函数声明类似于void ZLIBAPI inflateEnd(...),而宏ZLIBAPI在一个地方扩展为__stdcall,但在另一个地方扩展为__cdecl - Igor Tandetnik
@IgorTandetnik:从我查看代码得到的信息来看,它编译为__cdecl。我重新编译了它,现在dumpbin.exe显示“_inflateEnd@4”,而不是“@16”。 - fogbit
你之前看的是 inflateInit2,而不是 inflateEnd。@ 符号后面的数字是所有函数参数所需的总字节数,因此对于不同的函数,它可能会有所不同。同样,这就是 __stdcall 名称修饰的工作原理(请参阅 此文档 中的“名称修饰”部分)。 - Igor Tandetnik
1个回答

2

zlib函数被定义为ZEXPORT。

如果ZLIB_WINAPI被定义,则ZEXPORT被定义为__stdcall,否则它没有值,并且所有zlib函数默认被定义为__cdecl。

当我在VS2015中编译zlib时,在zlib项目中定义了ZLIB_WINAPI,在我的C++项目中未定义ZLIB_WINAPI。

因此,我的项目在zlib.lib文件中寻找__cdecl函数,而zlib.lib文件被编译为__stdcall。

要解决这个问题,您需要告诉您的项目编译器,zlib.lib文件使用__stdcall调用约定。

可以通过以下方式实现:

#define ZLIB_WINAPI

之前

#include "....\zlib.h"

在您的项目中


1
虽然这个答案可能是正确的,请添加一些解释。传授基本逻辑比仅仅给出代码更重要,因为它有助于OP和其他读者自己修复此类问题。 - CodeMouse92
2
@JasonMc92 我添加了一个解释。 - user1438233

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