现在越来越多的软件项目都提供插件机制,这样使得软件的扩展性大大增强,那么到底插件机制的实现是怎么样的呢?在这里只谈论C语言的实现,其实C语言实现插件的例子也很多,像mjpg-streamer就是将输入输出做成插件,dm500机顶盒的主程序enigma也使用了插件机制,我就是从enigma当中学习的。好了,这里给一个简单的例子来看看如何实现。

我的设想是这样的:有一个主程序,有一个插件(.so文件),主程序里面提供一些最基本的功能模块,而在插件中使用这些功能模块实现某些功能。简单点就是主程序要调用.so文件中的函数,而.so要调用主程序中的某些基础函数。

为了既能使用插件a.so, 又能使用插件b.so, 还能使用插件c.so,这里要显式调用动态链接库,即通过dlopen, dlsym, dlclose来使用.so文件,还是直接来看代码。

#mkdir soplugin

#cd soplugin

#vim main.h

//main.h

#ifndef MAIN_H

#define MAIN_H

class A {

public:

A(){};

~A(){};

void p(const char *s);

};

#endif

#vim main.cpp

#include

#include   // dlopen/dlsym/dlclose头文件

#include "main.h"

void A::p(const char *s)

{

printf("A::p()\n");

}

void plugin_show(const char *s)  // 这个函数会被.so文件调用

{

printf("%s\n", s);

}

int main(int argc, char *argv[])

{

int (*PluginExec)(int argc, char *argv);

void *plugin;

printf("loading...\n");

plugin = dlopen("./tplugin.so", RTLD_GLOBAL|RTLD_NOW); // 显式打开.so文件

if (plugin == NULL) {

printf("ptr: %p\n", plugin);

perror("Can not load tplugin.so");

return -1;

}

PluginExec = (int (*)(int, char*))dlsym(plugin, "plugin_exec"); // 得到入口函数指针

if (PluginExec) {

PluginExec(0, NULL);  // 调用入口函数

}

dlclose(plugin);

return 0;

}

#vim plugin.cpp

#include "main.h"

extern void plugin_show(const char *s);

extern "C"

int plugin_exec(int argc, char *argv[])  // 这里要用extern "C"声明,否则C++编译器会给函数名加上一些乱七八糟的东西,不信你可以试试,然后用objdump去查查看

{

A a;

a.p("in plugin_exec"); // 这个在主程序中实现

plugin_show("in plugin.");  // 这个也在主程序中实现

return 0;

}

好了,代码就这些,很简单,但能说明问题就行了,再写个Makefile。

# vim Makefile

all:

g++ -shared -fPIC -DPIC -c plugin.cpp -I.

ld -shared -o tplugin.so plugin.o

g++ -Wl,-E -o mm main.cpp -ldl

前面两行是将plugin.cpp做成一个.so文件,后面一行是编绎main.cpp,这里要特别注意参数-Wl,-E,这个参数意思是将-E参数传递给链接器ld,最终的目的是将main.cpp中的函数输出成全局符号,以方便.so文件调用,如果没有此参数,那么编绎也不会有问题,但在运行时dlopen总是会失败,原因是无法解决符号依赖问题。关于这个参数你可以用objdump对比一下加与不加的结果差别。

好了,接下来编译然后运行。

#make

g++ -shared -fPIC -DPIC -c plugin.cpp -I.

ld -shared -o tplugin.so plugin.o

g++ -Wl,-E -o mm main.cpp -ldl

#./mm

loading...

A::p()

in plugin.

这个例子只是简单的实现打印,但至少已经可以看到主程序和.so文件之间可以调用了,那我再实现a.so, b.so当然也不成问题了。可能有人会产生疑问,为什么不隐式调用呢?原因是:如果隐式调用就必须在编译阶段确定好.so文件,这样就谈不上可扩展插件了,它们之间就存在了编译上的依赖关系。而显式调用是在运行期间确定他们的依赖关系的。

如果有兴趣可以参数mjpg-streamer去学习,但是mjpg-streamer中的插件没有调用主程序的函数,最好的学习例子还是enigma,他里面实现了大量的插件。以后嵌入式软件项目的扩展性要求会越来越高,插件扩展也大受欢迎,插件扩展的机制很多,需要我们去收集学习,这里讲的是最简单的一种。我为什么要学习,原因是我目前参与的一个项目主程序尽然大到30多MB,编译链接时间太长,要扩展功能就更痛苦了,一次一次的编译/链接,一次一次的等待,真是折磨。

附:

