how to create a shared object with high maintainab

2019-08-27 23:24发布

问题:

I try to create a shared object for my C++ project with the purpose: every time I want to bring a new class, I recompile shared object only.

below is test code:

test.h:

#if !defined(_TEST_)
#define _TEST_

#include <string>
#include <memory>

class Test {
private:

public:
    Test() {

    }
    ~Test() {

    }

    virtual void show(const std::string &) = 0;
};

#ifdef __cplusplus
extern "C" {
#endif

// std::shared_ptr<Test> getObject();

#ifdef __cplusplus
}
#endif

#endif // _TEST_  

getObject.cpp: class TestSo derive from Test.

#include <memory>
#include "testso.h"

std::shared_ptr<Test> getObject()
{
    return std::make_shared<TestSo>();
}  

and the main.cpp:

#include "test.h"

#include <dlfcn.h>
#include <string>

#include <memory>

std::shared_ptr<Test> (*getTestSo)();

int main(int argc, char const *argv[])
{
    //...
    void *handle = dlopen("/usr/lib/libfunc.so", RTLD_NOW);
    if(handle == NULL)
        return 1;

    getTestSo = (std::shared_ptr<Test> (*)())dlsym(handle, "getObject");

    const char *dlmsg = dlerror();
    if(dlmsg != NULL) {
        printf("dlsym: %s\n", dlmsg);
        dlclose(handle);
        return 1;
    }

    std::shared_ptr<Test> classSo = getTestSo();

    classSo->show("Hi");

    dlclose(handle);
    //...
    return 0;
}  

I compile code with the following command line:
arm-none-linux-gnueabi-g++ -std=c++11 -c -fPIC getObject.cpp
arm-none-linux-gnueabi-g++ -shared getObject.o -o libtest.so
arm-none-linux-gnueabi-g++ -std=c++11 -L./ main.cpp -o test -ldl -ltest

compiler doesn't give me any warning or error. it says that undefined symbol: getObject when I run program.

finally I find that I must declare getObject in scope extern "C" within test.h.

dlsym fetch address of getObject from libtest.so and the program would jump to that address. why I must declare getObject? that is against my purpose. Or if I am totally going a wrong way, how do I do? if not, how can I fix it?

Edit:

arm-none-linux-gnueabi-nm -D libfunc.so 
         U __aeabi_atexit
         U __aeabi_unwind_cpp_pr0
         U __aeabi_unwind_cpp_pr1
0000f34c B __bss_end__
0000f34c B _bss_end__
0000f344 B __bss_start
0000f344 B __bss_start__
         U __cxa_begin_catch
         U __cxa_end_catch
         U __cxa_end_cleanup
         w __cxa_finalize
         U __cxa_pure_virtual
         U __cxa_rethrow
0000f344 D _edata
0000f34c B _end
0000f34c B __end__
00006664 T _fini
         w __gmon_start__
         U __gxx_personality_v0
00003e18 T _init
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
         w _Jv_RegisterClasses
         w __pthread_key_create
0000448c T _Z9getObjectv
         U _ZdlPv
000045a4 W _ZdlPvS_
00004630 W _ZN4TestC1Ev
00004630 W _ZN4TestC2Ev
00004678 W _ZN4TestD1Ev
00004678 W _ZN4TestD2Ev
00004760 W _ZN6TestDl4showERKSs
000046c0 W _ZN6TestDlC1Ev
000046c0 W _ZN6TestDlC2Ev
00004710 W _ZN6TestDlD1Ev
00004710 W _ZN6TestDlD2Ev
0000569c W _ZN9__gnu_cxx13new_allocatorI6TestDlE7destroyIS1_EEvPT_
00005424 W _ZN9__gnu_cxx13new_allocatorI6TestDlE9constructIS1_IEEEvPT_DpOT0_
00005424 W _ZN9__gnu_cxx13new_allocatorI6TestDlE9constructIS1_JEEEvPT_DpOT0_
000052d8 W _ZN9__gnu_cxx13new_allocatorI6TestDlEC1ERKS2_
00004af8 W _ZN9__gnu_cxx13new_allocatorI6TestDlEC1Ev
000052d8 W _ZN9__gnu_cxx13new_allocatorI6TestDlEC2ERKS2_
00004af8 W _ZN9__gnu_cxx13new_allocatorI6TestDlEC2Ev
00004b1c W _ZN9__gnu_cxx13new_allocatorI6TestDlED1Ev
00004b1c W _ZN9__gnu_cxx13new_allocatorI6TestDlED2Ev
000050bc W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEE10deallocateEPS5_j
000056c0 W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEE7destroyIS5_EEvPT_
00005018 W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEE8allocateEjPKv
0000510c W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEE9constructIS5_IKS3_EEEvPT_DpOT0_
0000510c W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEE9constructIS5_JKS3_EEEvPT_DpOT0_
00004fd0 W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEEC1Ev
00004fd0 W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEEC2Ev
00004ff4 W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEED1Ev
00004ff4 W _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEED2Ev
000045c4 W _ZN9__gnu_cxx7__mutexC1Ev
000045c4 W _ZN9__gnu_cxx7__mutexC2Ev
000050e4 W _ZNK9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceI6TestDlSaIS2_ELNS_12_Lock_policyE1EEE8max_sizeEv
00004e5c W _ZNKSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EE14_M_get_deleterERKSt9type_info
         U _ZNKSt9type_infoeqERKS_
