DLL LNK2019错误(未解决的外部错误__imp)

3
我基本上继承了一堆代码,被告知需要修复它,因为它几个月前还能工作,但现在不行了。 这个程序本身似乎充斥着链接错误,我能够修复其中的一些。 但是,我遇到了一个 LNK2019 无法解决的外部 _imp 错误,其中主函数中使用的某个函数未被解析。由于 "_imp" 的存在,我认为这是与从.dll 或 .lib 文件导入相关的问题。

首先,我有三个 .lib 文件,我认为我已经正确地将它们导入到 VS2010 中,并且已将平台配置为 64x。还有与 .lib 文件相对应的 .dll 文件。包含声明这些错误函数的 .h 文件看起来像是:

ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num);

很遗憾,我猜测该定义是在.dll文件中定义的,而我没有编写这个文件,所以我不确定。但由于这是之前可以工作的代码,我认为我之所以会出现这个错误是因为连接器找不到定义,而不是 def / decl 不匹配的原因。
当我悬停在ILAPI上时,它显示:“ILAPI __declspec(dllimport)” 我目前的猜测是程序导入.lib文件,.lib文件使用.dll文件获取函数的定义。我相信我正在导入.lib文件,因为编译器不再告诉我找不到特定的.lib文件。然而,我担心它可能没有连接到.dll文件。我有些不确定。我已经打开了.lib文件,.lib文件包含给出错误的函数名称。我还使用了dependency walker程序查看我的DLL文件,它一直在给我以下错误:
错误:由于隐式依赖模块中缺少导出函数,至少一个模块具有未解决的导入。
错误:发现不同CPU类型的模块。
基于其他人的评论,我觉得我可以忽略第二个错误。但是我不确定第一个错误。我也不确定那是否是问题的根本原因。可以是也可以不是。
我还使用VS cmd和dependency walker查看了.lib文件的内部,似乎无法找到的函数名称在其中一个.lib和.dll中列出。
在配置方面,我正在运行发布模式x64平台。 我在proj->prop->linker->commandline中添加了“DevIL.lib ILU.lib ILUT.lib”库函数。我还添加了链接器->general->additional library directory的路径。我也尝试过使用input additional dependency进行调整,但没有效果。.lib和.dll文件也放在同一个目录中。在proj属性配置中,我没有在任何地方提到.dll(我应该吗?我尝试了不同的位置,但仍然出现错误)。我知道有大量关于link 2019错误的帖子,但我迄今为止在搜索我的特定问题时并没有好运。我将感激任何建议、评论或可以找到线索的链接,以便了解为什么会发生这种情况。
以下是来自日志的链接器命令:
以下是构建日志本身的链接器命令:
链接: C:\ Program Files(x86)\ Microsoft Visual Studio 10.0 \ VC \ bin \ x86_amd64 \ link.exe / ERRORREPORT:PROMPT / OUT:“x64 \ Release \ dff.exe” / VERBOSE / INCREMENTAL / NOLOGO / LIBPATH:C:\ Users \ Sub2 \ Desktop \ dff \ x64 \ Release / MANIFEST / ManifestFile:“x64 \ Release \ dff.exe.intermediate.manifest” / MANIFESTUAC:“level ='asInvoker' uiAccess ='false'” / DEBUG / PDB:“C:\ Users \ Sub2 \ Desktop \ dff \ x64 \ Release \ dff.pdb” / SUBSYSTEM:CONSOLE / OPT:REF / OPT:ICF / TLBID:1 / DYNAMICBASE / NXCOMPAT / IMPLIB:“x64 \ Release \ dff.lib” / MACHINE:X64 x64 \ Release \ dff.exe.embed.manifest.res x64 \ Release \ acquisition.obj x64 \ Release \ azmemutil.obj x64 \ Release \ dff.obj x64 \ Release \ fft.obj x64 \ Release \ FocusMeasure.obj x64 \ Release \ ge.obj x64 \ Release \ stdafx.obj DevIL.lib ILU.lib ILUT.lib 1>链接:警告LNK4075:由于'/ OPT:ICF'规范,忽略'/ INCREMENTAL'
    // This is from Win32's <wingdi.h> and <winnt.h>
    #if defined(__LCC__)
        #define ILAPI __stdcall
    #elif defined(_WIN32) //changed 20031221 to fix bug 840421
        #ifdef IL_STATIC_LIB
            #define ILAPI
        #else
            #ifdef _IL_BUILD_LIBRARY
                #define ILAPI __declspec(dllexport)
            #else
                #define ILAPI __declspec(dllimport)
            #endif
        #endif
    #elif __APPLE__
        #define ILAPI extern
    #else
        #define ILAPI
    #endif

