从 Visual Studio 2012 使用 GnuTLS 3.1.6 时获取"error LNK2001: unresolved external symbol _gnutls_free"

Getting "error LNK2001: unresolved external symbol _gnutls_free" when using GnuTLS 3.1.6 from Visual Studio 2012

本文关键字:LNK2001 error unresolved symbol free gnutls external 获取 使用 2012 Studio      更新时间:2023-10-16

我正在尝试在Visual Studio 2012中构建一个使用GnuTLS的项目。我从网站上下载了最新的官方Windows版本,并通过在Visual Studio命令提示符下的bin目录中运行lib /def:libgnutls-28.def创建了一个链接库。

添加 typedef long ssize_t 后,代码可以正常编译,但链接失败并显示以下错误:

source_file.obj : error LNK2001: unresolved external symbol _gnutls_free
C:Pathtoexecutable.exe : fatal error LNK1120: 1 unresolved externals

我正在调用gnutls_free以释放库分配和返回的一些内存。如果我删除对gnutls_free的调用,项目链接成功。鉴于gnutls_free只是库导出的全局变量(包含函数指针),我不确定为什么访问它会导致对不同符号的未解析引用。我已经验证了gnutls_free没有#define任何东西。

作为测试,我尝试执行gnutls_free_function test = gnutls_free;这也导致了链接错误。在 GnuTLS 源代码上运行grep -w -r _gnutls_free .什么也没返回,所以我不知所措。

任何

使这项工作的想法将不胜感激。

编辑:

__declspec(dllimport)添加到gnutls.h中的gnutls_free声明可使链接成功。有没有办法在不维护头文件的自定义版本的情况下完成此操作?

似乎没有办法让链接器或导入库自动取消引用 IAT 指向数据项的指针,就像对函数所做的那样(通过静态链接到导入函数的模块的小蹦床函数)。 __declspec(dllimport) 属性告诉编译器需要执行此取消引用,以便它可以插入代码以隐式执行 IAT 指针的取消引用。这允许访问导出的数据,并且对于函数,编译器可以通过 IAT 指针的间接调用而不是通过调用蹦床函数来调用导入的函数。

请参阅Raymond Chen关于dllimport的几篇文章,以很好地解释函数调用的情况(不幸的是,他没有讨论导入数据):

  • 调用导入的函数,幼稚的方式
  • 不那么朴素的编译器如何调用导入的函数

MS 链接器或导入库没有帮助编译器以"幼稚"方式获取导入数据的机制 - 编译器需要__delcspec(dllimport)提示,即需要通过 IAT 进行额外的取消引用。无论如何,这一切的重点是,除了使用 __declspec(dllimport) 属性之外,似乎没有办法导入数据。

如果您想避免修改gnutls发行版(我可以理解),这里有一个相当不完美的解决方法:

你可以创建一个小的对象文件,它只包含一个简单的gnutls_free()包装器;由于gnutls_free()有一个没有真正依赖的接口,你可以让必要的声明"硬编码"而不是包含gnutls.h

typedef void (*gnutls_free_function) (void *);
__declspec(dllimport) extern gnutls_free_function gnutls_free;
void xgnutls_free(void* p)
{
    gnutls_free(p);
}

让您的代码调用xgnutls_free()而不是gnutls_free()

不是一个很好的解决方案 - 它需要您的代码调用包装器(因此,如果您要合并可能依赖于gnutls_free()的第三方代码,则尤其不好),但它可能已经足够好了。