Sharing a global/static variable between a process and DLL Sharing a global/static variable between a process and DLL linux linux

Sharing a global/static variable between a process and DLL


To get the behavior of linux where both the main program and a dll share the same x, you can export that variable from either the dll, or the main program. The other module must import that variable.

You do this by using DEF files (see microsoft's documentation), or by marking the uses with the variable with __declspec(dllexport) where it's defined, and __declspec(dllimport) in any other module it's used (see microsoft's documentation). This is the same as how any function, object, or variable is shared between modules in windows.

In the case where you'd like a program to load a library at runtime, but the main program may have to use the variable before the library is loaded, the program should export the variable, and the dll should import it. There is a little bit of a chicken and egg problem here because the dll depends on the main program, and the main program depends on the dll. See http://www.lurklurk.org/linkers/linkers.html#wincircular

I've written an example of how you can do this using both Microsoft's compiler and mingw (gcc in windows), including all the different ways a program and a library can link to each other (statically, dll loaded at program start, dll loaded during runtime)

main.h

#ifndef MAIN_H#define MAIN_H// something that includes this// would #include "linkage_importing.h"// or #include "linkage_exporting.h"// as appropriate#ifndef EXPLICIT_MAINLINKAGE int x;#endif // EXPLICIT_MAIN#endif // MAIN_H

main.c

#ifdef EXPLICIT_DLL#include "dyn_link.h"#endif // EXPLICIT_DLL#include <stdio.h>#include "linkage_exporting.h"#include "main.h"#include "linkage_importing.h"#include "dll.h"FNCALL_DLL get_call_dll(void);int main(int argc, char* argv[]){   FNCALL_DLL fncall_dll;   fncall_dll = get_call_dll();   if (fncall_dll)   {      x = 42;      printf("Address of x as seen from main() in main.c: %p\n", &x);      printf("x is set to %i in main()\n", x);      fncall_dll();      // could also be called as (*fncall_dll)();      // if you want to be explicit that fncall_dll is a function pointer      printf("Value of x as seen from main() after call to call_dll(): %i\n", x);   }   return 0;}FNCALL_DLL get_call_dll(void){#ifdef EXPLICIT_DLL   return get_ptr("dll.dll", "call_dll");#else   return call_dll;#endif // EXPLICIT_DLL}

dll.h

#ifndef DLL_H#define DLL_H// something that includes this// would #include "linkage_importing.h"// or #include "linkage_exporting.h"// as appropriate// declaration of type to hold a// pointer to the functiontypedef void(*FNCALL_DLL)(void);#ifndef EXPLICIT_DLLLINKAGE void call_dll(void);#endif // EXPLICIT_DLL#endif // DLL_H

dll.c

#ifdef EXPLICIT_MAIN#include "dyn_link.h"#endif // EXPLICIT_MAIN#include <stdio.h>#include "linkage_importing.h"#include "main.h"#include "linkage_exporting.h"#include "dll.h"int* get_x_ptr(void);LINKAGE void call_dll(void){   int* x_ptr;   x_ptr = get_x_ptr();   if (x_ptr)   {      printf("Address of x as seen from call_dll() in dll.c: %p\n", x_ptr);      printf("Value of x as seen in call_dll: %i()\n", *x_ptr);      *x_ptr = 31415;      printf("x is set to %i in call_dll()\n", *x_ptr);   }}int* get_x_ptr(void){#ifdef EXPLICIT_MAIN   return get_ptr("main.exe", "x");   // see note in dyn_link.c about using the main program as a library#else   return &x;#endif //EXPLICIT_MAIN}

dyn_link.h

#ifndef DYN_LINK_H#define DYN_LINK_H// even though this function is used by both, we link it// into both main.exe and dll.dll as necessary.// It's not shared in a dll, because it helps us load dlls :)void* get_ptr(const char* library, const char* object);#endif // DYN_LINK_H

dyn_link.c

#include "dyn_link.h"#include <windows.h>#include <stdio.h>void* get_ptr(const char* library, const char* object){   HINSTANCE hdll;   FARPROC ptr;   hdll = 0;   ptr = 0;   hdll = LoadLibrary(library);   // in a better dynamic linking library, there would be a   // function that would call FreeLibrary(hdll) to cleanup   //   // in the case where you want to load an object in the main   // program, you can use   // hdll = GetModuleHandle(NULL);   // because there's no need to call LoadLibrary on the   // executable if you can get its handle by some other means.   if (hdll)   {      printf("Loaded library %s\n", library);      ptr = GetProcAddress(hdll, object);      if (ptr)      {         printf("Found %s in %s\n", object, library);      } else {         printf("Could not find %s in %s\n", object, library);      }   } else {      printf("Could not load library %s\n", library);   }   return ptr;}

