The code below demonstrates the expected (and arguably, intuitive) behavior. Just as static objects in an executable are initialized before main()
is entered, one would expect static objects in a dynamically loaded library to be initialized before dlopen()
returns.
The issue: is this behavior for libraries loaded at runtime guaranteed in any way, or is it just a convenient accident or a lucky implementation detail? Can we rely on constructors of static objects in the libraries being invoked, or do we have to resort to alternatives such as functions marked with __attribute__((constructor))
in order to ensure some desired behavior within the scope of the dlopen()
call?
// libtest.cpp
#include <iostream>
namespace
{
class Test
{
public:
Test() { std::cerr << "In Test()...\n"; }
~Test() { std::cerr << "In ~Test()...\n"; }
};
Test test; // when is this initialized?
}
// testso.cpp
#include <dlfcn.h>
#include <iostream>
int main( int ac, char* av[] )
{
if ( ac < 2 )
{
std::cerr << "Usage: " << av[0] << "library-name\n";
return 1;
}
std::cerr << "Before dlopen()...\n";
::dlerror();
void* _handle(::dlopen( av[1], RTLD_NOW ));
std::cerr << "After dlopen()...\n";
if ( !_handle )
{
std::cerr << "Error: " << ::dlerror() << ", exiting...\n";
return 2;
}
::dlclose( _handle );
std::cerr << "After dlclose()...\n";
return 0;
}
Compiled and run (note Test()
invocation before dlopen()
returns):
$ g++ -o libtest.so -shared -fPIC libtest.cpp
$ g++ -o testso -ldl testso.cpp
$ ./testso ./libtest.so
Before dlopen()...
In Test()...
After dlopen()...
In ~Test()...
After dlclose()...
$
.