7

* Question revised (see below) *

I have a cpp file that defines a static global variable e.g.

static Foo bar;

This cpp file is compiled into an executable and a shared library. The executable may load the shared library at run time.

If I am on Linux there seem to be two copies of this variable. I assume one comes from the executable and one from the shared library. Other platforms (HP, Windows) there seems to be only one copy.

What controls this behavior on Linux and can I change it? For example is there a compiler or linker flag that will force the version of this variable from the shared library to be the same as the one from the executable?

* Revision of question *

Thanks for the answers so far. On re-examining the issue it is not actually the problem stated above. The static global variable above does indeed have multiple copies on Windows, so no difference to what I see on Linux.

However, I have another global variable (not static this time) which is declared in a cpp file and as extern in a header file.

On Windows this variable has multiple copies, one in the executable and one in each dll loaded up, and on Linux it only has one. So the question is now about this difference. How can I make Linux have multiple copies?

(The logic of my program meant the value of the static global variable was dependent of the value of the non-static global variable and I started accusing the wrong variable as being the problem)

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Reuben
  • 93
  • 1
  • 7

5 Answers5

7

I strongly suggest you read the following. Afterwards, you will understand everything about shared libraries in Linux. As said by others, the quick answer is that the static keyword will limit the scope of the global variable to the translation unit (and thus, to the executable or shared library). Using the keyword extern in the header, and compiling a cpp containing the same global variable in only one of the modules (exe or dll/so) will make the global variable unique and shared amongst all the modules.

EDIT: The behaviour on Windows is not the same as on Linux when you use the extern pattern because Windows' method to load dynamic link libraries (dlls) is not the same and is basically incapable of linking global variables dynamically (such that only one exists). If you can use a static loading of the DLL (not using LoadLibrary), then you can use the following:

//In one module which has the actual global variable:
__declspec(dllexport) myClass myGlobalObject;
//In all other modules:
__declspec(dllimport) myClass myGlobalObject;

This will make the myGlobalObject unique and shared amongst all modules that are using the DLL in which the first version of the above is used.

If you want each module to have its own instance of the global variable, then use the static keyword, the behaviour will be the same for Linux or Windows.

If you want one unique instance of the global variable AND require dynamic loading (LoadLibrary or dlopen), you will have to make an initialization function to provide every loaded DLL with a pointer to the global variable (before it is used). You will also have to keep a reference count (you can use a shared_ptr for that) such that you can create a new one when none exist, increment the count otherwise, and be able to delete it when the count goes to zero as DLLs are being unloaded.

Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
  • The Windows behavior was stated incorrectly. See revised question for actual difference between Windows and Linux. – Reuben Feb 07 '11 at 21:25
  • See my updated answer. Also, reading the article I linked to will explain why Linux is able to achieve this and why it is hard and apparently not possible in Windows. – Mikael Persson Feb 07 '11 at 22:08
  • 1
    The answer was in the linked document section 2.2. Because of the older compiler version I was restricted to and I could change the source where the variable was declared I ended up using export maps (section 2.2.5) – Reuben Mar 23 '11 at 21:55
4

The static qualifier applied to a namespace variable means that the scope of the variable is the translation unit. That means that if that variable is defined in a header and you include it from multiple .cpp files you will get a copy for each. If you want a single copy, then mark it as extern (and not static) in the header, define it in a single translation unit and link that in either the executable or the library (but not both).

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
1

What compiler did you use on each of these platforms? The behavior you're describing for Linux would be what I'd expect, the static global is only local to that particular file at compile time.

stackmate
  • 908
  • 9
  • 17
  • The Windows behavior was stated incorrectly. See revised question for actual difference between Windows and Linux. Windows compiler is MS Visual Studio 2003 Linux is gcc 3.3.3 HP is aC++/ANSI C B3910B A.06.01 [Jan 05 2005] – Reuben Feb 07 '11 at 21:31
  • @Reuben: These are very old compilers, you should consider an update for both platforms. I don't think it will change the behaviour though. – Mikael Persson Feb 07 '11 at 22:10
1

You may be able to work around your issue using the GCC visibility attribute or the visibility pragma

Hasturkun
  • 35,395
  • 6
  • 71
  • 104
0

I don't know about HPUX, but on Windows, if you have an exe and a DLL, and they each declare global variables, then there will be two distinct variables. If you are only getting a single variable then one image must be importing the variable from the other.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490