My question is similar to these but doesn't seem to correlate exactly:
How to force inclusion of an object file in a static library when linking into executable?
Forcing symbol export with MSVC
What I've got is something like so:
struct thingy;
struct container
{
static container& instance(); // singleton
int register_thingy(thingy*);
};
struct thingy
{
virtual ~thingy() {}
virtual int id() const = 0;
};
//template trick to force registration.
template < typename Derived >
struct registered_thingy : thingy
{
registered_thingy() : my_id(my_static_id) {}
int id() const { return my_id; }
private:
int my_id;
static int my_static_id;
}
template < typename Derived >
int registered_thingy<Derived>::my_static_id =
container::instance().register_thingy(new Derived);
Now, in a concrete_thingy.cpp
file I have:
struct my_concrete_thingy : registered_thingy<my_concrete_thingy>
{
my_concrete_thingy() {} // registered_thingy's constructor not called otherwise
};
Of course, the above is totally useless, but there's real behavior being abstracted here.
This works wonderfully when used in an application that is compiled as a whole. The issue now is that I'm not able, so far, to use this technique while bottling up the behavior behind collection
in a library. In other words, I've got a thingys.lib
file that contains concrete_thingy.cpp
but the registration is not occurring when that is linked to an executable. The collection
ends up existing and working fine, but it's empty.
Now, this is a STATIC library, not a DLL. That may change the issue a little and the techniques spoken about in the links above don't seem to apply. The one of course is about functions and I don't see how I could apply it to these C++ structures.
I've tried to use the #pragma comment
method with the following three lines (individually of course) in concrete_thingy.cpp
, none of which worked:
#pragma comment (linker, "/export:concrete_thingy")
#pragma comment (linker, "/export:concrete_thingy::my_static_id")
#pragma comment (linker, "/export:registered_thingy<concrete_thingy>::my_static_id")
If concrete_thingy.cpp
is in the executable rather than the library everything works fine.
So then, here's my questions:
1) Is it possible to do what I'm trying to do? I'm guessing yes, but I just don't know how.
2) If it is possible, how would I get MSVC++ 2010 to do it?
3) If it is possible, how could I do it in a portable way?
In short, what I'm trying to do would be similar to creating an abstract factory that creates implementations of an abstraction. It knows nothing about these implementations, which are registered using global initialization trickery. This should all be in a static library that can be linked to by an application and these implementations should be available through that factory. Nobody knows anything about these implementations except themselves and thus normal linking is causing them, and their registration globals, to disappear.
It's not exactly what I'm up to, but it's close enough.
Edit: ====================================================
Looks like this behavior is "by design". MS recognizes that construction of object that cause side effects should occur whether or not their used, they use a loophole in the standard that allows them to not include translation units in which nothing is used :\
https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&wa=wsignin1.0&siteid=210
The /OPT:NOREF option is designed to not do anything in this case apparently.