Consider code
EXE:
int main ()
{
printf("Executable Main, loading library\n");
#ifdef HAVE_WINDOWS
HMODULE lib = LoadLibraryA ("testdll.dll");
#elif defined(HAVE_LINUX)
void * lib = dlopen("testdll.so", RTLD_LAZY);
#endif
if (lib) {
printf("Executable Main, Freeing library\n");
#ifdef HAVE_WINDOWS
FreeLibrary (lib);
#elif defined(HAVE_LINUX)
dlclose(lib);
#endif
}
printf("Executable Main, exiting\n");
return 0;
}
DLL
struct Moo
{
Moo() { printf("DLL Moo, constructor\n"); }
~Moo() { printf("DLL Moo, destructor\n"); }
};
Moo m;
#ifdef HAVE_WINDOWS
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DllMain, DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
printf("DllMain, DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
printf("DllMain, DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
printf("DllMain, DLL_PROCESS_DETACH\n");
break;
default:
printf("DllMain, ????\n");
break;
}
return TRUE;
}
#else
CP_BEGIN_EXTERN_C
__attribute__((constructor))
/**
* initializer of the dylib.
*/
static void Initializer(int argc, char** argv, char** envp)
{
printf("DllInitializer\n");
}
__attribute__((destructor))
/**
* It is called when dylib is being unloaded.
*
*/
static void Finalizer()
{
printf("DllFinalizer\n");
}
CP_END_EXTERN_C
#endif
The output differs:
On windows
Executable Main, loading library
DLL Moo, constructor
DllMain, DLL_PROCESS_ATTACH
Executable Main, Freeing library
DllMain, DLL_PROCESS_DETACH
DLL Moo, destructor
Executable Main, exiting
Linux
Executable Main, loading library
DllInitializer
DLL Moo, constructor
Executable Main, Freeing library
DllFinalizer
DLL Moo, destructor
Executable Main, exiting
On windows, Moo constructor is called before DLLMain and whereas on linux it is called after Initializer defined using attribute((constructor)).
WHY?
Moo constructor isn't called before
DllMain
, it is called fromDllMain
. To be precise, its called from the realDllMain
, the function Windows calls first. This realDllMain
calls C++ constructors and then calls your C++DllMain
. The reason for this realDllMain
is exactly to initialize constructors, something which wasn't needed in C beforeLinux (GCC/ELF) doesn't have this concept at all; it only has constructors. Your manual ctor and the C++ ctor for Moo are treated the same.
There is a way:
StartupCleanup.cpp:
DllMain.cpp:
You DllMain must be just an empty shell and do your usual safe initialization and termination in those constructor and destructor like for Linux.
NOTE: Beware! you cannot create/delete threads inside static or global constructors/destructors if you plan to synchronize them. That's all folks !
EDIT: you also need to call needStartupAndCleanup() in a function you know it is linked, otherwise the object file StartupCleanup.obj will be discarded and those global constructor/destructor as well.