一个软件,如果把所有的功能写进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 主要是做符号显示隐藏
//
// Created by gearslogy on 5/9/16.
// #ifndef API_DESIGN_GLY_PLUGIN_H
#define API_DESIGN_GLY_PLUGIN_H #include <string>
class GLY_Plugin
{
public:
GLY_Plugin(std::string file);
~GLY_Plugin();
void *operator->();
void *getPlugin();
private:
std::string _dso_file;
void *_handle; //a pointer to a function can point to -> void * plugin_creator ()
typedef void* (*plugin_creator)(); // now create point can point any like -> void * plugin_creator ()
plugin_creator creator; //
typedef void (*plugin_destroy)(void *);
plugin_destroy destroyer; //plugin instance ,instance is a class handle
void *_instance;
}; #endif //API_DESIGN_GLY_PLUGIN_H
GLY_Plugin.h
//
// Created by gearslogy on 5/9/16.
//
#ifdef __GNUC__
#include <dlfcn.h>
#endif
#include "GLY_Plugin.h"
#include <stdio.h> GLY_Plugin::GLY_Plugin(std::string file)
{ _dso_file = file;
_handle = NULL;
_instance = NULL; // LINUX platform
#ifdef __GNUC__
_handle = dlopen(_dso_file.c_str(),RTLD_LAZY);
if(!_handle)
{
std::string so_open_error = file + " open error ";
throw so_open_error;
} //@creator() function return a pointers to the C++ class(_instance)
creator = (plugin_creator)dlsym(_handle,"plugin_create"); // search the signal plugin_create
if(creator == NULL)
{
dlclose(_handle);
throw "plugin creator not found ";
}
destroyer = (plugin_destroy)dlsym(_handle, "plugin_destroy");
if(destroyer == NULL)
{
dlclose(_handle);
throw "plugin destroyer not found";
} try
{
_instance = creator();
}
catch (...)
{
dlclose(_handle);
_handle= NULL;
throw std::exception();
}
#endif }
GLY_Plugin::~GLY_Plugin()
{
if(_instance)
{
printf("GLY_Plugin Free the instance %s \n",_dso_file.c_str());
destroyer(_instance); //free your dynamic library
}
if(_handle)
{
printf("GLY_Plugin Free the handle %s \n",_dso_file.c_str());
dlclose(_handle); // close the dynamic.so
}
}
void *GLY_Plugin::operator->()
{
return _instance;
}
void *GLY_Plugin::getPlugin()
{
return _instance;
}
GLY_Plugin.cpp
//
// Created by gearslogy on 5/9/16.
// #ifndef API_DESIGN_GLY_MESSAGEPLUGINAPI_H
#define API_DESIGN_GLY_MESSAGEPLUGINAPI_H class MessagePlugin_interface
{
public:
MessagePlugin_interface(){};
virtual void cookMyMessage()=;
virtual ~MessagePlugin_interface(){}; }; #endif //API_DESIGN_GLY_MESSAGEPLUGINAPI_H
GLY_MessagePluginAPI.h
//
// Created by gearslogy on 5/10/16.
// #ifndef API_DESIGN_GLY_PLUGINREGISTER_H
#define API_DESIGN_GLY_PLUGINREGISTER_H #ifdef _WIN32
#define TopVertexAPI __declspec(dllexport)
#else
#define TopVertexAPI __attribute__ ((visibility("default")))
#endif #define TopVertexHiddenAPI __attribute__((visibility("hidden"))) // do not use C++ function style.
extern "C" TopVertexAPI void *plugin_create();
extern "C" TopVertexAPI void plugin_destroy(void *); #endif //API_DESIGN_GLY_PLUGINREGISTER_H
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 ;
}
制作一个插件
#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