From: Vladimir Jovic on
Hi,

I am using c++, and need to dynamically load a shared library. To create
an example, I followed steps here:
http://rachid.koucha.free.fr/tech_corner/shared_libs_tests.html

The example works fine, but what if I extend the class to inherit from a
pure virtual base class and change the constructor to take a parameter?
Something like this:

class CompInterface
{
public:
CompInterface()
{
std::cout<<"CompInterface"<<std::endl;
}
virtual ~CompInterface()
{
std::cout<<"~CompInterface"<<std::endl;
}
virtual void Hello( const char* msg ) = 0;
};

class Comp : public CompInterface
{
public:
Comp( const char* msg )
{
std::cout << "Comp : Hello " << msg << std::endl;
}
virtual ~Comp()
{
std::cout << "~Comp : Goodbye!" << std::endl;
}
virtual void Hello( const char* msg )
{
std::cout << "Another message: " << msg << std::endl;
}
};


extern "C"
{
CompInterface* CreateTheObject( const char* msg )
{
return new Comp(msg);
}
void ReleaseTheObject( const CompInterface *obj )
{
delete(obj);
}
}

My idea is to have the Comp class in a shared library, and to
dynamically load it from another shared library.

When I try to load this shared library, and when I create an instance of
the Comp class, I get the output like this:
CompInterface
Comp : Hello ������p
and this
CompInterface
Comp : Hello ��?���p


Do you see any problems in the above example?


PS If needed I can post full example with make files.
From: Vladimir Jovic on
Vladimir Jovic wrote:
<SNIP all>


hmmm guess I posted too fast, as I just found this:
http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.9

Anyway, here is a new question: Is there a way to create the instance of
the class Comp?
From: Vladimir Jovic on
I found a solution, and posting it here if someone is interested how to
do it. (the idea I got from the firefox project, they used a structure
to pass function pointers).


1) Makefile.comp

all:
gcc -Wall -fPIC -c comp.cpp -o comp.o
gcc -shared -Wl,-soname,libcomp.so -o libcomp.so comp.o
clean:
rm -rf comp.o
rm -rf libcomp.so


2) Makefile.main

all:
g++ -Wall -fPIC -rdynamic -ldl -c main.cpp loader.cpp
SharedLibraryLoader.cpp
g++ -rdynamic -ldl loader.o main.o -o test
clean:
rm -rf main.o loader.o SharedLibraryLoader.o
rm -rf test

3) main.cpp

#include "loader.hpp"
#include "compinterface.hpp"
#include <iostream>
int main(int argc, char** argv)
{
std::cout << "main : starting"<<std::endl;
try
{
Loader loader( argc, argv, "cfg.xml" );

CompInterface *instance = loader.GetComp1( "component type 1" );

std::cout << "main : calling the virtual method"<<std::endl;

instance->Hello( "hi" );
}
catch(const int errNum )
{
std::cout<<"\n\nError = " << errNum << std::endl<< std::endl;
}
std::cout << "main : ending"<<std::endl;
}

4) loader.hpp
#ifndef COMP_HPP
#define COMP_HPP

#include "compinterface.hpp"
#include "SharedLibraryLoader.hpp"

class Loader
{
public :

Loader( int argc, char** argv, const char *cfgFile );
~Loader();

CompInterface* GetComp1( const char* msg );

private:
SharedLibraryLoader< CompInterface > comp1;
};

#endif

5) loader.cpp


#include "loader.hpp"

#include "SharedLibraryLoader.cpp"

#include <fstream>
#include <iostream>

std::string GetComp1ShLibrary( const char *cfgFile )
{
std::fstream f( cfgFile );
if ( f.fail() )
{
std::cout<<"Error 1 loading cfg file." << std::endl;
return "";
}
std::string shLibName;
f >> shLibName;
if ( f.fail() )
{
std::cout<<"Error 2 loading cfg file." << std::endl;
return "";
}
return shLibName;
}

Loader::Loader( int , char**, const char *cfgFile ) :
comp1( GetComp1ShLibrary( cfgFile ) )
{
}

Loader::~Loader()
{
}

CompInterface* Loader::GetComp1( const char* msg )
{
return comp1.GetInstance( msg );
}


6) compinterface.cpp


#ifndef COMPINTERFACE_HPP
#define COMPINTERFACE_HPP

#include <iostream>

class CompInterface
{
public:

CompInterface()
{
std::cout<<"CompInterface"<<std::endl;
}
virtual ~CompInterface()
{
std::cout<<"~CompInterface"<<std::endl;
}

virtual void Hello( const char* msg ) = 0;
};

#endif

7) comp.hpp

#ifndef COMP_HPP
#define COMP_HPP

#include "compinterface.hpp"
#include "comp_initializer.hpp"

class Comp : public CompInterface
{
public:

Comp( const char* msg );

virtual ~Comp();

virtual void Hello( const char* msg );
};


CompInterface* CreateTheObject( const char* msg );
void ReleaseTheObject( const CompInterface *obj );

CompInitializer init = { CreateTheObject, ReleaseTheObject };

extern "C" CompInitializer GetInitializer();

#endif

8) comp.cpp

#include "comp.hpp"

#include <iostream>

Comp::Comp( const char* msg )
{
std::cout << "Comp : Hello " << msg << std::endl;
}

Comp::~Comp()
{
std::cout << "~Comp : Goodbye!" << std::endl;
}

void Comp::Hello( const char* msg )
{
std::cout << "Another message: " << msg << std::endl;
}