000051a0 W _ZNSaI6TestDlEC1ERKS0_
00004934 W _ZNSaI6TestDlEC1Ev
000051a0 W _ZNSaI6TestDlEC2ERKS0_
00004934 W _ZNSaI6TestDlEC2Ev
0000495c W _ZNSaI6TestDlED1Ev
0000495c W _ZNSaI6TestDlED2Ev
00004edc W _ZNSaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEEC1IS0_EERKSaIT_E
00004edc W _ZNSaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEEC2IS0_EERKSaIT_E
00004f08 W _ZNSaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEED1Ev
00004f08 W _ZNSaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEED2Ev
         U _ZNSolsEPFRSoS_E
000048f4 W _ZNSt10shared_ptrI4TestEC1I6TestDlvEEOS_IT_E
000048f4 W _ZNSt10shared_ptrI4TestEC2I6TestDlvEEOS_IT_E
00004b40 W _ZNSt10shared_ptrI6TestDlEC1ISaIS0_EIEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004b40 W _ZNSt10shared_ptrI6TestDlEC1ISaIS0_EJEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004b40 W _ZNSt10shared_ptrI6TestDlEC2ISaIS0_EIEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004b40 W _ZNSt10shared_ptrI6TestDlEC2ISaIS0_EJEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004808 W _ZNSt10shared_ptrI6TestDlED1Ev
00004808 W _ZNSt10shared_ptrI6TestDlED2Ev
00005300 W _ZNSt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE1EEC1Ev
00005300 W _ZNSt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE1EEC2Ev
00004a8c W _ZNSt12__shared_ptrI4TestLN9__gnu_cxx12_Lock_policyE1EEC1I6TestDlvEEOS_IT_LS2_1EE
00004a8c W _ZNSt12__shared_ptrI4TestLN9__gnu_cxx12_Lock_policyE1EEC2I6TestDlvEEOS_IT_LS2_1EE
00004c00 W _ZNSt12__shared_ptrI6TestDlLN9__gnu_cxx12_Lock_policyE1EEC1ISaIS0_EIEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004c00 W _ZNSt12__shared_ptrI6TestDlLN9__gnu_cxx12_Lock_policyE1EEC1ISaIS0_EJEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004c00 W _ZNSt12__shared_ptrI6TestDlLN9__gnu_cxx12_Lock_policyE1EEC2ISaIS0_EIEEESt19_Sp_make_shared_tagRKT_DpOT0_
00004c00 W _ZNSt12__shared_ptrI6TestDlLN9__gnu_cxx12_Lock_policyE1EEC2ISaIS0_EJEEESt19_Sp_make_shared_tagRKT_DpOT0_
000047d8 W _ZNSt12__shared_ptrI6TestDlLN9__gnu_cxx12_Lock_policyE1EED1Ev
000047d8 W _ZNSt12__shared_ptrI6TestDlLN9__gnu_cxx12_Lock_policyE1EED2Ev
00004bb8 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EE7_M_swapERS2_
00004a5c W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EEC1Ev
00004d84 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EEC1I6TestDlSaIS4_EIEEESt19_Sp_make_shared_tagPT_RKT0_DpOT1_
00004d84 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EEC1I6TestDlSaIS4_EJEEESt19_Sp_make_shared_tagPT_RKT0_DpOT1_
00004a5c W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EEC2Ev
00004d84 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EEC2I6TestDlSaIS4_EIEEESt19_Sp_make_shared_tagPT_RKT0_DpOT1_
00004d84 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EEC2I6TestDlSaIS4_EJEEESt19_Sp_make_shared_tagPT_RKT0_DpOT1_
00004890 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EED1Ev
00004890 W _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE1EED2Ev
0000564c W _ZNSt16allocator_traitsISaI6TestDlEE10_S_destroyIS0_EENSt9enable_ifIXsrNS2_16__destroy_helperIT_EE5valueEvE4typeERS1_PS6_
000053fc W _ZNSt16allocator_traitsISaI6TestDlEE12_S_constructIS0_IEEENSt9enable_ifIXsrNS2_18__construct_helperIT_IDpT0_EEE5valueEvE4typeERS1_PS6_DpOS7_
000053fc W _ZNSt16allocator_traitsISaI6TestDlEE12_S_constructIS0_JEEENSt9enable_ifIXsrNS2_18__construct_helperIT_JDpT0_EEE5valueEvE4typeERS1_PS6_DpOS7_
000055fc W _ZNSt16allocator_traitsISaI6TestDlEE7destroyIS0_EEvRS1_PT_
000053d4 W _ZNSt16allocator_traitsISaI6TestDlEE9constructIS0_IEEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS1_PT_DpOS4_
000053d4 W _ZNSt16allocator_traitsISaI6TestDlEE9constructIS0_JEEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS1_PT_DpOS4_
00004fa0 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE10deallocateERS6_PS5_j
00005674 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE10_S_destroyIS5_EENSt9enable_ifIXsrNS7_16__destroy_helperIT_EE5valueEvE4typeERS6_PSB_
00005080 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE12_S_constructIS5_IKS2_EEENSt9enable_ifIXsrNS7_18__construct_helperIT_IDpT0_EEE5valueEvE4typeERS6_PSC_DpOSD_
00005080 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE12_S_constructIS5_JKS2_EEENSt9enable_ifIXsrNS7_18__construct_helperIT_JDpT0_EEE5valueEvE4typeERS6_PSC_DpOSD_
00005624 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE7destroyIS5_EEvRS6_PT_
00004f30 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE8allocateERS6_j
00004f64 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE9constructIS5_IKS2_EEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS6_PT_DpOSA_
00004f64 W _ZNSt16allocator_traitsISaISt23_Sp_counted_ptr_inplaceI6TestDlSaIS1_ELN9__gnu_cxx12_Lock_policyE1EEEE9constructIS5_JKS2_EEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS6_PT_DpOSA_
00004b7c W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE10_M_destroyEv
000049b4 W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE10_M_releaseEv
0000532c W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EEC1Ev
0000532c W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EEC2Ev
00004d0c W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EED0Ev
00004cb4 W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EED1Ev
00004cb4 W _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EED2Ev
0000553c W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE10_M_destroyEv
00005508 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE10_M_disposeEv
0000559c W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE14_M_get_deleterERKSt9type_info
00005398 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE5_ImplC1ES1_
00005398 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE5_ImplC2ES1_
000051d0 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE5_ImplD1Ev
000051d0 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE5_ImplD2Ev
000051f8 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEC1IIEEES1_DpOT_
000051f8 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEC1IJEEES1_DpOT_
000051f8 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEC2IIEEES1_DpOT_
000051f8 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EEC2IJEEES1_DpOT_
000054d8 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EED0Ev
00005464 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EED1Ev
00005464 W _ZNSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EED2Ev
         U _ZNSt8ios_base4InitC1Ev
         U _ZNSt8ios_base4InitD1Ev
         U _Znwj
