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

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 }

GLY_Plugin.cpp

 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

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

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

时间: 2024-08-26 05:08:54

Write Your software base on plugin(C/C++ ABI)的相关文章

Method and apparatus for transitioning between instruction sets in a processor

A data processor (104) is described. The data processor (104) is capable of decoding and executing a first instruction (212) of a first instruction set and a second instruction (213-219) in a second instruction set wherein the first instruction (212)

Gradle之旅-使用gradle+eclipse构建web项目

在前一篇博文中我们成功的搭建好了eclipse+gradle环境,那么接下来就开始使用eclipse+gradle构建web项目吧. 我们先打开eclipse新建一个动态web项目,到设置webcontent时将webcontent改为webroot(这只是个人喜好,可以不用修改,也可以修改为其他目录,gradle默认的是/src/main/webapp,但是我个人不是很喜欢这样的目录结构,所以我会在gradle的构建文档中定义默认的webcontent目录),创建好web项目后我们在src下添

Building Microservices with Spring Boot and Apache Thrift. Part 1 with servlet

https://dzone.com/articles/building-microservices-spring In the modern world of microservices it's important to provide strict and polyglot clients for your service. It's better if your API is self-documented. One of the best tools for it is Apache T

【转】使用BBB的device tree和cape(重新整理版)

只要你想用BBB做哪怕一丁点涉及到硬件的东西,你就不可避免地要用到 cape和device tree的知识.所以尽管它们看起来很陌生而且有点复杂,但还是得学.其实用起来不难的.下面我只讲使用时必须会的内容,不深究其工作原理.文中基本没有 废话,请仔细阅读每个字,勿遗漏细节. 我们已经知道beagleboard官网上有一些官方的硬件外设,比如lcd显示屏之类的,他们管这些外设叫做cape.其实应该说只要是修改了芯 片引脚功能,或占用了空闲的引脚的东西,都可以叫做cape.比如之前我们提到的开启某些

JDK版本不兼容问题之:一台机器安装多个版本的JDK

我的机器上最开始安装的是jdk1.6,后来因为工作需要又安装了jdk1.4.但是,环境变量我并未更改,还是指向jdk1.6的路径的. 可是,在cmd窗口输入 java -version 却得到是1.4.2. 查询环境变量: 1.我的电脑->属性->高级->环境变量 2. 系统环境变量(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment)   当前用户环境变量(HKEY_CURREN

【转】用Device tree overlay掌控Beaglebone Black的硬件资源

原文网址:https://techfantastic.wordpress.com/2013/11/15/beaglebone-black-device-tree-overlay/ 经过一晚上的Google,终于大致明白device tree是怎么用的了,这里简单梳理一下思路. 一.简介===============================================================device tree是ARM linux 3.7开始使用的系统控制硬件资源的方式,这里

systemctl中添加mysql服务

由于mysql的版本更新,许多术语有了新含义,所以需要特别指出,mysqld.service 等价于mysqld vim /usr/lib/systemd/system/mysqld.service [Unit]Description=MySQL Community ServerAfter=network.targetAfter=syslog.target [Install]WantedBy=multi-user.targetAlias=mysql.service [Service] # 启动服

Android内核源码Abi目录学习笔记

好记性不如烂笔头,今天要学习的是Android中Abi目录下的代码.下面是基本的学习的笔记的汇总. 首先是include中的头文件的说明. 在cxxabi的头文件中主要需要掌握下面的几个点: 1.这个头文件中包含的主要的功能就是基于C++ 2.9.5中的驱动的类型的信息. 2.驱动的类型这里面主要定义了这么几类: 2.1  __fundamental_type_info  基本驱动类型的信息 2.2 __array_type_info 数组驱动类型的信息 2.3 __function_type_

software with plugin

Linux 查看一个动态库的符号 nm -D plugin.so Windows dumpbin /exports plugin.dll linux 的符号是默认所有导出的,而windows是默认hide的. #define ALPHAAPI __attribute__ ((visibility("default"))) #define ALPHAAPI __attribute__ ((visibility("hidden")))