CompInterface* CreateTheObject( const char *msg )
{
return new Comp( msg );
}

void ReleaseTheObject( const CompInterface *obj )
{
delete( obj );
}

extern "C" CompInitializer GetInitializer()
{
return init;
}

9) comp_initializer.hpp


#ifndef COMP_INITIALIZER_HPP
#define COMP_INITIALIZER_HPP

#include "compinterface.hpp"

typedef CompInterface* (*CreateTheObjectFun)( const char* msg );
typedef void (*ReleaseTheObjectFunc)( const CompInterface *obj );

struct CompInitializer
{
CreateTheObjectFun ObjectConstructor;
ReleaseTheObjectFunc ObjectDestructor;
};

#endif


10) SharedLibraryLoader.hpp



#ifndef SHARED_LIB_LOADER_HPP
#define SHARED_LIB_LOADER_HPP

#include <string>
#include <boost/noncopyable.hpp>
#include <memory>

template < typename ClassInterface >
class SharedLibraryLoader : private boost::noncopyable
{
/*- Class invariants : What must be true after each call to a public
* interface
*/

public:

explicit SharedLibraryLoader( const std::string &shLibFile );
~SharedLibraryLoader();


// Methods
ClassInterface* GetInstance();
template < typename Arg1 >
ClassInterface* GetInstance( const Arg1 &arg1 );
template < typename Arg1, typename Arg2 >
ClassInterface* GetInstance( const Arg1 &arg1, const Arg2 &arg2 );

private:

struct Imp; // forward declaration of Imp
std::auto_ptr< Imp > pimpl; // Opaque pointer
};

#endif


11) SharedLibraryLoader.cpp


#include "SharedLibraryLoader.hpp"
#include "comp_initializer.hpp"
#include <dlfcn.h>
#include <iostream>
#include <cassert>


template < typename ClassInterface >
struct SharedLibraryLoader< ClassInterface >::Imp
{
/*- Class invariants : What must be true after each call to a public
* interface
*/

Imp( const std::string &shLibFile );
~Imp();

// Methods
ClassInterface* GetInstance();
template < typename Arg1 >
ClassInterface* GetInstance( const Arg1 &arg1 );

// the object instance
ClassInterface *object;

// the handle for the shared lubrary
void *shLibHandle;
};

template < typename ClassInterface >
SharedLibraryLoader< ClassInterface >::Imp::Imp( const std::string
&shLibFile ) :
object( NULL ),
shLibHandle( dlopen( shLibFile.c_str(), RTLD_NOW ) )
{
if ( NULL == shLibHandle )
{
const std::string error( dlerror() );
std::cout << "Error loading the shared library " << shLibFile
<< ". Actual error : " << error;

throw 1;
}
}

template < typename ClassInterface >
SharedLibraryLoader< ClassInterface >::Imp::~Imp()
{
// if the object was created, release it now
if ( NULL != object )
{
typedef CompInitializer (*InitializerFun)();
InitializerFun f =
reinterpret_cast< InitializerFun >( dlsym( shLibHandle,
"GetInitializer" ) );
if ( NULL != f )
{
assert( NULL != f().ObjectDestructor );
f().ObjectDestructor( object );
}
else
{
const std::string error( dlerror() );
std::cout << "Error releasing the instance. Actual error :
" << error;
}
}

// unload the shared library
dlclose( shLibHandle );
}

template < typename ClassInterface >
ClassInterface* SharedLibraryLoader< ClassInterface >::Imp::GetInstance()
{
// if the object was not created so far, do it now
if ( NULL == object )
{
typedef CompInitializer (*InitializerFun)();
InitializerFun f =
reinterpret_cast< InitializerFun >( dlsym( shLibHandle,
"GetInitializer" ) );
if ( NULL != f )
{
assert( NULL != f().ObjectConstructor );
object = f().ObjectConstructor();
}
else
{
const std::string error( dlerror() );
std::cout << "Error creating the instance. Actual error : "
<< error;

throw 2;
}
}

return object;
}

template < typename ClassInterface >
template < typename Arg1 >
ClassInterface* SharedLibraryLoader< ClassInterface >::Imp::GetInstance(
const Arg1 &arg1 )
{
// if the object was not created so far, do it now
if ( NULL == object )
{
typedef CompInitializer (*InitializerFun)();
InitializerFun f =
reinterpret_cast< InitializerFun >( dlsym( shLibHandle,
"GetInitializer" ) );
if ( NULL != f )
{
assert( NULL != f().ObjectConstructor );
object = f().ObjectConstructor( arg1 );
}
else
{
const std::string error( dlerror() );
std::cout << "Error creating the instance. Actual error : "
<< error;

throw 2;
}
}

return object;
}

template < typename ClassInterface >
SharedLibraryLoader< ClassInterface >::SharedLibraryLoader( const
std::string &shLibFile )
: pimpl( new Imp( shLibFile ) )
{
}

template < typename ClassInterface >
SharedLibraryLoader< ClassInterface >::~SharedLibraryLoader()
{
}

template < typename ClassInterface >
ClassInterface* SharedLibraryLoader< ClassInterface >::GetInstance()
{
return pimpl->GetInstance();
}

template < typename ClassInterface >
template < typename Arg1 >
ClassInterface* SharedLibraryLoader< ClassInterface >::GetInstance(
const Arg1 &arg1 )
{
return pimpl->GetInstance( arg1 );
}

12) cfg.xml
../libcomp.so