Reputation: 33
I have a working executable here and I'm trying to build a DLL from the same code, but I'm having some strange errors and managed to pinpoint the culprits after a lot of trial an error, I decided to ask for help because I'm really stuck now. I'm linking both SDL2 and Cimgui (Dear Imgui C Wrapper) statically in my code, the executable works perfectly fine:
#include "imgui/imgui.h"
#include "cimgui.h"
#pragma comment(lib, "cimgui.lib")
#include "SDL.h"
#undef main
#pragma comment(lib, "SDL2-staticd.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "imm32.lib")
#pragma comment(lib, "version.lib")
void main()
{
SDL_Init(0);
igCreateContext(0);
printf("OK");
}
So now I switch the project to DLL (I disabled that /IMPLIB
option to make sure the only difference in the link command is the /DLL
and the extension). When I try to build I get errors regarding cimgui.lib
like:
cimgui.lib(imgui_draw.obj) : error LNK2001: unresolved external symbol memcmp
cimgui.lib(imgui_widgets.obj) : error LNK2001: unresolved external symbol memcpy
cimgui.lib(imgui.obj) : error LNK2001: unresolved external symbol memset
Apparently the Visual C runtime isn't being linked anymore, I don't really understand why, I could just add it immediately but let's step back and remove Cimgui from the code:
#include "SDL.h"
#undef main
#pragma comment(lib, "SDL2-staticd.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "imm32.lib")
#pragma comment(lib, "version.lib")
extern "C" __declspec(dllexport) void main()
{
SDL_Init(0);
}
I get 13 errors similar to this:
MSVCRTD.lib(_init_.obj) : error LNK2019: unresolved external symbol _CrtDbgReport referenced in function _CRT_RTC_INIT
So I manually include the libs that contain the missing symbols: ucrtd.lib
, vcruntimed.lib
, and then the DLL builds fine.
Now I try to add Cimgui again, but it fails to build with errors like these:
MSVCRTD.lib(utility.obj) : error LNK2019: unresolved external symbol __vcrt_initialize referenced in function __scrt_initialize_crt
MSVCRTD.lib(utility.obj) : error LNK2019: unresolved external symbol __acrt_initialize referenced in function __scrt_initialize_crt
the __vcrt
definitions are in libvcruntimed.lib
, but the __acrt
definitions are in libucrtd.lib
, which conflicts with ucrtd.lib
, and even if I remove ucrtd.lib
altogether and try to link just libucrtd.lib
, I get errors like:
ucrtd.lib(ucrtbased.dll) : error LNK2005: malloc already defined in libucrtd.lib(malloc.obj)
Which I don't know how to interpret because I'm not linking ucrtd.lib
.
I don't really understand why building a DLL isn't just like building an Executable especially because the EXE binary is very similar to the DLL and I could even use it to interop as a DLL but that doesn't feel right. I'm sure there's a way to build this and I just don't know how.
For completeness (and just in case), here are the linker commands for the EXE and DLL:
/OUT:"C:\Projects\BuildTest\x64\Debug\Build.dll" /MANIFEST /NXCOMPAT /PDB:"C:\Projects\BuildTest\x64\Debug\Build.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /DLL /MACHINE:X64 /INCREMENTAL /PGD:"C:\Projects\BuildTest\x64\Debug\Build.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\Build.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /LIBPATH:"C:\Projects\cimgui_build\Debug" /LIBPATH:"C:\Projects\SDL2-2.0.8\build\Debug" /TLBID:1
/OUT:"C:\Projects\BuildTest\x64\Debug\Build.exe" /MANIFEST /NXCOMPAT /PDB:"C:\Projects\BuildTest\x64\Debug\Build.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"C:\Projects\BuildTest\x64\Debug\Build.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\Build.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /LIBPATH:"C:\Projects\cimgui_build\Debug" /LIBPATH:"C:\Projects\SDL2-2.0.8\build\Debug" /TLBID:1
EDIT:
I made a "Minimal, Complete and Verifiable Example" (Self-contained - dependencies included, relative paths, VS2017 project, should compile directly provided you have Windows SDK) and published online here:
https://bitbucket.org/AlanGameDev/buildmvce_so/downloads/
(you can download and extract or clone if you prefer)
Upvotes: 1
Views: 1282
Reputation: 16147
If you set the linker flag /VERBOSE to both exe/dll builds and diff the results, you'd get a clue as to what's going on.
In the exe build you'd see
1> Found mainCRTStartup
1> Loaded MSVCRTD.lib(exe_main.obj)
...
1> Found __xi_a
1> Referenced in MSVCRTD.lib(exe_main.obj)
1> Loaded MSVCRTD.lib(initializers.obj)
1>Processed /DEFAULTLIB:kernel32.lib
1> Processed /DISALLOWLIB:msvcrt.lib
1> Processed /DISALLOWLIB:libcmt.lib
1> Processed /DISALLOWLIB:libcmtd.lib
1> Processed /DISALLOWLIB:vcruntime.lib
1>Processed /DEFAULTLIB:vcruntimed.lib
1> Processed /DISALLOWLIB:libvcruntime.lib
1> Processed /DISALLOWLIB:libvcruntimed.lib
1> Processed /DISALLOWLIB:ucrt.lib
1>Processed /DEFAULTLIB:ucrtd.lib
1> Processed /DISALLOWLIB:libucrt.lib
1> Processed /DISALLOWLIB:libucrtd.lib
none of which appear in the dll build. In the dll build you'd see only -
1> Found _DllMainCRTStartup
1> Loaded SDL2-staticd.lib(SDL.obj)
Which is very weird. It seems SDL2 includes its own implementation of the entry point _DllMainCRTStartup, and since the linker takes it from there and not the crt lib - it misses a whole lot of useful /DEFAULTLIB pragmas.
Googling around it seems the _dllMainCRTStartup is included within SDL to satisfy some Watcom needs, and it was already suspected to cause trouble in MSVC.
If you build SDL from sources you should probably just comment out the _dllMainCRTStartup implementation and (hopefully) build successfully.
Upvotes: 1