Q:

different behavior when linking with static library vs using object files in C++

I'm working with some legacy C++ code which is behaving in a way I don't understand. I'm using the Microsoft compiler but I've tried it with g++ (on linux) as well--same behavior.
I have 4 files listed below. In essence it's a registry that's keeping track of a list of members. If I compile all files and link the object files into one program it shows the correct behavior: registry.memberRegistered is true:
>cl shell.cpp registry.cpp member.cpp
>shell.exe
1

So somehow the code in member.cpp gets executed (which I don't really understand, but OK). 
However, what I want is to build a static library from registry.cpp and member.cpp, and link that against the executable built from shell.cpp. But when I do this, the code in member.cpp does not get executed and registry.memberRegistered is false:
>cl registry.cpp member.cpp  /c
>lib registry.obj member.obj -OUT:registry.lib
>cl shell.cpp registry.lib
>shell.exe
0

My questions: how come it works the first way and not the second and is there a way (e.g. compiler/linker options) to make it work with the second way?
Thanks a bunch in advance.

registry.h:
class Registry {
public:

    static Registry& get_registry();
    bool memberRegistered;

private:
    Registry() {
        memberRegistered = false; 
    }
};

registry.cpp:
#include "registry.h"
Registry& Registry::get_registry() {
    static Registry registry;
    return registry;
}

member.cpp:
#include "registry.h"

int dummy() {
    Registry::get_registry().memberRegistered = true;
    return 0;
}
int x = dummy();

shell.cpp:
#include <iostream>
#include "registry.h"

class shell {
public:
    shell() {};
    void init() {
        std::cout << Registry::get_registry().memberRegistered;
    };
};
void main() {
    shell *cf = new shell;
    cf->init();
}

A:

You have been hit by what is popularly known as static initialization order fiasco.
The basics is that the order of initialization of static objects across translation units is unspecified. See this
The call here Registry::get_registry().memberRegistered; in "shell.cpp" may happen before the call here int x = dummy(); in "member.cpp"
EDIT:
Well, x isn't ODR-used. Therefore, the compiler is permitted not to evaluate int x = dummy(); before or after entering main(), or even at all.
Just a quote about it from CppReference (emphasis mine)

It is implementation-defined whether dynamic initialization
  happens-before the first statement of the main function (for statics)
  or the initial function of the thread (for thread-locals), or deferred
  to happen after.
If the initialization is deferred to happen after the first statement
  of main/thread function, it happens before the first odr-use of any
  variable with static/thread storage duration defined in the same
  translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library)...

The only way to get your program working as you want is to make sure x is ODR-used
shell.cpp
#include <iostream>
#include "registry.h"

class shell {
public:
    shell() {};
    void init() {
        std::cout << Registry::get_registry().memberRegistered;
    };
};

extern int x;   //or extern int dummy();

int main() {
    shell *cf = new shell;
    cf->init();
    int k = x;   //or dummy();
}

^ Now, your program should work as expected. :-)

A:

This is a result of the way linkers treat libraries: they pick and choose the objects that define symbols left undefined by other objects processed so far.  This helps keep executable sizes smaller, but when a static initialization has side effects, it leads to the fishy behavior you've discovered: member.obj / member.o doesn't get linked in to the program at all, although its very existence would do something.
Using g++, you can use:
g++ shell.cpp -Wl,-whole-archive registry.a -Wl,-no-whole-archive -o shell

to force the linker to put all of your library in the program.  There may be a similar option for MSVC.

