从返回 c++ 智能指针的共享库(mac 上的 dylib)导出符号时出现问题

问题描述 投票:0回答:0

我有一些关于如何在共享库之间导出功能的问题,尤其是如果共享库正在使用 managed_pointers 并且我们需要在运行时加载它们。 我有两个应用程序 SampleApplication(executable) 和 Foo Module (foo.dylib)

SampleApplication 和 Foo 模块都依赖于公共模块,在公共模块中我有一个接口让我们说

class FooInterface{
   ..
   void DoSomething()
};

Foo 模块实现 FooInterface 或示例

class Foo_IMPL : public FooInterface {
     shared_ptr<FooInterface> create(...);
     void DoSomething() override;
};

还有其他模块,如 Foo,这些模块中的每一个都有自己的工厂方法(创建方法),现在的要求是我需要在应用程序需要时动态加载/卸载这些模块。所以我将 Foo 模块设为共享库,并在公共库中编写了一个 dynamicModuleHandler,如下所示

 class DynamicHandlerCommon {
    protected:
    
        template <typename C>
        friend class DynamicHandler;
    
        DynamicHandlerCommon(const std::string& libPath, const std::string& absoluteSerializerPath);
        bool load(const std::string& libPath);
        void unload();
    
        bool m_isLoaded = false;
        std::string m_libPath;
        std::string m_absoluteSerializerPath;
        bool m_completed = false;
        void* m_libraryHandle;
    };
    
    template <typename C>
    class DynamicHandler
            : public DynamicCommon
            , public BarObserverInterface
            , public std::enable_shared_from_this<DynamicHandler<C>>{
    public:
        typedef void* (*pFunc)();
        static std::unique_ptr<DynamicHandler> create(
            std::shared_ptr<ManagerInterface> connection,
            const std::string& libPath,
            const std::string& absoluteSerializerPath);
    
        DynamicCapabilityAgentHandler(std::shared_ptr<BarObserverInterface> bar,
                                      const std::string& libPath,
                                      const std::string& absoluteSerializerPath);
    
        void onBarStatusChanged(
            const BarStatusObserverInterface::Status status,
            const BarStatusObserverInterface::ChangedReason reason) override;
    
        void serialize();
        void deserialize();
    
        void getFunction();
    };
    
    template <typename C>
    DynamicHandler<C>::DynamicHandler(std::shared_ptr<BarManagerInterface> barManager,
        const std::string& libPath,
        const std::string& absoluteSerializerPath)
            : DynamicHandlerCommon(libPath, absoluteSerializerPath){
        getFunction();
    }
    
    template <typename C>
    std::unique_ptr<DynamicHandler<C>> DynamicHandler<CapabilityAgentType>::create(
        std::shared_ptr<BarManagerInterface> connection,
        const std::string& libPath,
        const std::string& absoluteSerializerPath) {
        std::unique_ptr<DynamicHandler<C>> dynamicHandler( new DynamicHandler<C>>(libPath, absoluteSerializerPath));
    
        barManager->addBarStatusObserver(DynamicHandler<C>::shared_from_this());
    
        return dynamicHandler;
    }
    
    template <typename C>
    void DynamicHandler<C>::serialize(){
        {
            std::ofstream os(m_absoluteSerializerPath.c_str());
            cereal::JSONOutputArchive archive(os);
            //m_component->serialize(archive);
            //save(archive)
        }
        unload();
    }
    
    template <typename C>
    void DynamicHandler<C>::getFunction(){
        C pFunc = reinterpret_cast<C>(dlsym(m_libraryHandle, "createInstance"));
        if (!pFunc) {
            std::cout << dlerror() << std::endl;
            return;
        }
    
        C* pInstance = static_cast<C>(pFunc());
    
    }
    
    template <typename C>
    void DynamicHandler<C>::deserialize(){
    
    }
    
    template <typename C>
    void DynamicHandler<C>::onBarStatusChanged(
        const BarStatusObserverInterface::Status status,
        const BarStatusObserverInterface::ChangedReason reason){
        if(m_completed)
        {
            return;
        }
    
        if(BarStatusObserverInterface::Status::CONNECTED == status){
            m_completed = true;
            serialize();
        }
    }

我还在我的 Foo 模块中创建了一个新方法 createInstance,看起来像这样。

Util.h  in Foo module 
    extern "C" {
    __attribute__((
        __visibility__("default"))) void*
    createInstance();
    }
Util.cpp in Foo Module

void*
createInstance() {
    return Foo_IMPL::create().get();
}

为了提供更多上下文,我正在使用 extern“C”,这样方法名称就不会被管理,但这会导致问题,我不确定我的 SampleApplication 中的 getFunction 中的实现应该是什么,即

template <typename C>
        void DynamicHandler<C>::getFunction(){
            C pFunc = reinterpret_cast<C>(dlsym(m_libraryHandle, "createInstance"));
            if (!pFunc) {
                std::cout << dlerror() << std::endl;
                return;
            }
        
            C* pInstance = static_cast<C>(pFunc());
            ...
        }

基本上,如果我将导出的函数更改为像

extern "C" {
__attribute__((
    __visibility__("default"))) std::shared_ptr<FooInterface>
createInstance();
}

然后我得到一个错误说明

error: 'createInstance' has C-linkage specified, but returns incomplete type 'std::shared_ptr<FooInterfaceInterface>' which could be incompatible with C [-Werror,-Wreturn-type-c-linkage]

因此我将导出的函数更改为如下所示

extern "C" {
__attribute__((
    __visibility__("default"))) void*
createInstance();
}

void * createInstance() {
    return Foo_IMPL::create().get();
}

但现在我不确定我应该如何把它扔回去,因为我得到了错误 在行中分配抽象类类型“FooInterface”的对象 C* pInstance = static_cast(pFunc());其中 C 是 FooInterface

因此,如果我在这里遗漏了什么,以及如果其中一个/某些方法返回智能指针,使用 dlopen/dlsym 加载/卸载共享库的最佳方式是什么,我想获得反馈/意见。如果这不是理想的方式,我可以针对我的情况采用其他替代方法。我最初的想法是创建一个 SampleApplication 可以缓存的接口,然后有一个实现它的包装类,基于是否调用任何方法,它将在运行时加载 foo.lib,以某种方式从中获取实例,然后基本上调用关于它的方法,请对这种方法以及我的用例是否可行发表评论。我的项目仅与此处相关的 c++11 兼容。

--------更新------------ 所以我也试过我的导出功能是这样的,它有点工作

void createInstance(FooInterface* fooInterface) {
    fooInterface = Foo_IMPL::create().get();
    if(fooInterface){ // here fooInterface is not null

    }
}

但是在 SampleApplication 中,如果我的代码是这样的

template <typename C>
void DynamicHandler<C>::getFunction(){
C pFunc = reinterpret_cast<C(dlsym(m_libraryHandle,"createInstance"));
if (!pFunc) {
   std::cout << dlerror() << std::endl;
   return;
}
        
C* pInstance = nullptr;
pFunc(pInstance);
if(pInstance){  // here pInstance is null

}
...
}

所以我的猜测是 smart_pointer 在 pFunc(pInstance) 之后被销毁;所以仍然不确定这里最好的选择是什么

c++ smart-pointers dllexport
© www.soinside.com 2019 - 2024. All rights reserved.