C++ Static Variable in .Lib Does Not Initialize

C++ static variable in .lib does not initialize

I had a similar problem and solved it by setting the lib project as a dependency of the main app project and then setting 'Link Library Dependencies' and 'Use Library Dependency Inputs' to Yes for the main project.


Update:

Recently I discovered that Visual Studio 2015 now supports a /WHOLEARCHIVE linker flag. I can't find it through the linker options, but you can add it as an additional command line option. It works similar to the GCC flag -whole-archive and you add it to your target linker flags (not to the static lib flags).

For example, specify /WHOLEARCHIVE:lib_name as an additional linker command line option and it will include all symbols from that lib. You can do this more than one lib as well.

If you use this /WHOLEARCHIVE:lib_name you no longer need the 'Link Library Dependencies' and 'Use Library Dependency Inputs' set to Yes. This is perfect for solutions generated through CMAKE. See a related answer here: https://stackoverflow.com/a/42083877/1151329

Static variable initialization over a library

As a general rule of thumb, an application do not include static or global variables from a library unless they are implicitly or explicitly used by the application.

There are hundred different ways this can be refactored. One method could be to place the static variable inside function, and make sure the function is called.

C++ global variable not initialized when linked through static libraries, but OK when compiled with source

I believe your object file from the library is not getting linked. Look how Microsoft handles the acrtused symbol (search case insensitive, I do not remember the case and there's no MSVC on this machine).

Once you know how they handle acrtused, do the same thing with your global variable to force it to get linked.

Will update if I find the answer.

Here are a couple of possibilities to force things to link and initialize in a somewhat forced order.

Look here for a GCC answer.

Look here for MSVC10.

Static initialization in linked library under Windows C++

Is the "library file" part of the final executable. If it is an
object file in a statically linked library, it will only be part
of the final executable if it resolves an otherwise unresolved
external symbol. (This is the definition of a library.) If you
never use any symbol in the object file, it won't be part of
your executable, and it's as if the source file wasn't part of
the application.

If the library is dynamically loaded, the situation is slightly
different; a .dll is loaded as a unit (and not object file by
object file, so it's not really a library), but if there are no
unresolved symbols which would be resolved by loading the DLL,
it won't be loaded either.

What you probably want to do is link against the object files,
and not against a library. In Visual Studios, this means
putting all of the sources in the same project. Or... you can
link the library as a .dll, and then explicitly load it using
LoadLibrary. (This is what we do for libraries which are only
referenced because they have constructors of static objects
which register themselves.)

What happens to static variables when libraries are statically linked

First of all:

(B) and (C) do NOT link against (A). Static libs are compiled, not linked.
When building (B) and (C) the compiler might need to see certain definitions from (A) but do not confuse this with linking. (A's) code is not copied into (B) or (C).

Secondly:

(D) will have to link against (A), (B) and (C). That means you get only one copy of (A's) code in (D).

Dynamic-link Library/Shared Object:

This of course would be different if (B) and (C) were dlls/sos instead. Dlls are linked and so if you build (B) and (C) as dlls and link them against (A) then you would have a separate copy of (A's) code in both (B) and (C).

Are (B) and (C) seing the same static variable from (A)

This depends on if your variable has external or internal linkage. The following header file contains a static int variable with interal linkage. This means that every translation unit that includes this file will get it's own copy of myVariable.

//MyHeader.h
#pragma once
static int myVariable = 0;

What happens to global and static variables in a shared library when it is dynamically linked?

This is a pretty famous difference between Windows and Unix-like systems.

No matter what:

  • Each process has its own address space, meaning that there is never any memory being shared between processes (unless you use some inter-process communication library or extensions).
  • The One Definition Rule (ODR) still applies, meaning that you can only have one definition of the global variable visible at link-time (static or dynamic linking).

So, the key issue here is really visibility.

In all cases, static global variables (or functions) are never visible from outside a module (dll/so or executable). The C++ standard requires that these have internal linkage, meaning that they are not visible outside the translation unit (which becomes an object file) in which they are defined. So, that settles that issue.

Where it gets complicated is when you have extern global variables. Here, Windows and Unix-like systems are completely different.

In the case of Windows (.exe and .dll), the extern global variables are not part of the exported symbols. In other words, different modules are in no way aware of global variables defined in other modules. This means that you will get linker errors if you try, for example, to create an executable that is supposed to use an extern variable defined in a DLL, because this is not allowed. You would need to provide an object file (or static library) with a definition of that extern variable and link it statically with both the executable and the DLL, resulting in two distinct global variables (one belonging to the executable and one belonging to the DLL).

To actually export a global variable in Windows, you have to use a syntax similar to the function export/import syntax, i.e.:

#ifdef COMPILING_THE_DLL
#define MY_DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define MY_DLL_EXPORT extern "C" __declspec(dllimport)
#endif

MY_DLL_EXPORT int my_global;

When you do that, the global variable is added to the list of exported symbols and can be linked like all the other functions.

In the case of Unix-like environments (like Linux), the dynamic libraries, called "shared objects" with extension .so export all extern global variables (or functions). In this case, if you do load-time linking from anywhere to a shared object file, then the global variables are shared, i.e., linked together as one. Basically, Unix-like systems are designed to make it so that there is virtually no difference between linking with a static or a dynamic library. Again, ODR applies across the board: an extern global variable will be shared across modules, meaning that it should have only one definition across all the modules loaded.

Finally, in both cases, for Windows or Unix-like systems, you can do run-time linking of the dynamic library, i.e., using either LoadLibrary() / GetProcAddress() / FreeLibrary() or dlopen() / dlsym() / dlclose(). In that case, you have to manually get a pointer to each of the symbols you wish to use, and that includes the global variables you wish to use. For global variables, you can use GetProcAddress() or dlsym() just the same as you do for functions, provided that the global variables are part of the exported symbol list (by the rules of the previous paragraphs).

And of course, as a necessary final note: global variables should be avoided. And I believe that the text you quoted (about things being "unclear") is referring exactly to the platform-specific differences that I just explained (dynamic libraries are not really defined by the C++ standard, this is platform-specific territory, meaning it is much less reliable / portable).

Static variables in static lib vs dynamic dll

I found it. Like Mark Ransom said in the comments, the problem was not in the code, it was in my project properties. I was creating a .lib instead of dll, but didn't change the runtime library accordingly. So in Project Properties -> C/C++ -> All Options -> Runtime Library, I started using MD and it worked.

Also make sure Runtime Library and general use of MFC are compatible, look here for details.
I'm still not to sure of how using MT created problems, but at least I can run my program now.

initialisation of static object when linking against a static library

By default on many platforms, if your program doesn't reference any symbols from a given object file in a static library, the whole object file (including static initializers) will be dropped. So the linker is ignoring X.o in libX.a because it looks like it is unused.

There are a few solutions here:

  1. Don't depend on the side-effects of static initializers. This is the most portable/simple solution.
  2. Introduce some fake dependency on each file by referencing a dummy symbol in a way the compiler will not see through (like storing the address into a externally-visible global).
  3. Use some platform-specific trick to retain the objects in question. For example, on Linux you can use -Wl,-whole-archive a.o b.a -Wl,-no-whole-archive.


Related Topics



Leave a reply



Submit