help-gplusplus
[Top][All Lists]
Advanced

[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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]