如何创建具有高可维护性的共享库?

时间:2018-11-21 08:26:52

标签: c++ gcc g++

我试图为我的C ++项目创建一个共享对象,其目的是:每次我想带来一个新类时,我只会重新编译共享对象。

下面是测试代码:

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:类TestSo从Test派生。

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

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

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;
}  

我使用以下命令行编译代码:
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

编译器没有给我任何警告或错误。它说我运行程序时undefined symbol: getObject

最后,我发现我 必须 getObject的范围extern "C"中声明test.h

dlsymlibtest.so获取getObject的地址,程序将跳转到该地址。为什么我必须声明getObject?这违反了我的目的。或者,如果我完全走错了路,该怎么办?如果没有,我该如何解决?

编辑:

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  

2 个答案:

答案 0 :(得分:1)

  

您的方法行不通,因为C ++会在编译期间更改名称,也许可以在网上或例如在this thread中找到有关此主题的更多信息。当您编译名为std::shared_ptr<Test> getObject()的函数时,它会以名为_Z9getObjectv的符号结尾,因此您需要打开此符号dlsym(handle, "_Z9getObjectv");

  

每次我想带一个新类时,我只会重新编译共享对象。

我不明白为什么您不希望仅链接到您的程序。 dlsym的创建是为了允许与链接程序有关的程序处理加载,您的程序似乎不需要此功能。对于您的程序,只需添加该函数的前向声明(不带任何外部C,因为名称由C ++修饰):

std::shared_ptr<Test> getObject();

到您的test.h文件,然后使用:

-ltest

与现在一样(!)将链接到共享库。这就是共享库首先存在的原因-因此您可以更改基础代码而无需更改客户端代码。同样,在链接的情况下,如果找不到符号,链接器将发出符号解析错误,因此您具有另一层保护,您不必担心名称混乱。只需将您的main.cpp更改为:

#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;
}  

它应该可以工作(具有正确的LD_LIBRARY_PATH)...

答案 1 :(得分:0)

以下是适合您的示例。

不需要extern "C"链接,因为您可以找到并使用经过改写的C ++名称。

此外,工厂函数应返回std::unique_ptr,以向用户传达他们现在拥有该对象。除非工厂保留对该对象的引用,否则在这种情况下,std::shared_ptr是一个不错的选择。

共享库头:

// 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.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;
}

构建共享库并找到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

用户来源:

// 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';
}

构建并运行用户代码:

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