Write Your software base on plugin(C/C++ ABI)
一个软件,如果把所有的功能写进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 #include <string> 9 class GLY_Plugin 10 { 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 handle 31 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 #include <dlfcn.h> 6 #endif 7 #include "GLY_Plugin.h" 8 #include <stdio.h> 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 platform 21 #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_create 32 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 try 45 { 46 _instance = creator(); 47 } 48 catch (...) 49 { 50 dlclose(_handle); 51 _handle= NULL; 52 throw std::exception(); 53 } 54 #endif 55 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 library 63 } 64 if(_handle) 65 { 66 printf("GLY_Plugin Free the handle %s \n",_dso_file.c_str()); 67 dlclose(_handle); // close the dynamic.so 68 } 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_interface 12 { 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 #else 11 #define TopVertexAPI __attribute__ ((visibility("default"))) 12 #endif 13 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 <iostream> #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 <GLY_MessagePluginAPI.h> #include <stdio.h> #include <GLY_PluginRegister.h> 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 unloading
GLY_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