链接器读取库,但在其中找不到符号?未解析的外部符号,但仅适用于 Win32 而不是 x64

Linker reads library but can't find symbol within it? Unresolved External Symbol but only for Win32 and not x64

本文关键字:符号 适用于 外部 x64 Win32 读取 在其中 找不到 链接      更新时间:2023-10-16

Background

我有一个 C 天文库,我想在我的 C++ 应用程序中使用它。

我已经在Visual Studio 2012 Express中以Win32x64配置构建了它,并且:

  • 动态调试 (.dll)
  • 动态释放 (.dll)
  • 静态调试 (.lib)
  • 静态发布 (.lib)

。所以这是 2 * 4 = 8 个二进制文件(不包括 *.pdb 个文件等)

然后我使用批量构建来构建所有配置,因为有时我需要不同的版本,我发现在开始时完成所有工作并通过一个过程比在容易混淆时随意完成要好。

在我的C++应用程序中,我有相同的过程,并根据名称链接到库。具体来说,在我的项目属性链接器->输入字段中,我有:

SwissEphemeris_$(Platform)_$(Configuration).lib

。并且已正确设置其他库目录。一切似乎都是对的。库文件位于库目录中。

这是麻烦:

在我总共拥有的 8 个配置中,除了两个之外,所有配置都正确链接和构建:

  1. Win32 动态调试
  2. Win32 动态发布

对于这两种配置,相同的链接器错误:

main.obj : error LNK2019: unresolved external symbol _swe_close referenced in function _main

我已经尝试了一些诊断或修复的方法,但没有一个奏效:

  1. 在新的解决方案/项目中从头开始重建库,确保 Win32x64 之间没有偏差,除了 /MACHINE 链接器标志之外
  2. 创建一个新的解决方案/项目,只有一个main(),该 main() 在 Win32 动态调试配置中swe_close()调用此库函数并链接到该 *.lib。

错误始终相同,如上所示。我已经打开了详细的链接器输出,真正让我困惑的是链接器似乎成功地找到并读取了SwissEphemeris_Win32_DynamicDebug.lib文件,但仍然无法在其中找到swe_close()符号。即使dumpbin.exe表明,在我需要的所有其他符号中,该符号都在其中。

1>  Unused libraries:
1>    E:DataCodelibSwissEphemerisSwissEphemeris_Win32_DynamicDebug.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86user32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86gdi32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86winspool.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86comdlg32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86advapi32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86shell32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86ole32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86oleaut32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86uuid.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86odbc32.lib
1>    C:Program Files (x86)Windows Kits8.0libwin8umx86odbccp32.lib
1>    E:ProgramsVS2012VClibOLDNAMES.lib
1>  
1>main.obj : error LNK2019: unresolved external symbol _swe_close referenced in function _main
1>E:DataCodetestDebugtest.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

挠头

有没有人知道为什么链接器找不到该符号,并且仅适用于 Win32 动态调试/发布,但适用于所有其他 6 种配置?

为了确保库确实是为 Win32/X86 构建的,下面是库项目属性中的链接器命令行选项:

(路径与上面的路径略有不同 - 链接器尝试查找库 - 因为库首先构建到这个"bin"目录,然后复制到库目录,这肯定会发生。

/OUT:"E:DataCodelibBuildersSwissEphemerisbinSwissEphemeris_Win32_DynamicDebug.dll" 
/MANIFEST 
/NXCOMPAT 
/PDB:"E:DataCodelibBuildersSwissEphemerisbinSwissEphemeris_Win32_DynamicDebug.pdb" 
/DYNAMICBASE 
/IMPLIB:"E:DataCodelibBuildersSwissEphemerisbinSwissEphemeris_Win32_DynamicDebug.lib" 
/DEBUG 
/DLL 
/MACHINE:X86 
/SAFESEH 
/PGD:"E:DataCodelibBuildersSwissEphemerisbinSwissEphemeris_Win32_DynamicDebug.pgd" 
/SUBSYSTEM:CONSOLE 
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" 
/ManifestFile:"E:DataCodelibBuildersSwissEphemerisobjSwissEphemeris_Win32_DynamicDebugSwissEphemeris_Win32_DynamicDebug.dll.intermediate.manifest" 
/ERRORREPORT:PROMPT 
/NOLOGO 

dumpbin.exe /exports输出

E:DataCodelibSwissEphemeris>dumpbin /exports SwissEphemeris_Win32_DynamicDebug.dll
Microsoft (R) COFF/PE Dumper Version 11.00.50727.1
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file SwissEphemeris_Win32_DynamicDebug.dll
File Type: DLL
  Section contains the following exports for SwissEphemeris_Win32_DynamicDebug.dll
    00000000 characteristics
    528041A6 time date stamp Sun Nov 10 19:32:06 2013
        0.00 version
           1 ordinal base
         131 number of functions
         131 number of names
    ordinal hint RVA      name
          1    0 00001195 _swe_azalt@40 = @ILT+400(_swe_azalt@40)
          2    1 000011FE _swe_azalt_d@28 = @ILT+505(_swe_azalt_d@28)
          3    2 000012AD _swe_azalt_rev@24 = @ILT+680(_swe_azalt_rev@24)
          4    3 00001357 _swe_azalt_rev_d@20 = @ILT+850(_swe_azalt_rev_d@20)
          5    4 0000126C _swe_calc@24 = @ILT+615(_swe_calc@24)
          6    5 000011BD _swe_calc_d@20 = @ILT+440(_swe_calc_d@20)
          7    6 0000105F _swe_calc_ut@24 = @ILT+90(_swe_calc_ut@24)
          8    7 00001235 _swe_calc_ut_d@20 = @ILT+560(_swe_calc_ut_d@20)
          9    8 00001389 _swe_close@0 = @ILT+900(_swe_close@0)
         10    9 00001212 _swe_close_d@4 = @ILT+525(_swe_close_d@4)
         ...

在库头文件中定义用于导出的 DLL 的位置。仅定义了MAKE_DLLPASCAL,因此此处唯一处于活动状态的语句是 #define PASCAL_CONV PASCAL#else /* 32bit DLL */ 块。

/* DLL defines */
#ifdef MAKE_DLL
  #if defined (PASCAL)
    #define PASCAL_CONV PASCAL 
  #else
    #define PASCAL_CONV
  #endif
  #ifdef MAKE_DLL16 /* 16bit DLL */
    /* We compiled the 16bit DLL for Windows 3.x using Borland C/C++ Ver:3.x
       and the -WD or -WDE compiler switch. */
    #define EXP16 __export 
    #define EXP32 
  #else /* 32bit DLL */
    /* To export symbols in the new DLL model of Win32, Microsoft 
       recommends the following approach */ 
    #define EXP16 
    #define EXP32  __declspec( dllexport )
  #endif
#else 
  #define PASCAL_CONV 
  #define EXP16 
  #define EXP32 
#endif 

。然后声明swe_close()的实际函数如下所示:

ext_def( void ) swe_close(void);

他们使用大量的宏观步法,因此这解析为:

extern __declspec(dllexport) void far PASCAL swe_close();

我不熟悉farPASCAL.这些会干扰什么吗?为什么 x64 配置可以正常工作,但 Win32 会中断?

 9    8 00001389 _swe_close@0 = @ILT+900(_swe_close@0)

DLL 中的函数名称与链接器要查找的函数名称之间存在明显的不匹配。 DLL 项目已将其编译为__stdcall函数,您可以从 @0 修饰中看出链接器正在寻找__cdecl函数。

这可能是由编译器选项/Gd vs/Gz 引起的,但这不太可能,您已经检查过它。 更可能的原因是声明导出函数的 .h 文件,以便另一个项目可以 #include 它并使用 DLL。 这通常是用宏汤完成的,以便__declspec(dllexport)和__declspec(dllimport)属性是正确的用法。 调用约定应始终显式声明,通常使用另一个宏。 就像 WINAPI 宏在 Windows SDK 标头中的使用方式一样。 我会在汤上花钱