此外:
    #define ILAPIENTRY __stdcall 

当接近错误时,生成日志信息:

           Found KERNEL32_NULL_THUNK_DATA
             Referenced in kernel32.lib(KERNEL32.dll)
             Loaded kernel32.lib(KERNEL32.dll)
         Searching C:\Users\Sub2\Desktop\dff\x64\Release\DevIL.lib:
         Searching C:\Users\Sub2\Desktop\dff\x64\Release\ILU.lib:
         Searching C:\Users\Sub2\Desktop\dff\x64\Release\ILUT.lib:
         Searching C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64\MSVCRT.lib:
         Searching C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64\OLDNAMES.lib:
         Searching C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64\msvcprt.lib:

     Finished searching libraries

     Finished pass 1


     Invoking CVTRES.EXE:
      /machine:amd64
      /verbose
      /out:"C:\Users\Sub2\AppData\Local\Temp\lnk92ED.tmp"
      /readonly
      "x64\Release\dff.exe.embed.manifest.res"
     Microsoft (R) Windows Resource To Object Converter Version 10.00.30319.01
     Copyright (C) Microsoft Corporation.  All rights reserved.

     adding resource. type:MANIFEST, name:1, language:0x0409, flags:0x30, size:2
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluGetImageInfo referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluImageParameter referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilDeleteImages referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilSaveImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluFlipImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluScale referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilTexImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilCopyPixels referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilGetError referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilLoadImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilBindImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilGenImages referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilInit referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilGetInteger referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilEnable referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilOriginFunc referenced in function main
 1>x64\Release\dff.exe : fatal error LNK1120: 16 unresolved externals
 1>Done Building Project "C:\Users\Sub2\Desktop\dff\dff.vcxproj" (rebuild target(s)) -- FAILED.

构建失败。

为了确保,我还尝试编写#define _IL_BUILD_LIBRARY,但没有效果。


1
我通过编辑提供了更多关于何时将ILAPI定义为declspec(dllimport)的信息。 - undefined
嗯,如何最有效地检查这个呢?我现在正在查看我的构建日志,但它没有指明编译器如何看待ilDeleteImage()。然而,有一些行代码发生了以下情况:找到了"__declspec(dllimport) public: int __cdecl std::basic_streambuf<char,struct std::char_traits<char> >::sputc(char)" (_imp?sputc@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QEAAHD@Z) 在dff.obj中引用 在fft.obj中引用 加载了msvcprt.lib(MSVCP100.dll) - undefined
添加了有关构建日志的更多信息 - undefined
对于msvc,你可以使用/P开关来实现这个 - undefined
很遗憾,我没有。我有.dll文件和.lib文件。我也有使用.dll和.lib构建我的exe的源文件。对于.dll和.lib的详细规格,对我来说是个谜。关于导出函数看起来像__cdecl,而头文件声明它们为__stdcall,我是否可以只将__cdecl切换为__stdcall来解决这个冲突,还是创建.def文件是解决这个可能冲突的唯一方法? - undefined
显示剩余43条评论
2个回答

