C++ static variable in .lib does not initialize

2019-02-18 05:36发布

问题:

I have static library (.lib) in VS2010 and am linking it to my test project.

The lib has a factory that I create using the below MACRO:

#define REGISTER_FACTORY(mType, my_class) \
class Factory##my_class : public CAbstractFactory\
{\
public:\
    Factory##my_class() : CAbstractFactory(mType){}\
    CBaseClass *Create()\
    { return new my_class(); }\
};\
static Factory##my_class StaticFactory##my_class;

What is supposed to happen is that in the CAbstractFactory the new factory gets registered by mtype. But when I check the factory the factory does not exist.

It works fine when I use a DLL instead of a .lib. My guess is that the linker does not include the static variable as it is not referenced or the static variable was not even included in the library.

How can I force the linker to include all objects from the static library in my .exe.

I use the macro like this:

// Register factory that can create CMyObject with ID=100
REGISTER_FACTORY(100, CMyObject);

class CMyObject
{
};

The CAbstractFactory looks like this:

class CAbstractFactory {
    CAbstractFactory(int id) {
        CFactory::instance().add(id, this);
    }
}

Then some where else in the code, my main .exe I use:

CBaseClass *pObject = CFactory::instance().Create(100);

This will then give my a new CMyObject. The idea is that I have many different kind object and I have a database containing the id specifying the kind of objects I need. 100 is just an example.

So indeed, I do not reference anything from the .lib directly but I want to be able to create the objects using my factory

The CFactory class is a simple class that keeps a register (in a map) of all the CAbstractFactory classes and delegates the create method to the correct factory.

CFactory &CFactory::Instance()
{
    static CFactory instance;
    return instance;
}

The main problem lies in the fact that I do not reference anything from the .lib as it is all done through the CFactory. It works if I make it a DLL and make sure I add some reference to this DLL to make sure it is loaded. But for a .lib, I even added a dummy function to make sure I have at least one reference that doesn't include the rest of the code.

回答1:

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



回答2:

static defines an object with internal linkage --> if it's not used internally in the same translation unit, it can be optimized out. Remove the static from your instantiation for the object to have external linkage - Factory##my_class StaticFactory##my_class;