linkage_importing.h

// sets up some macros to handle when to use "__declspec(dllexport)",// "__declspec(dllimport)", "extern", or nothing.// when using the LINKAGE macro (or including a header that does)://    use "#include <linkage_importing.h>" to make the LINKAGE macro//    do the right thing for importing (when using functions,//    variables, etc...)////    use "#include <linkage_exporting.h>" to make the LINKAGE macro//    do the right thing for exporting (when declaring functions,//    variables, etc).////    You can include either file at any time to change the meaning of//    LINKAGE.// if you declare NO_DLL these macros do not use __declspec(...), only// "extern" as appropriate#ifdef LINKAGE#undef LINKAGE#endif#ifdef NO_DLL   #define LINKAGE extern#else   #define LINKAGE extern __declspec(dllimport)#endif

linkage_exporting.h

// See linkage_importing.h to learn how this is used#ifdef LINKAGE#undef LINKAGE#endif#ifdef NO_DLL   #define LINKAGE#else   #define LINKAGE __declspec(dllexport)#endif

build mingw explicit both.sh

#! /bin/bashecho Building configuration where both mainecho and dll link explicitly to each otherrm -rf mingw_explicit_bothmkdir -p mingw_explicit_both/objcd mingw_explicit_both/obj# compile the source code (dll created with position independent code)gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.cgcc -c -DEXPLICIT_DLL ../../main.cgcc -c ../../dyn_link.c#create the dll from its object code the normal waygcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a# create the executablegcc -o main.exe main.o dyn_link.omv dll.dll ..mv main.exe ..cd ..

build mingw explicit dll.sh

#! /bin/bashecho Building configuration where main explicitlyecho links to dll, but dll implicitly links to mainrm -rf mingw_explicit_dllmkdir -p mingw_explicit_dll/objcd mingw_explicit_dll/obj# compile the source code (dll created with position independent code)gcc -c -fPIC ../../dll.cgcc -c -DEXPLICIT_DLL ../../main.cgcc -c ../../dyn_link.c# normally when linking a dll, you just use gcc# to create the dll and its linking library (--out-implib...)# But, this dll needs to import from main, and main's linking library doesn't exist yet# so we create the linking library for main.o# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)gcc -omain.exe -shared main.o -Wl,--out-implib,main.a  #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a#create the dll from its object code the normal way (dll needs to know about main's exports)gcc -shared -odll.dll dll.o dyn_link.o main.a -Wl,--out-implib,libdll.a# create the executablegcc -o main.exe main.o dyn_link.omv dll.dll ..mv main.exe ..cd ..

build mingw explicit main.sh

#! /bin/bashecho Building configuration where dll explicitlyecho links to main, but main implicitly links to dllrm -rf mingw_explicit_mainmkdir -p mingw_explicit_main/objcd mingw_explicit_main/obj# compile the source code (dll created with position independent code)gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.cgcc -c ../../main.cgcc -c ../../dyn_link.c# since the dll will link dynamically and explicitly with main, there is no need# to create a linking library for main, and the dll can be built the regular waygcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a# create the executable (main still links with dll implicitly)gcc -o main.exe main.o -L. -ldllmv dll.dll ..mv main.exe ..cd ..

build mingw implicit.sh

#! /bin/bashecho Building configuration where main andecho dll implicitly link to each otherrm -rf mingw_implicitmkdir -p mingw_implicit/objcd mingw_implicit/obj# compile the source code (dll created with position independent code)gcc -c -fPIC ../../dll.cgcc -c ../../main.c# normally when linking a dll, you just use gcc# to create the dll and its linking library (--out-implib...)# But, this dll needs to import from main, and main's linking library doesn't exist yet# so we create the linking library for main.o# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)gcc -omain.exe -shared main.o -Wl,--out-implib,main.a  #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a# create the dll from its object code the normal way (dll needs to know about main's exports)gcc -shared -odll.dll dll.o main.a -Wl,--out-implib,libdll.a# create the executable (exe needs to know about dll's exports)gcc -o main.exe main.o -L. -ldllmv dll.dll ..mv main.exe ..cd ..

build mingw static.sh

#! /bin/bashecho Building configuration where main and dllecho statically link to each otherrm -rf mingw_staticmkdir -p mingw_static/objcd mingw_static/obj# compile the source codegcc -c -DNO_DLL ../../dll.cgcc -c -DNO_DLL ../../main.c# create the static libraryar -rcs dll.a dll.o# link the executablegcc -o main.exe main.o dll.amv main.exe ../cd ..

build msvc explicit both.bat

