I have a C astronomical library that I want to use in my C++ application.
I've built it in Visual Studio 2012 Express in both Win32 and x64 configurations, and:
...so that is 2 * 4 = 8 total binaries (not counting *.pdb files, etc.)
Then I use Batch Build to build all configurations, as sometimes I need different versions and I find getting this all done at the start and with a process is better than haphazardly when it's easy to mix things up.
Well in my C++ app, I have the same process, and link to the library based on the name. Specifically, in my project properties Linker -> Input field, I have:
SwissEphemeris_$(Platform)_$(Configuration).lib
...and the Additional Library Directories is properly set. Everything seems right. The library files are in the library directory.
Out of the 8 total configurations I have, all are linking and building properly except for two:
For both of these configurations, the same linker error:
main.obj : error LNK2019: unresolved external symbol _swe_close referenced in function _main
I have tried some things to diagnose or fix, but none have worked:
/MACHINE
linker flagswe_close()
in Win32 dynamic debug configuration and linked to that *.lib.The error is always the same, as shown above. I've turned on verbose linker output, and what really puzzles me is that the linker seems to successfully find and read the SwissEphemeris_Win32_DynamicDebug.lib
file, but still cannot find the swe_close()
symbol within it. Even when dumpbin.exe
shows that symbol, among all the other ones I need, are in it.
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 ==========
scratching head
Does anyone have any idea why the linker is failing to find the symbol, and ONLY for Win32 dynamic debug/release, but working fine for all 6 other configurations?
Just to be sure that the library was indeed built for Win32/X86, here is the linker command-line options from the library project's properties:
(paths are slightly different than the paths above--where the linker attempts to find the library--because the library is first built to this 'bin' directory and then copied to the library directory, which is definitely happening.)
/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
Output from 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)
...
Where the DLL is defined for export in the library header file. Only MAKE_DLL
and PASCAL
are defined, so the only statements here that are active are the #define PASCAL_CONV PASCAL
and the #else /* 32bit DLL */
block.
/* 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
...Then the actual function swe_close()
declaration looks like:
ext_def( void ) swe_close(void);
They use a lot of macro footwork, so this resolves to:
extern __declspec(dllexport) void far PASCAL swe_close();
I am unfamiliar with the far
and the PASCAL
. Could these be interfering with anything? And why would the x64 configuration work fine with this, but the Win32 break?
9 8 00001389 _swe_close@0 = @ILT+900(_swe_close@0)
There's a clear mismatch between the function name in the DLL and the one that the linker is looking for. The DLL project has it compiled to an __stdcall function, you can tell from the @0 decoration, the linker is looking for a __cdecl function.
That can be caused by a compiler option, /Gd vs /Gz but that's unlikely and you already checked it. The more likely cause is the .h file where the exported functions are declared so that another project can #include it and use the DLL. That's usually done with macro soup so that the __declspec(dllexport) and __declspec(dllimport) attributes are correct for usage. And the calling convention should always be explicitly declared, typically with another macro. Like the way the WINAPI macro is used in Windows SDK headers. I'll put a buck on that soup being the cause.