C++ 获得;错误LNK2001:未解析的外部符号“U gnutls”“U free”;使用Visual Studio 2012中的GnuTLS 3.1.6时

C++ 获得;错误LNK2001:未解析的外部符号“U gnutls”“U free”;使用Visual Studio 2012中的GnuTLS 3.1.6时,c++,visual-c++,linker-errors,gnutls,C++,Visual C++,Linker Errors,Gnutls,我正试图在VisualStudio2012中构建一个使用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:\Path\t

我正试图在VisualStudio2012中构建一个使用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:\Path\to\executable.exe : fatal error LNK1120: 1 unresolved externals
我正在调用
gnutls\u free
来释放库分配和返回的一些内存。如果我删除对
gnutls\u free
的调用,则项目链接成功。鉴于
gnutls\u free
只是库导出的一个全局变量(包含函数指针),我不确定为什么访问它会导致对不同符号的未解析引用。我已经验证了
gnutls\u free
没有定义任何内容

作为测试,我试着做
gnutls\u free\u函数测试=gnutls\u free也会导致链接错误。在gnutls源代码上运行
grep-w-r\u gnutls\u free.
不会返回任何内容,因此我感到不知所措

如果您有任何能让这项工作顺利进行的想法,我们将不胜感激

编辑:


\u declspec(dllimport)
添加到
gnutls.h
中的
gnutls\u free
声明中,允许链接成功。有没有办法在不维护头文件自定义版本的情况下实现这一点?

似乎没有办法让链接器或导入库以与函数相同的方式自动取消对IAT指向数据项的指针的引用(通过静态链接到导入该功能的模块中的小型蹦床功能)。
\uu declspec(dllimport)
属性告诉编译器需要执行此取消引用,以便它可以插入代码来隐式执行IAT指针的取消引用。这允许访问导出的数据,而对于函数,则允许编译器通过IAT指针的间接调用调用导入的函数,而不是通过调用trampol非对称函数

请参阅Raymond Chen的几篇关于
dllimport
的文章,了解函数调用的详细说明(遗憾的是,他没有讨论导入数据):

MS链接器或导入库没有帮助编译器以“简单”的方式获取导入数据的机制-编译器需要
\u delcspec(dllimport)
提示需要通过IAT进行额外的取消引用。无论如何,这一切的关键在于,似乎除了使用
\u declspec(dllimport)
属性外,没有其他方法导入数据

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

您可以为
gnutls\u free()
创建一个小对象文件,其中只包含一个简单的包装器;因为
gnutls\u 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\u free()
而不是
gnutls\u free()


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

似乎没有办法让链接器或导入库自动取消IAT指向数据项的指针引用,方法与函数相同(通过静态链接到导入函数的模块中的小型蹦床函数)。
\u declspec(dllimport)
属性告诉编译器需要执行此取消引用,以便它可以插入代码来隐式执行IAT指针的取消引用。这允许访问导出的数据,而对于函数,则允许编译器通过IAT指针的间接调用调用导入的函数,而不是通过调用trampol非对称函数

请参阅Raymond Chen的几篇关于
dllimport
的文章,了解函数调用的详细说明(遗憾的是,他没有讨论导入数据):

MS链接器或导入库没有帮助编译器以“简单”的方式获取导入数据的机制-编译器需要
\u delcspec(dllimport)
提示需要通过IAT进行额外的取消引用。无论如何,这一切的关键在于,似乎除了使用
\u declspec(dllimport)
属性外,没有其他方法导入数据

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

您可以为
gnutls\u free()
创建一个小对象文件,其中只包含一个简单的包装器;因为
gnutls\u 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\u free()
而不是
gnutls\u free()


这不是一个很好的解决方案-它需要您的代码调用包装器(因此,如果您要合并可能依赖于
gnutls\u free()
)的第三方代码,这就特别不好了,但它可能已经足够好了。

非常有用,谢谢。是否有必要将头文件中的所有声明都标记为
\u declspec(dllimport)
而不修改每个声明?(我想如果有的话,你可能会提到它。)@rkjnsn:我不知道。此外,如果你计划将
declspec
添加到标题中,请使用宏(如
#define GNUTLS\D