c语言插件实现原理,C语言实现插件机制
现在越来越多的软件项目都提供插件机制,这样使得软件的扩展性大大增强,那么到底插件机制的实现是怎么样的呢?在这里只谈论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语言实现插件机制相关推荐
- Android插件化原理解析——ContentProvider的插件化
目前为止我们已经完成了Android四大组件中Activity,Service以及BroadcastReceiver的插件化,这几个组件各不相同,我们根据它们的特点定制了不同的插件化方案:那么对于Co ...
- Android 插件化原理解析——Service的插件化
在 Activity生命周期管理 以及 广播的管理 中我们详细探讨了Android系统中的Activity.BroadcastReceiver组件的工作原理以及它们的插件化方案,相信读者已经对Andr ...
- 插件化原理解析——ContentProvider的插件化
目前为止我们已经完成了Android四大组件中Activity,Service以及BroadcastReceiver的插件化,这几个组件各不相同,我们根据它们的特点定制了不同的插件化方案:那么对于Co ...
- 如何用c语言做高精度计算原理,C语言羁绊之高精度乘法计算
很大一部分借鉴了(C语言的高精度算法)这一博客,你们可以去看看.欢迎指正!!! 1,定义 对于计算机无法用普通数据类型(如:longint)表示的大整数进行乘法运算,称为高精度算法.这里的高精度乘法主 ...
- c语言万年历程序原理,C语言实现万年历程序
C语言实现万年历程序 #include int year(int y) { if ((y%4==0) && (y%100!=0) || y%400==0) return 366; el ...
- Android 插件化原理入门笔记
Android开发笔记 onGithub 笔记,参考7.2中所列参考文章所写,DEMO地址在PluginTestDemoApplication 1.综述 2015年是Android插件化技术突飞猛进的 ...
- 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 大前端开发者需要了解的基础编译原理和语言知识
转自:https://yq.aliyun.com/articles/180879 在我刚刚进入大学,从零开始学习 C 语言的时候,我就不断的从学长的口中听到一个又一个语言,比如 C++.Java.Py ...
- C语言函数调用的原理
该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105088660 C ...
最新文章
- c++用牛顿法开多次根_望远镜的历史之三:大神出世,改变望远镜历史的竟然是牛顿...
- linux磁盘fio压力测试,fio进行磁盘压力测试
- 服务器数据库带宽费开票项目,服务器带宽和访问数据库速度
- 2019 牛客多校第三场 B Crazy Binary String
- Unity ---WidgetsUI CreateTileView Demo
- 【图像分割】基于K-means聚类算法图像分割【含Matlab源码 1476期】
- 计算机应用c 简历,计算机应用专业的简历模板
- Java PC端微信、支付宝扫码支付(一)
- js 返回值提示框不提示
- 在Chrome谷歌浏览器中使用H5地理位置API
- 手机端APP接口拦截(抓包)-Charles
- Hive Privilege 分析
- quartz框架(五)-Trigger相关内容
- python中的成员运算符用于判断指定_Python中的成员运算符用于判断指定序列中是否包含某个值...
- java中cbrt_JavaScript中带有示例的Math.cbrt()方法
- 2.19 serenity
- yolanda的性能测试经验
- mysql 唯一更新_MySQL 唯一索引和插入重复自动更新
- C语言为什么不会过时?
- Ten Googol
热门文章
- 工作102:设置url实现查询 秒呀
- “约见”面试官系列之常见面试题第十篇值meta标签(建议收藏)
- 前端学习(1930)vue之电商管理系统电商系统之美化一层循环的UI结构删除业务逻辑实现
- 前端学习(908):location常用方法
- 第二十六期:HTTP 3的前世今生及尝鲜
- 实例65:python
- 聊一聊CSS中的死循环
- android image设置adjustviewbounds_探索 Android 平台的 CameraX
- php 5.4 aws,使用 Amazon EC2 管理 AWS SDK for PHP 实例 - 适用于 PHP 的 AWS 开发工具包
- 有限状态自动机java实现_用java开发编译器之:Thompson构造,将正则表达式转换为有限状态自动机...