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

时间:2013-11-11 03:30:48

标签: c++ visual-studio-2012 dll unresolved-external

背景

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

我已在 Win32 x64 配置中在Visual Studio 2012 Express中构建它,并且:

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

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

然后我使用Batch Build来构建所有配置,因为有时我需要不同的版本,并且我发现在开始时完成这一切,并且当一个过程很容易混淆时,过程优于偶然。< / p>

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

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

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

这是麻烦:

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

  1. Win32动态调试
  2. Win32动态发布
  3. 对于这两种配置,相同的链接器错误:

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

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

    1. 在新的解决方案/项目中从头开始重建库,确保 Win32 x64 之间没有/MACHINE链接器标志
    2. 之间的偏差
    3. 创建一个新的解决方案/项目,只有一个main()在Win32动态调试配置中调用此库函数swe_close()并链接到* .lib。
    4. 错误始终相同,如上所示。我打开了详细的链接器输出,让我感到困惑的是链接器似乎成功找到并读取了SwissEphemeris_Win32_DynamicDebug.lib文件,但仍然无法在其中找到swe_close()符号。即使dumpbin.exe显示该符号(在我需要的所有其他符号中)也在其中。

      1>  Unused libraries:
      1>    E:\Data\Code\lib\SwissEphemeris\SwissEphemeris_Win32_DynamicDebug.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\user32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\gdi32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\winspool.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\comdlg32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\advapi32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\shell32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\ole32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\oleaut32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\uuid.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\odbc32.lib
      1>    C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\odbccp32.lib
      1>    E:\Programs\VS2012\VC\lib\OLDNAMES.lib
      1>  
      1>main.obj : error LNK2019: unresolved external symbol _swe_close referenced in function _main
      1>E:\Data\Code\test\Debug\test.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:\Data\Code\libBuilders\SwissEphemeris\bin\SwissEphemeris_Win32_DynamicDebug.dll" 
      /MANIFEST 
      /NXCOMPAT 
      /PDB:"E:\Data\Code\libBuilders\SwissEphemeris\bin\SwissEphemeris_Win32_DynamicDebug.pdb" 
      /DYNAMICBASE 
      /IMPLIB:"E:\Data\Code\libBuilders\SwissEphemeris\bin\SwissEphemeris_Win32_DynamicDebug.lib" 
      /DEBUG 
      /DLL 
      /MACHINE:X86 
      /SAFESEH 
      /PGD:"E:\Data\Code\libBuilders\SwissEphemeris\bin\SwissEphemeris_Win32_DynamicDebug.pgd" 
      /SUBSYSTEM:CONSOLE 
      /MANIFESTUAC:"level='asInvoker' uiAccess='false'" 
      /ManifestFile:"E:\Data\Code\libBuilders\SwissEphemeris\obj\SwissEphemeris_Win32_DynamicDebug\SwissEphemeris_Win32_DynamicDebug.dll.intermediate.manifest" 
      /ERRORREPORT:PROMPT 
      /NOLOGO 
      

      dumpbin.exe /exports

      的输出
      E:\Data\Code\lib\SwissEphemeris>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 中断?

1 个答案:

答案 0 :(得分:6)

 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)属性对于使用是正确的。并且应始终显式声明调用约定,通常使用另一个宏。就像Windows SDK头文件中使用WINAPI宏的方式一样。我会把汤放在原因上。