为了让应用程序在发不之后不需要重新编译而修改程序行为,我们引入了插件机制,如Linux下的“*.so”、Windows下的“.dll”以及Java中的“.jar”,这种机制让程序的框架趋于小巧、分工明细,完成详细设计文档以后,应用程序的功能接口已经约定完好,根据需要,可以将重要的功能接口封装成插件形式的函数库,根据插件的不同,安排不同的开发人员维护,这样也可以避免因为一群人共用一套代码文件造成同步问题。
函数库分为动态库跟静态库,由于静态库是在链接阶段被整合到可执行文件中去的,程序在运行过程中不依赖静态库,这样一来,每次更新静态库都必须重新链接生成新的可执行程序,这样显然违背了插件机制的初衷,所以我们应该采用运行时链接的动态库来实现插件机制。
Linux下默认的动态库搜索路径是/lib跟/usr/lib,为了让编译器找到指定函数库,需要将动态库拷贝到/lib或者/usr/lib目录下,那么有没有办法指定动态库的绝对路径或者相对路径?答案是肯定的,Linux为动态库的访问提供了4个API,分别是dlopen、dlerror、dlsym和dlclose,这些函数的原型在系统头文件dlfcn.h中定义,其实现分别对应两个库文件(静态库libdl.a和动态库libdl.so)。
dlopen——加载动态库并返回句柄;
dlerror——如果动态库加载失败,返回错误详细消息的指针,否则返回NULL;
dlsym——传入句柄跟函数名,返回函数指针;
dlclose——释放dlopen返回的句柄。
下面演示一个用插件实现加法功能的C语言实例:
一、源代码
1、plugintest.c
#include <stdio.h>
#include <dlfcn.h>
int main(){
//句柄
void *flib;
//入口函数原型
int (*padd)(int a, int b);
//错误信息字符串
char *error_message;
int a = 2, b = 7, result = 0;
//加载plugin.so,以RTLD_LAZY方式
flib = dlopen("./libplugin.so", RTLD_LAZY);
error_message = dlerror();
if(error_message)
{
printf("%s:%d %s\n", __FILE__, __LINE__, error_message);
return -1;
}
//找到函数名为func的函数,返回其指针
padd = dlsym(flib, "add");
error_message = dlerror();
if(error_message)
{
printf("%s:%d %s\n", __FILE__, __LINE__, error_message);
return -1;
}
//调用padd指向的指针,即add函数
result = padd(a, b);
printf("%d + %d = %d\n", a, b, result);
//释放
dlclose(flib);
error_message = dlerror();
if(error_message)
{
printf("%s:%d %s\n", __FILE__, __LINE__, error_message);
return -1;
}
return 0;
}
2、plugin.c
int add(int a, int b)
{
return a+b;
}
二、编译
//生成plugin.o gcc -fpic -c plugin.c //生成libplugin.so gcc -shared -lc -o libplugin.so plugin.o //生成可执行文件plugintest gcc plugintest.c -o plugintest -ldl
三、运行结果
./plugintest 2 + 7 = 9
除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。