0000457c W _ZnwjPv
00004834 W _ZSt11make_sharedI6TestDlIEESt10shared_ptrIT_EDpOT0_
00004834 W _ZSt11make_sharedI6TestDlJEESt10shared_ptrIT_EDpOT0_
00004984 W _ZSt15allocate_sharedI6TestDlSaIS0_EIEESt10shared_ptrIT_ERKT0_DpOT1_
00004984 W _ZSt15allocate_sharedI6TestDlSaIS0_EJEESt10shared_ptrIT_ERKT0_DpOT1_
         U _ZSt17__throw_bad_allocv
00004ec0 W _ZSt32__enable_shared_from_this_helperILN9__gnu_cxx12_Lock_policyE1EEvRKSt14__shared_countIXT_EEz
         U _ZSt4cout
         U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
00004d3c W _ZSt4moveIRKSaI6TestDlEEONSt16remove_referenceIT_E4typeEOS5_
000048d0 W _ZSt4moveIRSt10shared_ptrI6TestDlEEONSt16remove_referenceIT_E4typeEOS5_
00004d60 W _ZSt7forwardIKSaI6TestDlEEOT_RNSt16remove_referenceIS3_E4typeE
         U _ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E
         U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
0000f098 V _ZTI4Test
0000f08c V _ZTI6TestDl
0000f0c4 V _ZTIN9__gnu_cxx7__mutexE
0000f0b8 V _ZTISt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE1EE
0000f0a0 V _ZTISt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE
0000f084 V _ZTISt19_Sp_make_shared_tag
0000f078 V _ZTISt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE
000066f8 V _ZTS4Test
000066f0 V _ZTS6TestDl
00006764 V _ZTSN9__gnu_cxx7__mutexE
00006734 V _ZTSSt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE1EE
00006700 V _ZTSSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE
000066d8 V _ZTSSt19_Sp_make_shared_tag
0000668c V _ZTSSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE
0000f048 V _ZTV4Test
0000f038 V _ZTV6TestDl
         U _ZTVN10__cxxabiv117__class_type_infoE
         U _ZTVN10__cxxabiv120__si_class_type_infoE
         U _ZTVN10__cxxabiv121__vmi_class_type_infoE
