关于动态库
- 动态加载库的优点是在程序运行时加载,而且开发主程序的时候不需要include 库的 .h文件。只需要知道函数的调用格式就可以了。
- 动态加载库需要使用CPU 的MMU 支持,所以在cortex-M 单片机上通常不能使用动态加载库的机制。
- 我关心得是利用动态库技术来实现轻量级动态软件组件(例如IEC61499 功能块)的部署,更新和维护。
为什么关心动态库的动态加载
实现软件组件的远程动态部署和更新。例如在IEC61499 运行时中,如果用户自己开发ST或者C语言的功能块,开发环境通常是export 模块的C++ 源码,需要重新编译运行时才能更新。无法实现远程更新。如果使用docker 容器工具,显然又过于庞大。因此,我尝试使用动态库来实现功能块的远程部署和独立开发。以后另文报告。
测试例子
CSDN 有许多关于linux 动态库的博文,但是许多文章中不是代码有错误,就是文字太多,或者看不明白。最后
参考了:Linux动态库的 静态加载 和 动态加载 的使用 的博文,并且做了部分修改。我的代码在 window10 的ubuntu (WSL2)上调试通过。
首先,编写了两个函数 math.c 和show.c
math.c
#include<stdio.h>
int add(int a,int b)
{
return a+b;
}
show.c
#include<stdio.h>
int show(int a)
{
printf("两数之和:%d\n",a);
}
分别进行编译
gcc -fpic -c math.c -o math.o
gcc -fpic -c show.c -o show.o
在目录中出现了math.o和show.o
链接成共享库
gcc -shared math.o show.o -o libmath.so
编写调用共享库的主程序(dmain.c)
#include<stdio.h>
#include<dlfcn.h>
typedef int(*PFUNC_CALL)(int,int);
typedef int(*PFUNC_SHOW)(int); //给函数指针定义一个别名 PFUNC_SHOW = int(*)(int)
int main()
{
printf("Dynamic lib test\n");
void *handle = dlopen("./libmath.so",RTLD_LAZY); //加载动态库
if(handle==NULL)
{
printf("dlopen fail:%s\n",dlerror());
return -1;
}
//获取函数地址
printf("get add function address\n");
PFUNC_CALL add = (PFUNC_CALL)dlsym(handle,"add");
if(add==NULL)
{
printf("dlsym fail:%s\n",dlerror());
return -1;
}
printf("get show function address\n");
PFUNC_SHOW show = (PFUNC_SHOW)dlsym(handle,"show");
if(show==NULL)
{
printf("dlsym fail:%s\n",dlerror());
return -1;
}
show(add(9,5));
dlclose(handle);
return 0;
}
编译 dmain
gcc dmain.c -ldl -o test
运行 ./test
Dynamic lib test
get add function address
get show function address
两数之和:14
使用的主要函数
加载共享库 ---- dlopen
filename:给路径按照路径加载,给文件名就根据LD_LIBRARY_PATH环境变量去查找
flag:加载标志
RTLD_LAZY:延迟加载,什么时候真正使用的时候才加载
RTLD_NOW:立即加载
返回值:
成功返回动态库的句柄,失败返回NULL
获取动态库的的函数地址 ------- dlsym
handle:动态库的句柄
symbol:函数名
返回值:
成功返回函数地址,失败返回NULL
卸载动态库 -------------dlclose
handle:动态库的句柄
获取出错信息 --------- dlerror
返回错误字符串