5
我在这里添加一个答案,简要总结一下上面的评论,可能的根本原因并找到解决未解决错误的方法。我首先要说的是,链接器往往是愚笨的低级工具。如果目标文件中引用的符号与库不完全匹配,则构建过程会以这些未解析的错误退出。因此,dll库的作者和使用它的客户端需要付出一些努力来确保符号一致。
根本原因
未解析的错误通常由以下原因之一引起:
1. 项目和链接的库都没有实现该符号的函数。 2. 实际上,库确实实现了该函数,但是参考符号不同。 3. 库的标题没有经过正确处理或装饰,从而导致#2。
寻找
根据OP所描述的,链接的dll库公开了C API。不清楚该库遵循哪种调用约定。 dll中导出的名称包含未装饰的函数名称,表明采用 __cdecl 约定。提供的对应头文件却有以下函数:
ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num);

预处理之后,它会被扩展成这样:

__declspec(dllimport) void __stdcall ilDeleteImage(const ILuint Num);

从这里你可以得出三种可能的情况:
  1. 未解决的函数遵循 __cdecl 约定,提供的头文件是错误的。
  2. 未解决的函数遵循 __stdcall 约定,导出的 dll 名称是错误的。
  3. 函数遵循 __stdcall 但在 dll 中未装饰,看起来像 __cdecl。这表明可能使用了一个 .def 文件来构建相关的 dll。

可悲的局面

不幸的是,在 win32 dll 中遵循的函数调用约定处于混乱状态。标准 C 或 C++ 中没有任何内容描述这个 ABI 问题。参见我在此处的另一个回答。工具链供应商可以自由地以任何方式装饰名称,但对于 __cdecl 函数,它通常是未装饰或附有前缀的下划线 _

你能找到的 WinAPI 函数,如 kernel32.dlluser32.dllgdi32.dll 等,也都未装饰,但遵循 __stdcall。然而,MSVC 本身会将 __stdcall 装饰为带有参数总字节数的结尾和符号(例如,ilDeleteImage@4),从而导致混乱。要覆盖 LINK 装饰函数的方式,必须提供一个指定新名称别名的 .def 文件。了解更多详细信息,请参见此处

查找真实约定

假设你无法访问用于构建 dll 的源代码,则我可以想到两种方法来识别实际使用的约定。

创建一个最小化的测试应用程序,调用 dll 函数,就像它使用 __cdecl 一样,并查看是否崩溃。这是更简单、更直接的方法,你不需要理解汇编语言来完成它。

第二种方法是进行相同的操作,但在测试应用程序中插入汇编断点,并通过单步执行指令运行它。确保选择一个至少需要一个参数的 dll 函数。例如:

// pullin dll headers
// etc..

int main()
{
  __asm int 3;
  ilDeleteImage(0xdecafbad);
}

在dll函数调用之前,这将中断并将控制权还给调试器。从这里开始,在汇编级别单步执行,直到达到ilDeleteImage的函数序言。

 ; function prologue
 push   ebp
 mov    ebp, esp
 ; function implemention
 ; more opcodes here
 ; ...

 ; function epilogue
 mov    esp, ebp
 pop    ebp
 ret    0x8

检查函数返回时使用的ret形式。跟随ret助记符的数字参数表示需要增加多少esp栈指针。任何大于0的数字都表明这是一个__stdcall函数。上面的假设反汇编显示了一个__stdcall函数在栈上释放了8个字节,这也暗示着该函数需要2个参数。


0

在使用外部静态库 QDBM 和 PCRE 构建项目时,我遇到了这个编译错误:

_main.obj : error LNK2001: unresolved external symbol __imp__dpversion
_main.obj : error LNK2001: unresolved external symbol __imp__regcomp

我已经正确配置了这些外部项目以构建静态库,但是我忘记在使用这些库的自己的代码中定义正确的预处理器定义,以启用静态链接。

所以当他们导入QDBM和PCRE的头文件时,他们添加了一个不应该存在的__declspec(dllimport)(用于静态链接),因此他们试图从不存在的DLL中导入符号。

我在我的构建系统中添加了缺失的预处理器定义,这修复了错误:

-DQDBM_STATIC -DPCRE_STATIC

这意味着我需要在我的CMakeLists.txt文件中添加以下几行代码:
# Tell QDBM not to build itself as a DLL, because we want to link statically to it.
target_compile_definitions(qdbm PUBLIC -DQDBM_STATIC)
target_compile_definitions(lib_common PUBLIC -DPCRE_STATIC)

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