Initializing Dependencies in g++

My  previous article talking about dependency injection had the dependencies registered via an explicit function called from main.  This may give the wrong Idea about how to register dependencies.  Here is a much better approach, but with a solution that is compiler specific.

Applications on Linux comply with a one of a limited number of different formates.  The older style is referred to as  a.out, the default file produced by gcc if no -o target is given.  More common now is the Extensible Loadable File format, or elf.  An application can link libraries in one of three ways.  The tight coupling comes from static binding, where all dependencies are resolved before the executable file is written.  Typically, this is linking together files with extension like .a or .o depending on format.

Second is library loading done at execution time.  Here , a version of the library is registered with the system, and resolved at process execution time.  These libraries have extension of .so for ‘shared object’ although they usually have version numbers after the so.  To see the libraries that an executable depends on, run the command ldd.

The third type of binding is done after the process hits main, and is a deliberate function call by the application ‘dlopen’.  This also loads .so files, but  all linking and symbol resolution is done via function calls.

The mechanism allows the library to specify  a block of code that the linker runs whenever one of these forms of loading occurs.  The current incarnation of this mechanism looks like this:

void __attribute__ ((constructor)) my_init()

The name of the function does not matter: I have called mine my_init but it cane be anything, although you should account for name clash, especially if you wish to call the function again later in your program.  There is a corresponding function called upon cleanup.

void __attribute__ ((destructor)) my_fini(void)

The earlier names for these functions were _init and _fini, and I suspect many compilers support this, but it has been deprecated in gcc to use that form.

Since this gets called at application load time, and before main, it is a logical place to place our registration code.  Note that you can make no assumptions about what has been loaded or initialized at this time.  A modified version of the bindings.cpp code from the previous article would look like this:

extern “C”{
void __attribute__ ((constructor)) register_all_bindings(){
static bool not_yet_run = true;
std::cout << __FUNCTION__;

if (not_yet_run){
std::cout << “:Registering”;

supply<A>::configure();
supply<A,1>::configure(destroy);
supply<B>::configure(make);
supply<B,1>::configure();
supply<C>::configure(makeC,dropC);
not_yet_run = false;
}
std::cout << std::endl;
}
void __attribute__ ((destructor)) binding_fini(void){
std::cout << __FUNCTION__ << std::endl;
}
}

I have added a little bit of logging to show when these function are called.  It is probably safe to put a  simple boolean “lock” around the initialization code since this is run before any pthread create type code, and thus is guaranteed to be single threaded, but this assumption may not stay true in the future, so beware.

The code I have above registers all the classes in a single chunk.  This is not really interesting, nor is it likely how an application would be written in the “real world.” Instead, each subsystem would be responsible for registering their set of factories.  This code should not attempt to create any objects, as they may not be loaded yet.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.