0000f058 V _ZTVSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE
0000f018 V _ZTVSt23_Sp_counted_ptr_inplaceI6TestDlSaIS0_ELN9__gnu_cxx12_Lock_policyE1EE  

回答1:

You approach does not work, because C++ mangles names during compilation, maybe more on this topic can be found over the net or for example in this thread. When you compile a function named std::shared_ptr<Test> getObject() it ends up as a symbol named _Z9getObjectv, so in you need to open this symbol dlsym(handle, "_Z9getObjectv");

every time I want to bring a new class, I recompile shared object only.

I don't understand why do you don't want to just link against your program. dlsym was created to allow linker-related programs to handle the loading, the functionality seems not needed in your program. In case of your program simply adding a forward declaration of the function (without any extern C, because the name is mangled by C++):

std::shared_ptr<Test> getObject();

to your test.h file and then compiling with:

-ltest

as you do now(!) will link against shared library. That's exactly the reason why shared libraries exists in the first place - so you can change the underlying code without changing the client code. Also in case of linking the linker will issue symbol resolution error if the symbol is not found, so you have another layer of protection and you don't have to worry about mangled names. Just change your main.cpp to:

#include "test.h"

#include <dlfcn.h>
#include <string>

#include <memory>

int main(int argc, char const *argv[])
{
    std::shared_ptr<Test> getObject();
    std::shared_ptr<Test> (*getTestSo)() = getObject;

    std::shared_ptr<Test> classSo = getTestSo();

    return 0;
}  

and it should work (with proper LD_LIBRARY_PATH)...



回答2:

Below is a working example for you.

There is no need for extern "C" linkage as you can find out and use the mangled C++ name just fine.

Also, factory functions should return std::unique_ptr to convey to the user that they now own the object. Unless the factory keeps a reference to the object, in which case std::shared_ptr would be a good choice.

Shared library header:

// shared.h
#pragma once

#include <memory>
#include <string>
#include <iosfwd>

namespace shared {

struct Test {
    virtual ~Test() = 0;
    virtual void print(std::ostream&) const = 0;

    // Factory function.
    static std::unique_ptr<Test> create(std::string const& type);
};

inline std::ostream& operator<<(std::ostream& s, Test const& t) {
    t.print(s);
    return s;
}

} // namespace shared

Shared library source:

// shared.cc
#include "shared.h"
#include <iostream>

namespace {

struct A : shared::Test {
    void print(std::ostream& s) const override {
        s << __PRETTY_FUNCTION__;
    }
};

} // namespace

shared::Test::~Test() = default;

std::unique_ptr<shared::Test> shared::Test::create(std::string const& type) {
    std::unique_ptr<Test> result;
    if(type == "A")
        result.reset(new A);
    return result;
}

Build the shared library and find the mangled name of Test::create:

$ g++ -c -fPIC -W{all,extra,error} -std=c++11 shared.cc
$ g++ -o libshared.so -shared shared.o
$ nm --demangle --defined-only --dynamic libshared.so | grep Test::create
0000000000001894 T shared::Test::create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
$ nm --defined-only --dynamic libshared.so | grep 0000000000001894
0000000000001894 T _ZN6shared4Test6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE

The user source:

// test.cc
#include "shared.h"
#include <iostream>
#include <dlfcn.h>

struct DlClose { void operator()(void* handle) const { ::dlclose(handle); } };
using dl_ptr = std::unique_ptr<void, DlClose>;

int main() {
    dl_ptr handle(::dlopen("./libshared.so", RTLD_NOW));
    if(!handle)
        std::abort();

    using FactoryFn = std::unique_ptr<shared::Test>(std::string const&);
    FactoryFn* shared_create = reinterpret_cast<FactoryFn*>(::dlsym(handle.get(), "_ZN6shared4Test6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"));
    if(!shared_create)
        std::abort();

    auto a = shared_create("A");
    std::cout << *a << '\n';
}

Build and run the user code:

$ g++ -W{all,extra,error} -std=c++11 -o test -ldl test.cc
$ ./test
virtual void {anonymous}::A::print(std::ostream&) const


标签: c++ gcc g++