[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: constructors not called in dynamic object, Linux only.
From: |
James Kanze |
Subject: |
Re: constructors not called in dynamic object, Linux only. |
Date: |
Wed, 02 Feb 2005 20:39:50 +0100 |
User-agent: |
Mozilla Thunderbird 1.0 (X11/20041206) |
Paul Pluzhnikov wrote:
> James Kanze <kanze@none> writes:
>>Does anyone know what options are necessary for static
>>initializers in a dynamic object to be correctly executed
>>under Linux.
> Compiling with '-fPIC' and linking with '-shared' has always sufficed
> for me.
>>The g++ documentation for -shared has a footnote "On some
>>systems, gcc -shared needs to build supplementary stub code for
>>constructors to work. ...
>>Presumable, Linux is one of the cases where you need some
>>special option to make g++ generate these stubs
> No, Linux/ELF does *not* need to generate any such stubs.
> They are only needed on platforms which do not support .init/.fini
> sections.
That's what I would have thought.
> Either you are using some extremely weird (or old) Linux
> environment, or there is something else going on which you
> didn't tell us about.
Well, it's Mandrake 10.0, and I tend to install the upgrades as
they appear. G++ is 3.4.0. ld is 2.14.90.0.7.
> As Larry said, post a minimal test case, and do tell us what
> Linux, and what versions of g++ and binutils you are using.
I was afraid that the minimal test case would still be too big,
but here goes:
------------- IF.hh ------------
#ifndef IF_hh
#define IF_hh
#include <string>
class IF
{
public:
virtual ~IF() ;
virtual int f() const = 0 ;
static IF const* getIF( std::string const& name ) ;
protected:
explicit IF( std::string const& name ) ;
private:
std::string const myName ;
} ;
#endif
------------- IF.cc ------------
#include "IF.hh"
#include <string>
#include <map>
#include <iostream>
#include <ostream>
#include <dlfcn.h>
#include <link.h>
namespace {
typedef std::map< std::string, IF const* >
IFMap ;
IFMap ourMap ;
IFMap::const_iterator
tryToLoadTranslator(
std::string const& name )
{
std::string filename = "./IF" + name + ".so" ;
std::cerr << "Loading " << name << std::endl ;
if ( dlopen( filename.c_str(), RTLD_NOW | RTLD_GLOBAL ) == NULL ) {
std::cerr << "load failed, error = " << dlerror() << std::endl ;
}
std::cerr << name << " loaded" << std::endl ;
return ourMap.find( name ) ;
}
}
IF::~IF()
{
ourMap.erase( myName ) ;
}
IF const*
IF::getIF(
std::string const& name )
{
IFMap::const_iterator
entry = ourMap.find( name ) ;
if ( entry == ourMap.end() ) {
entry = tryToLoadTranslator( name ) ;
}
return entry == ourMap.end()
? NULL
: entry->second ;
}
IF::IF(
std::string const& name )
: myName( name )
{
std::cerr << "IF: ctor for " << name << std::endl ;
bool inserted
= ourMap.insert( IFMap::value_type( name, this ) ).second ;
assert( inserted ) ;
}
------------- main.cc ------------
#include "IF.hh"
#include <iostream>
#include <ostream>
int
main( int argc, char** argv )
{
for ( int i = 1 ; i < argc ; ++ i ) {
std::cerr << "Loading " << argv[ i ] << std::endl ;
IF const* p = IF::getIF( argv[ i ] ) ;
if ( p == NULL ) {
std::cerr << argv[ i ] << " not loaded" << std::endl ;
} else {
std::cerr << argv[ i ] << " = " << p->f() << std::endl ;
}
}
return 0 ;
}
------------- IFTest1.cc ------------
#include "IF.hh"
namespace {
class IFTest1 : public IF
{
public:
IFTest1() ;
virtual int f() const ;
} instance ;
IFTest1::IFTest1()
: IF( "test1" )
{
}
int
IFTest1::f() const
{
return 1 ;
}
}
------------ compiled with ------------
g++ -g -fPIC -c IF.cc
g++ -g -fPIC -c main.cc
g++ -g -fPIC -o ./test IF.o main.o -ldl
g++ -g -fPIC -c IFTest1.cc
g++ -g -fPIC -shared -o IFTest1.so IFTest1.o
------------- output when executed ----------
$ ./test Test1 | c++filt
Loading Test1
Loading Test1
load failed, error = ./IFTest1.so: undefined symbol: typeinfo for IF
Test1 loaded
Test1 not loaded
---------------------------------------------
Under Solaris, I also got output from the constructor (both the
derived and base class), and the class was found in main.
My original code didn't even check the status of dlopen -- it
was just a quick concept check, before I designed the principle
in. And since it worked first go on Solaris...
Anyway, the problem seems clear; something isn't getting linked
correctly into the main, so dlopen isn't finding it. Why, I
don't know. Or more to the point, I don't know why it works
under Solaris, and not under Linux; maybe the different linkers?
(I use the Sun linker under Solaris, even with g++.)
This seems pretty basic; I feel sure that there's just an option
or something that I've missed. Something that will force the
link of ./test to include the missing typeinfo.
--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34