动态库的制作和使用
lib库名.so
- 将所有要打包的动态库的源文件编译为目标文件(与位置无关的目标文件?)
gcc -c -fPIC t*.c 将所有t 开头 的.c 文件打包生成与位置无关的.o 文件 - 将第一步中生成的目标文件打包成为动态库
gcc -shared -o libt_math.so *.o - 使用动态库链接生成可执行文件
gcc main.c -L. -lt_math
注意: 这一步使用的是静态连接器,当识别为动态库时,只是check 一下其中有没有需要的函数 没有则会报错。
然后执行./a.out 会有error :
显示 libt_math.so cant open 找不到这个文件
产生这个error 的原因是动态连接器到不到文件
处理方法
ldd a.out : 查看 a.out 在执行时,需要依赖那些动态库
普通的c 程序依赖的库如下
linux-vdso.so.1 => (0x00007ffd769f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fee7137b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fee71745000)
libt_math.so =》 not found
表示动态链接器无法找到这个动态库
告知动态连接器这个库文件的位置:
1.export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
冒号分隔符分隔多条路径
2. 动态连接器默认的搜索路径是 /lib 或者是 /usr/lib
静态库和动态库的区别
- 使用静态库生成的可执行文件不再依赖静态库,
- 使用动态库生成的可执行文件,在执行时依赖动态库。
- 使用动态库生成的可执行文件,执行时,依赖的动态库由系统管理,不需用户的干预。由系统直接加载依赖的动态库。
将动态库加载到内存执行的叫做加载器, 加载器中包含一个动态连接器。
动态连接器是一个软件。 向外提供了服务接口。
用户可以调用动态连接器的接口,按需加载。
动态加载
动态连接器给用户提供了什么服务? 服务的接口是什么?
dlopen(3) dlcolse(3) dlerror(3) dlsym(3)
#include <dlfcn.h>
void *dlopen(const char *filename, int flags); 功能: 参数:filename 动态库的路径名字 flags : RTLD_LAZY 懒绑定 RTLD_NOW 立即加载 返回值: 返回一个地址 成功: 非NULL 失败 : NULL 可以使用dlerror(3) 来获取函数失败的错误诊断信息 void *p void* 表示返回一个不访问的地址 char *q char* 表示返回一个地址,这个地址中放了一个char 类型的数据 int dlclose(void *handle); 如果引用计数减到0,则将共享库卸载 参数 : handle 指定了要操作的共享库的地址
char *dlerror(void);
返回值:
返回描述错误的字符串
Link with -ldl.void *dlsym(void *handle, const char *symbol);
功能 获取指定的符号加载到内存的地址
参数
handle dlopen 打开共享库文件的返回值
symbol (函数的名称)
返回值
符号的地址
code :
#include <stdio.h>
#include <dlfcn.h>
typedef int (*f_t)(int, int);
int main(int argc, char * argv[])
{
void *handle = dlopen(argv[1],RTLD_NOW);
if (NULL == handle)
{
printf("dlopen error ....\n");
printf("%s \n",dlerror());
return -1;
}
printf("dlopen success ...\n");
f_t f = (f_t)dlsym(handle, "sub");
if (NULL == f)
printf("dlsym error : %s\n",dlerror());
printf("sub(3-2)= %d\n",f(3,2));
dlclose(handle);
return 0;
}
库文件源码:
> #include "lib/t_math.h"
>
> int sub (int a, int b) { return (a-b); }
>
> int mul (int a, int b) { return (a*b); }
ldd dynamic
linux-vdso.so.1 => (0x00007ffd2dbc7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f78a1c20000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f78a1856000)
/lib64/ld-linux-x86-64.so.2 (0x00007f78a1e24000)
可以发现 编译出来的 dynamic 链接的库文件中有
libdl.so.2 这个就是加载器的库文件 通过这个库 可以动态加载动态库
nm dynamic
U dlclose@@GLIBC_2.2.5
U dlerror@@GLIBC_2.2.5
U dlopen@@GLIBC_2.2.5
U dlsym@@GLIBC_2.2.5
其中没有 sub 的符号,但是有动态连接器的函数符号,通过这些函数,动态加载libt_math.so