Search code examples
c++visual-c++static-librariesstatic-initialization

Calling function before main in static libraries


I have a type registration system for a custom form of runtime type information. Up until now I've used the following macro to call a registration function before main and register the types:

#define REGISTRATION                                    \
static void _register();                                \
namespace { struct temp { temp() { _register(); } }; }  \
static const temp CAT(temp, __LINE__);                  \
static void _register()

That way I can do this in lots of different cpp files:

REGISTRATION()
{
    RegisterNewType(vec2)
    ->RegisterMember("x", &vec2::x)
    ->RegisterMember("y", &vec2::y);
}

This works great. However this falls apart when I try and do this in a static library. It appears that this because C++ does not initialize static variables in static libraries.

I went googling for a solution and found this:

#define REGISTRATION                                  \
static void _register() __attribute__((constructor)); \
static void _register()

Which might solve my problem, but it turns out that I can only do that in clang and gcc. I am using msvc.

Is there a way to get this to work so I can have pre-main functions in libraries?

EDIT: Some more googling brought me to this:

#if defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define EXT_REGISTRATION_(f,p) \
        static void __cdecl f(void); \
        __declspec(allocate(".CRT$XCU")) void (__cdecl*f##_)(void) = f; \
        __pragma(comment(linker,"/include:" p #f "_")) \
        static void __cdecl f(void)
#ifdef _WIN64
#define EXT_REGISTRATION(f) EXT_REGISTRATION_(f,"")
#else
#define EXT_REGISTRATION(f) EXT_REGISTRATION_(f,"_")
#endif
#else
#define EXT_REGISTRATION(f) \
        static void f(void) __attribute__((constructor)); \
        static void f(void)
#endif

However the registration function is still not called. The debugger states that No symbols have been loaded.


Solution

  • I ended up finding a solution to this in a game engine called Ethereal. Credit goes to that guy for this code.

    Instead of having the one register function I have two:

    #define CAT_IMPL(a, b) a##b
    #define CAT(a, b) CAT_IMPL(a, b)
    
    #define REGISTER_EXTERN(cls)\
        template <typename T>\
        extern void register_func();\
        template <>\
        void register_func<cls>();\
        static const int CAT(temp, __LINE__) =\
            reg_helper::call<cls>(&register_func<cls>)
    
    #define REGISTER(cls)\
        template <> \
        void register_func<cls>()
    

    And then I have this helper function:

    namespace reg_helper
    {
        template <typename T>
        inline int call(void(*f)())
        {
            static const int s = [&f]() {
                f();
                return 0;
            }();
            return s;
        }
    }
    

    In header functions I define REGISTER_EXTERN(SomeClass);, and then in a cpp filesomewhere I use the register macro like before:

    REGISTER(SomeClass)
    {
        // This code will run before main
    }
    

    If you make a header file that lists all your REGISTER_EXTERN calls you can actually specify the order in which the the register functions will be run, since the first time the static is hit, it'll initialize and call the function. The helper ensures that the REGISTER function is only called once, since including the header in different places will re-initialize the static variable in each translation unit.

    This solves the problem of static libraries, since the headers will be included and the symbols will exist. And secondly it ensures I can initialize things in the right order.