一个软件,如果把所有的功能写进C++源码,维护,扩展,编译都特别麻烦。
共享库后缀名。Linux -> .so Windows -> .dll
关于动态符号显示问题,具体可以看系统的API,现在做了个只支持Linux.
Linux 查看一个动态库的符号 nm -D plugin.so
注意Linux如果不设置符号隐藏,那么默认的动态库所有的符号都是暴露的。可以用下面的语句设置符号是可暴露。
#define TopVertexAPI __attribute__ ((visibility("default")))
为什么不读取C++类的符号,因为每个编译器编译C++的函数符号都是不一样,所以将要暴露的符号全部定义为C符号,
C符号不会被修饰。好做跨平台。关键字:extern "C"
设计方法:GLY_Plugin.h 主要管理插件读取,插件释放内存,查找符号。
GLY_MessagePluginAPI.h 主要是纯虚类,提供给用户的API
GLY_PluginRegister.h 主要是做符号显示隐藏
1 // 2 // Created by gearslogy on 5/9/16. 3 // 4 5 #ifndef API_DESIGN_GLY_PLUGIN_H 6 #define API_DESIGN_GLY_PLUGIN_H 7 8 #include9 class GLY_Plugin10 {11 public:12 GLY_Plugin(std::string file);13 ~GLY_Plugin();14 void *operator->();15 void *getPlugin();16 private:17 std::string _dso_file;18 void *_handle;19 20 //a pointer to a function can point to -> void * plugin_creator ()21 typedef void* (*plugin_creator)();22 23 // now create point can point any like -> void * plugin_creator ()24 plugin_creator creator;25 26 //27 typedef void (*plugin_destroy)(void *);28 plugin_destroy destroyer;29 30 //plugin instance ,instance is a class handle31 void *_instance;32 };33 34 35 #endif //API_DESIGN_GLY_PLUGIN_H
1 // 2 // Created by gearslogy on 5/9/16. 3 // 4 #ifdef __GNUC__ 5 #include6 #endif 7 #include "GLY_Plugin.h" 8 #include 9 10 11 GLY_Plugin::GLY_Plugin(std::string file)12 {13 14 15 _dso_file = file;16 _handle = NULL;17 _instance = NULL;18 19 20 // LINUX platform21 #ifdef __GNUC__22 _handle = dlopen(_dso_file.c_str(),RTLD_LAZY);23 if(!_handle)24 {25 std::string so_open_error = file + " open error ";26 throw so_open_error;27 }28 29 30 //@creator() function return a pointers to the C++ class(_instance)31 creator = (plugin_creator)dlsym(_handle,"plugin_create"); // search the signal plugin_create32 if(creator == NULL)33 {34 dlclose(_handle);35 throw "plugin creator not found ";36 }37 destroyer = (plugin_destroy)dlsym(_handle, "plugin_destroy");38 if(destroyer == NULL)39 {40 dlclose(_handle);41 throw "plugin destroyer not found";42 }43 44 try45 {46 _instance = creator();47 }48 catch (...)49 {50 dlclose(_handle);51 _handle= NULL;52 throw std::exception();53 }54 #endif55 56 }57 GLY_Plugin::~GLY_Plugin()58 {59 if(_instance)60 {61 printf("GLY_Plugin Free the instance %s \n",_dso_file.c_str());62 destroyer(_instance); //free your dynamic library63 }64 if(_handle)65 {66 printf("GLY_Plugin Free the handle %s \n",_dso_file.c_str());67 dlclose(_handle); // close the dynamic.so68 }69 }70 void *GLY_Plugin::operator->()71 {72 return _instance;73 }74 void *GLY_Plugin::getPlugin()75 {76 return _instance;77 }
1 // 2 // Created by gearslogy on 5/9/16. 3 // 4 5 #ifndef API_DESIGN_GLY_MESSAGEPLUGINAPI_H 6 #define API_DESIGN_GLY_MESSAGEPLUGINAPI_H 7 8 9 10 11 class MessagePlugin_interface12 {13 public:14 MessagePlugin_interface(){};15 virtual void cookMyMessage()=0;16 virtual ~MessagePlugin_interface(){};17 18 };19 20 21 #endif //API_DESIGN_GLY_MESSAGEPLUGINAPI_H
1 // 2 // Created by gearslogy on 5/10/16. 3 // 4 5 #ifndef API_DESIGN_GLY_PLUGINREGISTER_H 6 #define API_DESIGN_GLY_PLUGINREGISTER_H 7 8 #ifdef _WIN32 9 #define TopVertexAPI __declspec(dllexport)10 #else11 #define TopVertexAPI __attribute__ ((visibility("default")))12 #endif13 14 #define TopVertexHiddenAPI __attribute__((visibility("hidden")))15 16 17 18 // do not use C++ function style.19 extern "C" TopVertexAPI void *plugin_create();20 extern "C" TopVertexAPI void plugin_destroy(void *);21 22 23 #endif //API_DESIGN_GLY_PLUGINREGISTER_H
主程序:
#include#include "GLY_Plugin.h"#include "GLY_MessagePluginAPI.h"using namespace std;int main(){ GLY_Plugin MessagePlugin_dyn("./libapi_plugin.so"); MessagePlugin_interface *message_plugin_handle = (MessagePlugin_interface*) (MessagePlugin_dyn.getPlugin()); message_plugin_handle->cookMyMessage(); return 0;}
制作一个插件
#include#include #include class Message_Plugin:public MessagePlugin_interface{public: Message_Plugin() { } void cookMyMessage() { printf("MessagePlugin cookMyMessage Houdini function \n"); } static Message_Plugin * plugin_create() { return new Message_Plugin; // create the class pointer } static void *plugin_destroy(Message_Plugin *plugin) { delete plugin; } virtual ~Message_Plugin() { }};void *plugin_create(){ printf("plugin loading\n"); return Message_Plugin::plugin_create(); // for our plugin system}void plugin_destroy(void *plugin){ printf("plugin unloading\n"); Message_Plugin::plugin_destroy((Message_Plugin*) plugin );}
主程序运行结果:
plugin loading
MessagePlugin cookMyMessage Houdini function GLY_Plugin Free the instance ./libapi_plugin.so plugin unloadingGLY_Plugin Free the handle ./libapi_plugin.so
GCC对一些属性的定义:
#if defined _WIN32 || defined __CYGWIN__ #ifdef BUILDING_DLL #ifdef __GNUC__ #define DLL_PUBLIC __attribute__ ((dllexport)) #else #define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. #endif #else #ifdef __GNUC__ #define DLL_PUBLIC __attribute__ ((dllimport)) #else #define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax. #endif #endif #define DLL_LOCAL#else #if __GNUC__ >= 4 #define DLL_PUBLIC __attribute__ ((visibility ("default"))) #define DLL_LOCAL __attribute__ ((visibility ("hidden"))) #else #define DLL_PUBLIC #define DLL_LOCAL #endif#endif