(Only needs to work for gcc 5.4, if a general solution can't be found)
I have a generic factory that I use to construct objects based on some key (like a string representing a class name). The factory must allow classes to register that may not be known at construction time (so I can't simply register a list of classes explicitly).
As a means of registering these keys and their associated constructors, I have another 'RegisterInFactory' (templated) class. In each class's source file, I construct an object in an anonymous namespace corresponding to that class. This way, each class is automatically registered to the factory once the global objects are constructed. These objects never get used or referenced outside of doing this initial registration task.
However, when the code is compiled into a static library, when that library is linked into an executable, these static objects never get constructed, so the classes don't register to the factory, and the factory can't create anything.
I'm aware of the -Wl,--whole-archive -lfoo
flag, which does include these global objects. But it also introduces a lot of 'multiple definition' errors. I'm aware that there's another flag that I can turn off the multiple definition errors, but I don't feel comfortable going without those errors. I'm aware of -u symbolName
to turn off specific symbol names from these multiple definition errors (at least that's what I think it does). However, there are just too many of these redundant functions for that to be realistic (mostly from protobuf classes).
Is there any way to tell the compiler not to optimize those objects out, but only those objects so I can avoid the multiple definition issue? Is there another pattern I might be able to follow that fits within the constraints? (Particularly that I do not know at compile time what classes may be registered to the factory.)
Simplified Example code: Factory.h:
template<Base>
class Factory{
...
template<Derived>
class RegisterInFactory{
RegisterInFactory(){
instance().regInFactory(derivedConstructorFunctional);
}
};
};
In Derived.cpp:
namespace{ BaseFactory::RegisterInFactory<Derived> registerMe{"Derived"}; }
Final note: I've gotten lucky to some degree where without the linker flags, they still get included, but the only way that seems to happen is if the Derived class is 'sufficiently' complicated. Or maybe it's if I use the Derived class directly within the linked executable. I can't really tell why it's worked when it has.
static
in namespace scope are not constructed until right before some code in that cpp file is used. Ergo, if no code in a cpp file is ever called, thosestatic
s may never be constructed. This has nothing to do with Gcc optimizations, this is how C++ works. MSVC is an oddball that ignores this and constructs all namespacestatic
s before startingmain
. – Brawl-Wl,--allow-multiple-definition
– Kvass