C语言插件机制(下)


转载:http://abruzzi.iteye.com/blog/739673


前言

上一篇文章简单介绍了*NIX下的动态库的使用,我们在这篇文章中实现一个计算器,计算器程序calc本身不做运算,只是将操作数传递给具体的插件(adder, suber, muler, diver)来完成实际运算。首先,计算器根据插件配置文件plugin.xml来确定插件的位置,名称,入口符号的定义,然后依次调用各个插件完成计算。

 

插件列表

文中涉及到的插件定义在plugin.xml中,文档结构如下:

 

Xml代码   收藏代码
  1. <plugins>  
  2.     <plugin name="adder">  
  3.         <library path="/home/juntao/.libs/adder.so">  
  4.         </library>  
  5.         <entry name="add">  
  6.         </entry>  
  7.     </plugin>  
  8.     <plugin name="suber">  
  9.         <library path="/home/juntao/.libs/suber.so">  
  10.         </library>  
  11.         <entry name="sub">  
  12.         </entry>  
  13.    </plugin>  
  14.    <plugin name="muler">  
  15.         <library path="/home/juntao/.libs/muler.so">  
  16.         </library>  
  17.         <entry name="mul">  
  18.         </entry>  
  19.    </plugin>  
  20.    <plugin name="diver">  
  21.         <library path="/home/juntao/.libs/diver.so">  
  22.         </library>  
  23.         <entry name="div">  
  24.         </entry>  
  25.    </plugin>  
  26. </plugins>  

 

每个插件为一个plugin标签,plugin标签中包含library, entry两个字标签,分别定义动态库文件的路径及名称和插件函数的入口。为了简便,我们不重复设计list及xml解析,这里使用libxml2作为xml的分析器,GLIB中的GSList(单链表)来作为插件列表的链表对象。

 

每一个插件在C语言中的定义如下,非常简单(plugin.h)

 

C代码   收藏代码
  1. #ifndef _PLUGIN_H_  
  2. #define _PLUGIN_H_  
  3.   
  4. typedef struct{  
  5.     char name[64];  
  6.     char path[256];  
  7.     char entry[128];  
  8.     int version;  
  9. }Plugin;  
  10.   
  11. #endif  

 

这里为了行文方便,Plugin结构中的字符串为静态尺寸。

 

计算器 

计算器调用parseconf模块中的load_plugins将plugin.xml中定义的Plugin加载进一个GSList,以备后用:

 

C代码   收藏代码
  1. #include "plugin.h"  
  2.   
  3. extern int load_plugins(char *config, GSList **list);  

 

插件中的函数原型应该符合接口定义:

 

C代码   收藏代码
  1. //pointer to function, which return a double, and get 2 double as input  
  2. double (*pfunc)(double a, double b);  

 

计算器的主要代码如下:

C代码   收藏代码
  1. int calc_test(double a, double b){  
  2.     GSList *list = NULL, *it = NULL;  
  3.     Plugin *pl = NULL;  
  4.       
  5.     //insert a null node into list at first  
  6.     list = g_slist_append(list, NULL);  
  7.       
  8.     int code = 0;  
  9.     double result;  
  10.   
  11.     //load plugin defined in plugin.xml into list  
  12.     load_plugins("plugin.xml", &list);  
  13.       
  14.     for(it = list; it != NULL; it = it->next){  
  15.         pl = (Plugin *)it->data;  
  16.         if(pl == NULL){  
  17.             continue;  
  18.         }else{  
  19.             //open the library  
  20.             flib = dlopen(pl->path, RTLD_LAZY);  
  21.             dlError = dlerror();  
  22.   
  23.             if(dlError){  
  24.                 fprintf(stderr, "open %s failed\n", pl->name);  
  25.                 g_slist_free(list);  
  26.                 return -1;  
  27.             }  
  28.               
  29.             //get the entry  
  30.             *(void **)(&pfunc) = dlsym(flib, pl->entry);  
  31.             dlError = dlerror();  
  32.             if(dlError){  
  33.                 fprintf(stderr, "find symbol %s failed\n", pl->entry);  
  34.                 g_slist_free(list);  
  35.                 return -1;  
  36.             }  
  37.   
  38.             //call the function  
  39.             result = (*pfunc)(a, b);  
  40.             printf("%s(%f, %f) = %f\n", pl->entry, a, b, result);  
  41.               
  42.             //then close it  
  43.             code = dlclose(flib);  
  44.             dlError = dlerror();  
  45.   
  46.             if(code){  
  47.                 fprintf(stderr, "close lib error\n");  
  48.                 g_slist_free(list);  
  49.                 return -1;  
  50.             }  
  51.         }  
  52.     }  
  53.       
  54.     g_slist_free(list);  
  55.     return 0;  
  56. }  

 

首先,定义一个GSList,然后将其传递给load_plugins,load_plugins解析plugin.xml,然后填充list返回,calc_test遍历插件列表,并调用每一个插件定义的entry.

 

除法器

 我们来看一个具体的插件:做除法的模块

 

C代码   收藏代码
  1. #include <stdio.h>  
  2.   
  3. double div(double a, double b){  
  4.     if(b == 0){  
  5.         fprintf(stderr, "div zero error\n");  
  6.         return -1;  
  7.     }else{  
  8.         return a / b;  
  9.     }  
  10. }  

diver.c在编译之后,生成diver.so,将其置于plugin.xml定义的位置处即可。

 

运行结果如下图所示:


C语言插件机制(下)_第1张图片

其他代码如xml的解析,GSList的使用等与插件机制关系不大,感兴趣的朋友可以在附件中查看。


你可能感兴趣的:(C语言插件机制(下))