# test_plugin_dll **Repository Path**: occt/test_plugin_dll ## Basic Information - **Project Name**: test_plugin_dll - **Description**: 演示使用Boost::DLL创建一个插件化的DLL:(1) 加载及卸载,(2) 接口的设计 -- factory/creator 。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-15 - **Last Updated**: 2024-10-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # README # 1. 借助 `Boost.DLL`,实现将 `DSO/DLL` 接口封装成插件接口。 2. 使用`Factory`模式,提供创建插件实例的接口。 ## 1. 实现插件接口 ## ### 1.1 DSO/DLL原型定义 ### ```c++ class DIInterface { public: DIInterface() = default; virtual ~DIInterface() = default; //virtual std::shared_ptr clone() = 0; virtual void loadInfo(const std::string& dataFile) = 0; virtual QWidget* getWidget() = 0; virtual void unload() = 0; protected: QWidget* widget_; }; ``` ### 1.2 接口定义及实现 ### ```c++ std::shared_ptr diLoader(const std::string& infoFile) { std::shared_ptr ptr = std::make_shared(); ptr->loadInfo(infoFile); return ptr; } BOOST_DLL_ALIAS(diLoader, // 被封装成插件接口的函数名 diLoaderAlias); // 别名,可用于创建插件实例 ``` ## 2. 插件加载 ## ```c++ // static const char* kDILoaderFnName = "diLoaderAlias"; const std::string dir_path = boost::dll::program_location().parent_path().string(); const auto chaoke_dll_path = fs::path(dir_path) / "di_plugin_chaoke.dll"; lib_ = boost::dll::shared_library(chaoke_dll_path.string()); try { auto creator = boost::dll::import_alias(chaoke_dll_path.string(), kDILoaderFnName, boost::dll::load_mode::append_decorations); auto loader_proto = lib_.get_alias(kDILoaderFnName); instance_ = loader_proto(dataFilePath); } catch (const std::exception& e) { SPDLOG_WARN("Failed to load dll: {}", e.what()); return false; } ``` ## 3. 插件卸载 ## 在卸载`DSO/DLL`之后,由于类的成员函数代码内存被释放,故其`vtable`所指向的内存(即成员方法)变成非法地址,在调用其成员方法函数,以及析构函数时,会导致程序崩溃。 所以在卸载`DLL/DSO`之前,需要先释放外部持有的资源: 1. 调用`unload`接口,释放资源,比如释放`QWidget`; 2. 释放外部持有的`shared_ptr`; ## 4. 技巧:将`boost::dll::shared_library`生命周期与Plugin实例对象生命周期绑定 ## 定义如下`deletor`: ```c++ struct library_holding_deleter { library_holding_deleter(std::shared_ptr libDLL) : lib_(libDLL) {} void operator()(DIInterface* p) const { delete p; } std::shared_ptr lib_; }; ``` 在创建`DIInterface`实例时,传入`library_holding_deleter`(make_shared不支持传入自定义`deleter`): ```c++ // auto lib_dll = std::make_shared(chaoke_dll_path.string()); // library_holding_deleter deletor(lib_dll); std::shared_ptr diLoader(const std::string& infoFile, library_holding_deleter deletor) { std::shared_ptr ptr(new test::plugin::DIInfoChaoke, deletor); ptr->loadInfo(infoFile); return ptr; } ``` ## 5. 资料 ## * [Boost DLL -- Plugin](https://www.boost.org/doc/libs/1_86_0/doc/html/boost_dll/tutorial.html) * [跨平台的 plugin 開發函式庫:Boost DLL - 進階](https://viml.nchc.org.tw/archive_blog_614/)