【转】C语言插件机制(上)

本文转自:http://abruzzi.iteye.com/blog/739673

 

前言

插件机制可以使得应用程序在发布之后,在不经过重新编译的情况下修改应用程序的行为,这种形式使得应用的框架比较小巧,也可以给用户一些自由(不是 完全的自由,有一定的限制)。Java中,使用*.jar或者其他的脚本引擎都可以完成这样的工作,如Eclipse那样。在C语言中,当然可以使用脚本 引擎来实现,比如emacs,内置一个lisp的引擎,用户可以自己为emacs写脚本,访问emacs环境的一些组件,从而定制emacs.这里要讨论 的无需使用脚本引擎,而是用C语言访问动态链接库来实现。

Linux下的动态库

Linux环境中,与windows下一样,函数库有两种方式:静态库和动态库,静态库参与连接,由于要将目标代码.o与lib中的函数符号合并在 一起,所以最终生成的可执行文件较大。一般以.a结尾。如libxxx.a。而动态库(共享库)则不参与编译,只是在运行时才加载如内存,且仅加载一次, 因此最终的可执行文件较小。事实上,当一个可执行文件需要运行动态库中的函数时,系统会在内存中查找,如果已经加载,则直接调用,否则才做一次加载,动态 库的结尾一般为.so,如libxxx.so。

 

Linux为动态库的访问提供了4个API,分别为dlopen  , dlerror  , dlsym  和 dlclose。这些API的原型定义在文件 dlfcn.h中,其实现则分别对应有两个库文件( 静态库 libdl.a  和动态库 libdl.so )。

 

 

  • dlopen加载动态库,并返回句柄
  • dlerror如果加载,访问符号出错,可以通过此接口获得详细的描述
  • dlsym返回一个动态库中的符号,即通过函数名获得此函数的指针
  • dlclose完成之后,释放dlopen返回的句柄
动态库的使用较为简单,比如动态库的名称为plugina.so,其中包含这样的函数原型:

C代码   收藏代码
  1. int  func( int  a,  int  b);  
可以看下一个例子:

C代码   收藏代码
  1. #include <dlfcn.h>   
  2.   
  3. //句柄   
  4. void  *flib;  
  5.   
  6. //入口函数原型   
  7. int  (*pfunc)( int  a,  int  b);  
  8.   
  9. //错误信息字符串   
  10. char  *error_message;  
  11.   
  12. int  plugin_test(){  
  13.     int  a = 1, b = 4;  
  14.     int  result = 0;  
  15.       
  16.     //加载plugina.so,以RTLD_LAZY方式   
  17.     flib = dlopen("/home/juntao/.libs/plugina.so" , RTLD_LAZY);  
  18.     error_message = dlerror();  
  19.       
  20.     if (error_message){  
  21.         return  (-1);  
  22.     }  
  23.       
  24.     //找到函数名为func的函数,返回其指针   
  25.     *(void  **)(&pfunc) = dlsym(flib,  "func" );  
  26.     error_message = dlerror();  
  27.     if (error_message){  
  28.         return  (-1);  
  29.     }  
  30.       
  31.     //调用pfunc指向的指针,及func函数   
  32.     result = pfunc(a, b);  
  33.       
  34.     //释放   
  35.     int  code = dlclose(flib);  
  36.     error_message = dlerror();  
  37.   
  38.     if (error_message){  
  39.         return  (-1);  
  40.     }  
  41.       
  42.     return  0;  
  43. }  
 

编译运行

假设plugina.so的源文件为plugina.c,内容为:

 

C代码   收藏代码
  1. //file plugina.c   
  2.   
  3. int  func( int  a,  int  b){  
  4.     int  c = 0;  
  5.     c = 3*a + 4*b + 6;  
  6.       
  7.     return  c;  
  8. }  

 

我们将这个.c文件编译为.so,命令如下:

 


//生成plugina.o
$gcc -c -fpic plugina.c

//生成plugina.so
$gcc -shared -lc -o plugina.so plugina.o

 

将动态库访问部分的代码存为plugintest.c,然后使用下列命令编译:

 

 

C代码   收藏代码
  1. $gcc -o plugintest plugintest.c -ldl  

 

 -ldl意思是,使用库libdl.so,linux下访问搜索路径内的库文件无需加lib前缀。

 

将生成的plugina.so放入路径/home/juntao/.libs/,然后运行plugintest。

 


$./plugintest

result = 25

 

好了,这一次先介绍一些基础知识,相信在此基础上,很多朋友都可以自己设计出一些简单实用的支持“插件”的应用来了,我们下一次详细讨论一个更实际 一些的例子,一个计算器的实现,这个计算器只有简单的框剪,所有的运算都通过插件来实现。用户可以通过配置文件来定制插件的路径,入口等信息。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值