I have several modules that build to static libraries. Depending on what's needed, some of the static libraries may be linked, and others may not. Several of these static libraries have classes that have a static Init() method. The "Core" library, which is also linked in, also has an Init() method, and previously it contained multiple lines like:
Telephony::Init();
But if Telephony is not going to be linked into this specific application, I don't want to have to modify the Core library's code to remove that line. So I tried something like:
class init_hook_base
{
public:
inline init_hook_base() { Core::AddInitHook(this); }
protected:
friend class Core;
virtual ~init_hook_base() {}
virtual void operator()() const = 0;
};
template<class T>
class init_hook_t
{
protected:
void operator()() const
{
T::Init();
}
};
And then I would just make a static global variable like:
static init_hook_t<Telephony> telephony_init_hook;
In the Telephony library, and that would allow Core to call Telephony::Init indirectly without knowing about it at compile time. Unfortunately, telephony_init_hook is not getting constructed, and I'm assuming it's getting stripped in the linking phase despite its constructor having side effects. Doing something like:
void Telephony::Init() { (void)telephony_init_hook; }
Also doesn't work, because Init itself is also unreachable as far as the linker is concerned. Is there a way to achieve this style of modularity with C++? Compiler specific options are viable, so long as there's an equivalent for both GCC and VC++. Thanks.
Note: For those concerned about global initialization order affecting Core::AddInitHook:
std::vector<init_hook_base*>* Core::init_hooks; //THESE ARE DELIBERATELY UNINITIALIZED!!!
unsigned char Core::init_hooks_ptr_hash[20];
bool Core::inited = false;
void Core::EnsureInitHooksContainerReady()
{
unsigned char current_hash[20];
sha1::calc(&init_hooks, sizeof(init_hooks), current_hash);
if (memcmp(current_hash, init_hooks_ptr_hash, 20))
{
//the hash is incorrect, so init_hooks is not yet initialized;
init_hooks = new std::vector<init_hook_base*>();
sha1::calc(&init_hooks, sizeof(init_hooks), init_hooks_ptr_hash);
}
}
void Core::AddInitHook(init_hook_base* init_hook)
{
EnsureInitHooksContainerReady();
init_hooks->push_back(init_hook);
}
void Core::Init()
{
assert(!inited);
PlatformInit();
EnsureInitHooksContainerReady();
for (auto init_hook_base : *init_hooks) {
(*init_hook_base)();
}
}