概述
动态库的使用分为两种方式(按照编码内容,编译方式及动态库加载时机来区分):
- 显示调用
- 隐式调用
1、动态库的制作
动态库测试内容如下:
- 动态库对应的源文件 “test_lib.c”
#include "stdio.h"
void test_print(void) {
printf("======= This is a test line.\n");
return;
}
- 动态库对应的头文件 “test_lib.h”
void test_print(void);
编译命令如下:
gcc test_lib.c -fPIC -shared -o libtest.so
说明: -fPIC :表示生成位置无关代码(PIC:Position Independent Code)
-shared : 表示创建生成动态共享库
2、隐式调用(程序启动运行前加载动态库)
在代码中没有指明需要的动态库,只包含库的头文件和库函数,需要在编译时来指明需要的动态库,软件启动运行前会加载动态库。
测试文件 test_bin1.c 内容如下:
#include <stdio.h>
#include "test_lib.h"
int main(void) {
printf("========= start...\n");
test_print();
return 0;
}
编译命令如下(和链接静态库命令基本一样):
gcc test_bin1.c -L. -ltest -o test1
说明:编译的时候指定了libtest.so(上述编译好的动态库)
测试1:没有指定动态库路径,且没有将生成的动态库拷贝到系统路径下,测试结果如下图:
Error:报错找不到动态库 libtest.so
没有打印main函数入口的内容,说明动态库加载是在软件启动时进行的。
测试2:指定动态库的路径后(也可以将动态库复制到系统目录下),测试结果如下图:
3、显示调用 (程序运行过程中加载动态库)
在代码中明确指出需要的动态库,不用在编译时指定。软件运行过程中,使用特定的函数来加载动态库,使用特定函数通过符号名来查找动态库内的函数或变量,并调用。
测试文件 test_bin2.c 内容如下:
#include <stdio.h>
#include <dlfcn.h>
#include "test_lib.h"
int main(void) {
void * handle = NULL;
void (* pFuc)(void) = NULL; //函数指针
printf("========= start...\n");
handle = dlopen("libtest.so", RTLD_NOW); //打开动态库
if (handle == NULL) {
printf("%s\n", dlerror());
return -1;
}
pFuc = dlsym(handle, "test_print"); // 查找需要使用的符号
if ((pFuc != NULL) && (NULL == dlerror()) ) {
pFuc(); // 调用动态库中的函数
} else {
printf("get test_print FUNC failed.\n");
}
dlclose(handle); // 卸载动态库
return 0;
}
编译命令如下:
gcc test_bin2.c -ldl -o test2
说明:不需要指定libtest.so,但是需要链接libdl.so(或者libdl.a)库,因为使用了libdl库中的函数
测试1:没有指定动态库路径,测试结果如下图:
Error::报错找不到动态库 libtest.so
有打印main函数入口的内容,说明软件是可以启动的,动态库是在软件运行过程中加载的。
测试2:指定动态库的路径后,测试结果如下图:
4、附录
对应测试例子的Makefile文件如下:
all: test1 test2
test1:test_bin1.c libtest.so
gcc test_bin1.c -L. -ltest -o test1
test2:test_bin2.c
gcc test_bin2.c -ldl -o test2
libtest.so:test_lib.c
gcc $^ -fPIC -shared -o $@
clean:
rm -f libtest.so test1 test2
.PHONY: clean all