Devolus
Devolus

Reputation: 22094

static initializer is optimized away when it is in a library

I have a function which calls an initialization routine statically. This is needed for a pluginsystem where the plugin is either dynamically loaded (which works fine) or can also be statically linked. Since the static plugin is not known to the main application it must register itself, so that the main app knows about it (just like it were a dynamically loaded plugin).

The problem now is that the initalization is never called. However, when I add a dummy function and call it from the main app, then the initializer is suddenly called. So this looks to me as if the initalization is "optimized" away from gcc.

static bool registerPlugins(void)
{
    std::cout << "Registering CSV static plugin ... " << std::endl;
    PluginManager::registerStaticPlugin(&PluginInfo);

    return true;
}
static bool gCSVRegistered = registerPlugins();

The text "Registering..." is never printed, but adding the dummy function

void helper(void)
{
    std::cout << "Registered: "  << gCSVRegistered << std::endl;
}

... and call it dfrom the main app, then all the exptected text is printed.

So how can I force the static initalizer to not get thrown away???

I'm using Mingw32 with gcc 4.9.2 (just for the record :)).

Important update: The relevant code is in a static library. In this case it doesn't get triggered, only when the module is linked directly to the main application the initalizer is called.

SSCCE

main.cpp:

#include <iostream>

const char *gData = NULL;

int main()
{
    if(gData)
        std::cout << "Registration: " << gData << std::endl;
    else
        std::cout << "Registration: NULL" << std::endl;

    return 0;
}

void registered(const char *pData)
{
    gData = pData;
}

static1.cpp

void registered(const char *pData);

static bool registration(void)
{
    registered("Static initializer 1");
    return true;
}

static bool reg = registration();

static2.cpp

void registered(const char *pData);

static bool registration(void)
{
    registered("Static initializer 2");
    return true;
}

static bool reg = registration();

static library: lib_main.cpp

void registered(const char *pData);

static bool registration(void)
{
    registered("Static initializer library");
    return true;
}

static bool reg = registration();

Upvotes: 5

Views: 1965

Answers (3)

Devolus
Devolus

Reputation: 22094

So because of the comments on the question that finally led me into the right direction. The problem is that the function is in a static library and there the code is not called if it is not used in the main application, because the linker doesn't even add the code to the executable.

For a more detailed description I found this question: Static initialization and destruction of a static library's globals not happening with g++

In order to force the code being called, I have to either move the registration into a module that will be needed for sure (and thus gets linked in), or use the linker option -Wl,--whole-archive.

ld linker question: the --whole-archive option

Upvotes: 3

Jonathan Wakely
Jonathan Wakely

Reputation: 171333

Because you don't use the static variable it gets optimised away. To prevent that you can tell the compiler it is needed using the "used" attribute:

[[gnu::used]] const bool gCSVRegistered = registerPlugins();

(I also changed static to const because presumably you don't want to modify the variable after it is initialized, and namespace-scope const objects are static by default anyway).

For C++03 you can use the non-standard GNU attribute syntax:

__attribute__((used)) const bool gCSVRegistered = registerPlugins();

Upvotes: 1

alain
alain

Reputation: 12047

I can't reproduce the error, but volatile could do the trick:

static volatile bool gCSVRegistered = registerPlugins();

Upvotes: 2

Related Questions