Thread: shared libraries in c++ name mangling error

  1. #1
    Registered User
    Join Date
    Feb 2012
    Posts
    5

    Unhappy shared libraries in c++ name mangling error

    I am trying to create a dynamic(.so) wrapper library along mongoDB c++ driver. There is no problem with the compilation but when I test it in a C++ sample program i get the error
    Code:
    undefined symbol: _ZN5mongo18DBClientConnection15_numConne

    which i assume has something to do with name mangling issues.


    I compiled the library as
    Code:
     g++ -fPIC -shared mongoquery.cpp -I/pathto/mongodriver -lmongoclient -lboost_thread-mt -lboost_filesystem -lboost_program_options -o libmongoquery.so
    Here's the program I am using for testing:


    Code:
     
    #include <iostream>
    #include <dlfcn.h>
    #include "mongoquery.hpp"
    using namespace std;
    
    
    int main()
    {
        void *lib_handle;
        int (*fn)(int *,string);
        lib_handle=dlopen("./libmongoquery.so",RTLD_NOW);
        if(!lib_handle)
        {
            cerr<<"Error"<<dlerror();
            return 1;
        }
        fn=(int (*)(int *,string))dlsym(lib_handle,"count_query");
        string q="{}";
        int n;
        (*fn)(&n,q);
        cout<<n;
        dlclose(lib_handle);
    return 0;
    }
    the header mongoquery.hpp contains


    Code:
    #include <iostream>
    #include <client/dbclient.h>
    #define HOST "localhost"
    #define COLLECTION "test.rules"
    using namespace mongo;
    using namespace std;
    class mongoquery
    {
        private:
            string q;
            mongo::DBClientConnection c;
    
    
    
    
        public:
            mongoquery(string);
            int result_count();
    };
    int count_query(int *,string);


  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    I would try compiling that client with "-rdynamic" on the commandline. I would also try a dynamically linked client to see if it has the same issue (no dlopen etc...).

    >> the header mongoquery.hpp contains
    Don't put "using namespace" in headers. Anyone including the header will be forced to "use" it as well.

    gg

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Most dynamic libraries which export C++ classes do it using interfaces and factories, as opposed to directly exporting the class methods. Typically, you'd define an interface which your class provides:

    Code:
    // Inside the headers the clients of your library will use...
    class IMyInterface
    {
    public:
        virtual ~IMyInterface() {}
    
        virtual void MyFunction() = 0;
    };
    While in your dynamic library itself you actually create your class:

    Code:
    // Inside your library implementation code
    class MyClass : public IMyInterface
    {
        // implement the methods
    };
    And then you'd provide a function which the user of the library can call which instantiates a MyClass and returns it as a IMyInterface, and you'd declare it extern "C":

    Code:
    // Inside the headers the clients of your library will use...
    extern "C" {
    IMyInterface *CreateMyClass(...params...);
    }
    The user of the library then does something like this:

    Code:
    // Inside the user code using your library...
    IMyInterface *object = CreateMyClass(...params...);
    
    // Use the object through the interface
    This keeps all the implementation code hidden (which is good design anyway) and reduces mangling problems by forcing everything through extern "C" names. Your dynamic library only has to export the CreateMyClass() function, and its name won't be mangled because of the extern "C" declaration.
    Last edited by brewbuck; 02-11-2012 at 11:06 AM.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Registered User
    Join Date
    Feb 2012
    Posts
    5

    tried it

    Quote Originally Posted by brewbuck View Post
    Most dynamic libraries which export C++ classes do it using interfaces and factories, as opposed to directly exporting the class methods. Typically, you'd define an interface which your class provides:

    Code:
    // Inside the headers the clients of your library will use...
    class IMyInterface
    {
    public:
        virtual ~IMyInterface() {}
    
        virtual void MyFunction() = 0;
    };
    While in your dynamic library itself you actually create your class:

    Code:
    // Inside your library implementation code
    class MyClass : public IMyInterface
    {
        // implement the methods
    };
    And then you'd provide a function which the user of the library can call which instantiates a MyClass and returns it as a IMyInterface, and you'd declare it extern "C":

    Code:
    // Inside the headers the clients of your library will use...
    extern "C" {
    IMyInterface *CreateMyClass(...params...);
    }
    The user of the library then does something like this:

    Code:
    // Inside the user code using your library...
    IMyInterface *object = CreateMyClass(...params...);
    
    // Use the object through the interface
    This keeps all the implementation code hidden (which is good design anyway) and reduces mangling problems by forcing everything through extern "C" names. Your dynamic library only has to export the CreateMyClass() function, and its name won't be mangled because of the extern "C" declaration.
    Thanks for the reply but I tried using the method mentioned by you and still getting the same error . Can there be any other reasons?

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by mayank.gupta22 View Post
    Thanks for the reply but I tried using the method mentioned by you and still getting the same error . Can there be any other reasons?
    If you are getting an error such as this:

    undefined symbol: _ZN5mongo18DBClientConnection15_numConne
    Then you are definitely not using the method I described.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    Registered User
    Join Date
    Feb 2012
    Posts
    5
    According to what I understood from your reply I have attached the code below. Please help !
    interface.h contains
    Code:
    #ifndef __INTERFACE_H
    #define __INTERFACE_H
    
    
    #include <iostream>
    
    
    class interface
    {
        public:
            virtual int get_result()=0;
    };
    
    
    typedef interface* create_t();
    
    
    #endif
    and mongoquery.cpp contains
    Code:
    #include "interface.h"
    #include <client/dbclient.h>
    #include <iostream>
    #define HOST "localhost"
    class mongoquery:public interface
    {
            
        public:
            virtual int get_result()
            {
        mongo::DBClientConnection c;
        try
        {
            c.connect(HOST);
           
        }catch(mongo::DBException e)
        {
            std::cerr<<"Error interacting with DB"<<e.what();
            return 0;
        }
        
        int count=c.count("test.rules");
        return count;
    }
    };
    
    
    extern "C" interface* create()
    {
        return new mongoquery;
    }
    I am making mongoquery.cpp as
    Code:
     
    g++ -fpic  -shared -static -I /home/mayank/Desktop/mongo-cxx-driver-v1.8/mongo mongoquery.cpp -o libmongoquery.so -lmongoclient -lboost_filesystem -lboost_thread-mt -lboost_program_option
    and the test file
    Code:
    #include <iostream>
    #include <dlfcn.h>
    #include "interface.h"
    using namespace std;
    
    
    int main()
    {
        void *lib_handle;
        interface * (*fn)();
        lib_handle=dlopen("./libmongoquery.so",RTLD_NOW);
        if(!lib_handle)
        {
            cerr<<"Error"<<dlerror();
            return 1;
        }
        create_t* cro=(create_t*) dlsym(lib_handle,"create");
        const char* dlsym_error = dlerror();
            if (dlsym_error) {
            cerr << "Cannot load symbol create: " << dlsym_error << '\n';
            return 1;
            }    
        interface *obj=cro();
        cout<<obj->get_result()<<endl;
        
        dlclose(lib_handle);
    return 0;
    }
    Last edited by mayank.gupta22; 02-13-2012 at 02:35 PM.

  7. #7
    Registered User
    Join Date
    Feb 2012
    Posts
    5
    I figured it out. The problem was the shared library of the database client wasn't added to the default configuration path due to which the -rdynamic tag wasn't adding the complete list of symbols present in the DB library. This was causing the undefined reference error. Thanks for suggesting me the proper design practice

  8. #8
    Registered User
    Join Date
    Feb 2012
    Posts
    5
    thanks. That was one of the problem apart from the -static flag which I should be using to build a standalone library.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. run time error while loading shared libraries
    By mijax in forum C++ Programming
    Replies: 7
    Last Post: 05-16-2010, 07:27 AM
  2. shared libraries
    By kris.c in forum Linux Programming
    Replies: 5
    Last Post: 12-25-2006, 08:08 PM
  3. Shared Libraries and such
    By divineleft in forum Linux Programming
    Replies: 3
    Last Post: 11-04-2006, 08:38 PM
  4. Problems with shared libraries
    By nilesh82 in forum C Programming
    Replies: 2
    Last Post: 10-02-2005, 06:29 AM
  5. shared libraries
    By Raven Arkadon in forum C++ Programming
    Replies: 5
    Last Post: 06-27-2005, 07:11 AM

Tags for this Thread