tags:

views:

351

answers:

8

I have a .cpp file (let's call it statinit.cpp) compiled and linked into my executable using gcc. My main() function is not in statinit.cpp.

statinit.cpp has some static initializations that I need running. However, I never explicitly reference anything from statinit.cpp in my main(), or in anything referenced by it. What happens (I suppose) is that the linked object created from statinit.cpp is never loaded on runtime, so my static initializations are never run, causing a problem elsewhere in the code (that was very difficult to debug, but I traced it eventually).

Is there a standard library function, linker option, compiler option, or something that can let me force that object to load on runtime without referencing one of its elements?

What I thought to do is to define a dummy function in statinit.cpp, declare it in a header file that main() sees, and call that dummy function from main(). However, this is a very ugly solution and I'd very much like to avoid making changes in statinit.cpp itself.

Thanks, Daniel

+2  A: 

I ran into the same problem.

Write a file, DoNotOptimizeAway.cpp:

void NoDeadcodeElimination()
{
    // Here use at least once each of the variables that you'll need.
}

Then call NoDeadcodeElimination() from main.

EDIT: alternatively you can edit your linker options and tell it to always link everything, even if it's not used. I don't like this approach though since executables will get much bigger.

Andreas Bonini
Thanks for the answer. The problem with using a variable from my unreferenced file is that in this particular file, there are only classes with complex constructors that require pre-built parameters, and there are no static members. I found that adding my own little variable or function in the file and referencing it solves the problem, but I'd like to avoid making changes in the file.
Daniel Hershcovich
What's the linker option you were talking about? I think that might be the solution in this case. There's probably not a lot of unused code in my project (if at all), but I could be wrong.
Daniel Hershcovich
A: 

Since you are using C++, you could always declare a global object (ie a global variable that references a class in statinit.cpp. As always, the constructor will be called on initialization and since the object is global, this will be called before main() is run.

There is one very important caveat though. There is no guarantee as to when the constructor will be called and there is no way to explicitly order when each of these constructors is called. This will also probably defeat any attempt to check for memory leaks since you can no longer guarantee that all the memory allocated while running main has been deallocated.

doron
If it's in a library, there is no guarantee the constructor of the global object will ever be called. In fact, t probably won't be.
anon
+1  A: 

These problems, and the problems with these potential solutions all revolve around the fact that you can't guarantee much about static initialization. So since it's not dependable, don't depend on it!

Explicitly initialize data with a static "InititalizeLibrary" type static function. Now you guarantee it happens, and you guarantee when it happens in relation to other code based on when you make the call.

Clyde
Thanks for the advice, but unfortunately, it's not my choice.Static initializations have been used in this project before I started working on it, and I'm supposed to use that file without altering it (unless there's other way). Eliminating the static initializations in the project and replacing them with a better solution is possible, but I'm looking for a more immediate solution.
Daniel Hershcovich
static initialization is well defined (apart from the order, which does not seem to be the problem).
Martin York
+1  A: 

One C++'ish way to do this is with Singletons.

Essentially, write a function to return a reference to the object. To force it to initialize, make it a static object inside the function.

Make a class static function that is vaguely like this:

class MyClass {
   static MyClass& getObject()
   {
        static MyObject obj;
        return obj;
    }
};
Zan Lynx
I tried to do this, but I can't include the .cpp file, and no header file declares anything from it.
Daniel Hershcovich
This is __not__ a singelton.
Martin York
@Martin: It is if you make getObject a static function and make the constructors private. How else would you do it?
Zan Lynx
A: 

Is the problem that the static items were never initialized, or is the problem that the static items weren't initialized when you needed to use them?

All static initialization is supposed to be finished before your main() runs. However, you can run into issues if you initialize on static object with another static object. (Note: this doesn't apply if you are using primitives such as int)

For example, if you have in file x.cpp:

static myClass x(someVals);

And in y.cpp:

static myClass y = x * 2;

It's possible that the system will try to instantiate y before x is created. In that case, the "y" variable will likely be 0, as x is likely 0 before it is initialized.

In general, the best solution for this is to instantiate the object when it is first used (if possible). However, I noticed above you weren't allowed to modify that file. Are the values from that file being used elsewhere, and maybe you can change how those values are accessed?

Dan
I'm never directly using anything from that file, but the static initializations have a side effect of appending the created object to a global data structure.The problem is that the static initializations are never run, so the structure does not contain what I expected it to.
Daniel Hershcovich
+4  A: 

It is not exactly clear what the problem is:

C++ does not have the concept of static initializers.
So one presume you have an object in "File Scope".

  • If this object is in the global namespace then it will be constructed before main() is called and destroyed after main() exits (assuming it is in the application).
  • If this object is in a namespace then optionally the implementation can opt to lazy initialize the variable. This just means that it will be fully initialized before first use. So if you are relying on a side affect from construction then put the object in the global namespace.

Now a reason you may not be seeing the constructor to this object execute is that it was not linked into the application. This is a linker issue and not a language issue. This happens when the object is compiled into a static library and your application is then linked against the static library. The linker will only load into the application functions/objects that are explicitly referenced from the application (ie things that resolve undefined things in the symbol table).

To solve this problem you have a couple of options.

  • Don't use static libraries.
    • Compile into dynamic libraries (the norm nowadays).
    • Compile all the source directly into the application.
  • Make an explicit reference to the object from within main.
Martin York
You're saying it's different if I use a .a static library file or if I use a .so shared object (dynamic library) file? Interesting. That may be the answer to my question indeed. I'll try changing it tomorrow and report. Thanks.
Daniel Hershcovich
Yes. Read this: http://stackoverflow.com/questions/1897184/static-variable-initialisation-code-never-gets-called/1897394
Martin York
Well, my question is identical to that guy's question, but I hadn't found it before posting. I should have rephrased it, and then I'd have an instant answer :)
Daniel Hershcovich
A: 

Read the manual page for the ld command and look at the -u option. If statinit.cpp defines anything that looks like a function then try naming it in -u. Otherwise choose a data object that's defined in statinit.cpp and name that in -u, and hope it works. I think it's best if you write the command line so the -u option comes immediately before your -l option for your library that has statinit's object code in it.

Windows programmer
Thanks, I think that could be the next-best solution to using a dynamic library.
Daniel Hershcovich
A: 

Of course the dynamic library solution is the best, but I've also been told it's possible to link the whole static library with the linker option:

-Wl,-whole-archive

before the library's -l option, and

-Wl,-no-whole-archive

after it (to avoid including other libraries as a whole, too).

Daniel Hershcovich