enigma是dm500机顶盒的主程序,enigma本身通过c++实现gui, gdi, dvb等一堆基础库,并实现了插件管理器,外围的功能基本全是c/c++插件实现。

enigma2是dm800的机顶盒主程序,enigma2就比enigma更高级了,他通过c++实现gui, gdi, dvb等一些基础库,其余的界面功能,机顶盒功能全部是用动态语言python实现,中间使用swig胶合在一起。也是不错的学习例子,但项目太大,学习不太容易。

c语言插件实现原理,C语言实现插件机制相关推荐

  1. Android插件化原理解析——ContentProvider的插件化

    目前为止我们已经完成了Android四大组件中Activity,Service以及BroadcastReceiver的插件化,这几个组件各不相同,我们根据它们的特点定制了不同的插件化方案:那么对于Co ...

  2. Android 插件化原理解析——Service的插件化

    在 Activity生命周期管理 以及 广播的管理 中我们详细探讨了Android系统中的Activity.BroadcastReceiver组件的工作原理以及它们的插件化方案,相信读者已经对Andr ...

  3. 插件化原理解析——ContentProvider的插件化

    目前为止我们已经完成了Android四大组件中Activity,Service以及BroadcastReceiver的插件化,这几个组件各不相同,我们根据它们的特点定制了不同的插件化方案:那么对于Co ...

  4. 如何用c语言做高精度计算原理,C语言羁绊之高精度乘法计算

    很大一部分借鉴了(C语言的高精度算法)这一博客,你们可以去看看.欢迎指正!!! 1,定义 对于计算机无法用普通数据类型(如:longint)表示的大整数进行乘法运算,称为高精度算法.这里的高精度乘法主 ...

  5. c语言万年历程序原理,C语言实现万年历程序

    C语言实现万年历程序 #include int year(int y) { if ((y%4==0) && (y%100!=0) || y%400==0) return 366; el ...

  6. Android 插件化原理入门笔记

    Android开发笔记 onGithub 笔记,参考7.2中所列参考文章所写,DEMO地址在PluginTestDemoApplication 1.综述 2015年是Android插件化技术突飞猛进的 ...

  7. 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  8. 大前端开发者需要了解的基础编译原理和语言知识

    转自:https://yq.aliyun.com/articles/180879 在我刚刚进入大学,从零开始学习 C 语言的时候,我就不断的从学长的口中听到一个又一个语言,比如 C++.Java.Py ...

  9. C语言函数调用的原理

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105088660 C ...

最新文章

  1. c++用牛顿法开多次根_望远镜的历史之三:大神出世,改变望远镜历史的竟然是牛顿...
  2. linux磁盘fio压力测试,fio进行磁盘压力测试
  3. 服务器数据库带宽费开票项目,服务器带宽和访问数据库速度
  4. 2019 牛客多校第三场 B Crazy Binary String
  5. Unity ---WidgetsUI CreateTileView Demo
  6. 【图像分割】基于K-means聚类算法图像分割【含Matlab源码 1476期】
  7. 计算机应用c 简历,计算机应用专业的简历模板
  8. Java PC端微信、支付宝扫码支付(一)
  9. js 返回值提示框不提示
  10. 在Chrome谷歌浏览器中使用H5地理位置API
  11. 手机端APP接口拦截(抓包)-Charles
  12. Hive Privilege 分析
  13. quartz框架(五)-Trigger相关内容
  14. python中的成员运算符用于判断指定_Python中的成员运算符用于判断指定序列中是否包含某个值...
  15. java中cbrt_JavaScript中带有示例的Math.cbrt()方法
  16. 2.19 serenity
  17. yolanda的性能测试经验
  18. mysql 唯一更新_MySQL 唯一索引和插入重复自动更新
  19. C语言为什么不会过时?
  20. Ten Googol

热门文章

  1. 工作102:设置url实现查询 秒呀
  2. “约见”面试官系列之常见面试题第十篇值meta标签(建议收藏)
  3. 前端学习(1930)vue之电商管理系统电商系统之美化一层循环的UI结构删除业务逻辑实现
  4. 前端学习(908):location常用方法
  5. 第二十六期:HTTP 3的前世今生及尝鲜
  6. 实例65:python
  7. 聊一聊CSS中的死循环
  8. android image设置adjustviewbounds_探索 Android 平台的 CameraX
  9. php 5.4 aws,使用 Amazon EC2 管理 AWS SDK for PHP 实例 - 适用于 PHP 的 AWS 开发工具包
  10. 有限状态自动机java实现_用java开发编译器之:Thompson构造,将正则表达式转换为有限状态自动机...