@echo offecho Building configuration where both mainecho and dll link explicitly to each otherrd /s /q win_explicit_bothmd win_explicit_both\objcd win_explicit_both\objrem compile the source codecl /nologo /c /DEXPLICIT_MAIN ..\..\dll.ccl /nologo /c /DEXPLICIT_DLL ..\..\main.ccl /nologo /c ..\..\dyn_link.crem create the dll from its object code the normal waylink /nologo /dll dll.obj dyn_link.objrem create the executablelink /nologo main.obj dyn_link.objmove dll.dll ..\move main.exe ..\cd ..

build msvc explicit dll.bat

@echo offecho Building configuration where main explicitlyecho links to dll, but dll implicitly links to mainrd /s /q win_explicit_dllmd win_explicit_dll\objcd win_explicit_dll\objrem compile the source codecl /nologo /c ..\..\dll.ccl /nologo /c /DEXPLICIT_DLL ..\..\main.ccl /nologo /c ..\..\dyn_link.crem normally when linking a dll, you just use the link commandrem that creates the dll and its linking library.rem But, this dll needs to import from main, and main's linking library doesn't exist yetrem so we create the linking library for main.objrem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)lib /nologo /def /name:main.exe main.objrem create the dll from its object code the normal way (dll needs to know about main's exports)link /nologo /dll dll.obj main.librem create the executablelink /nologo main.obj dyn_link.objmove dll.dll ..\move main.exe ..\cd ..

build msvc explicit main.bat

@echo offecho Building configuration where dll explicitlyecho links to main, but main implicitly links to dllrd /s /q win_explicit_mainmd win_explicit_main\objcd win_explicit_main\objrem compile the source codecl /nologo /c /DEXPLICIT_MAIN ..\..\dll.ccl /nologo /c ..\..\main.ccl /nologo /c ..\..\dyn_link.crem since the dll will link dynamically and explicitly with main, there is no needrem to create a linking library for main, and the dll can be built the regular waylink /nologo /dll dll.obj dyn_link.objrem create the executable (main still links with dll implicitly)link /nologo main.obj dll.libmove dll.dll ..\move main.exe ..\cd ..

build msvc implicit.bat

@echo offecho Building configuration where main andecho dll implicitly link to each otherrd /s /q win_implicitmd win_implicit\objcd win_implicit\objrem compile the source codecl /nologo /c ..\..\dll.ccl /nologo /c ..\..\main.crem normally when linking a dll, you just use the link commandrem that creates the dll and its linking library.rem But, this dll needs to import from main, and main's linking library doesn't exist yetrem so we create the linking library for main.objrem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)lib /nologo /def /name:main.exe main.objrem create the dll from its object code the normal way (dll needs to know about main's exports)link /nologo /dll dll.obj main.librem create the executable (exe needs to know about dll's exports)link /nologo main.obj dll.libmove dll.dll ..\move main.exe ..\cd ..

build msvc static.bat

@echo offecho Building configuration where main and dllecho statically link to each otherrd /s /q win_staticmd win_static\objcd win_static\objrem compile the source codecl /nologo /DNO_DLL /c ..\..\dll.ccl /nologo /DNO_DLL /c ..\..\main.crem create the static librarylib /nologo dll.objrem link the executablelink /nologo main.obj dll.libmove main.exe ..\cd ..


First, I found that this article was a very interesting and a concise read on dynamic link libraries (the article is only specific to Linux, but the concepts surely apply to windows as well and you might get some insight as to the different behaviour you are seeing). Especially the fundamental difference between static and dynamic loading.

I think what you want or are trying to implement is a "cross-module singleton" pattern. If you read the answers to this thread, I don't know how I could possibly answer your question any better than Ben Voigt answered that post. I have implemented a cross-module singleton before (a few times actually) using the method he describes, and it works like a charm.

Of course, you will not be able to retain the cleaniness of just having the global variable sit there in the cpp file. You will have to use a static pointer and some accessor functions and reference counting. But it can work. I'm not so sure how it would be possible to avoid that foo.exe and foo.exe share the same instance of global data one bar.dll, I never had to do that and can't really think of a way to do it, sorry.


If foo.exe always loads bar.dll then you can implement the variable in bar.dll and export it. For example, some file b.cpp compiled only into bar.dll, not into foo.exe:

__declspec(dllexport) int x;

Then import it in a source file c.cpp compiled into foo.exe:

__declspec(dllimport) int x;

However, if sometimes foo.exe doesn't load bar.dll then this won't work. Also, I'm writing this from memory and so there might be some syntactical errors, but hopefully it's enough to point you in the right direction.

I can't answer why it's different Linux.