Prev: What is the protocal for GMT offset in SMTP (e-mail) header time-stamp?
Next: Receiving broadcast packets using packet socket
From: Vladimir Jovic on 12 Apr 2010 03:42 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 12 Apr 2010 03:50 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 12 Apr 2010 04:17
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 |