10.函数库-静态库和共享库
函数库是指由若干目标文件按某种格式构成的集合,它分为两种类型:静态库和共享库。应用程序在链接静态库时是将所需的静态库函数嵌入至可执行文件中(并非全部静态库),而在链接共享库时它仅在可执行文件中保存加载目标对象所需的信息,真正调用时才将目标对象加载至内存。
1. 静态库由ar工具创建和更新,库文件命名规则为libxxx.a,以lib开头,.a作为文件名后缀。以ANSI C为例,它定义了一组广泛的标准I/O、字符串操作等如atoi、printf、strcpy等,存在libc.a库中,浮点函数存在libm.a库中。它的缺点是程序运行时要求有静态库中所需的对象的一份拷贝,不容易维护和更新
2. 共享库在运行时才调用所需的函数库,库文件命名规则为libxxx.so,以lib开头,.so作为文件名后缀。例如调用thread、socket等库,只需要对应添加编译器选项-lthread、-lsocket选项即可(注:始终将-lxxx选项放在编译命令行参数的最右边)。使用ldd命令查看当前可执行文件在运行时所需的共享库。它的优点是每个链接到该共享库的程序都共享它的同一份拷贝(一个.so文件,无需被拷贝或嵌入到可执行文件中,函数库的一个副本可被多个不同的正在运行的进程共享)
3. -fPIC选项编译生成与位置无关代码的共享库,它可在任何地址加载,也可以在运行时被多个进程共享
此外应用程序还可以在运行的任何时刻动态加载共享库,启动时不一定立即加载共享库而是在需要时动态加载共享库。此时共享库称为动态链接库。Linux系统为动态链接库提供了一组API,允许应用程序在运行时加载和链接共享库
#include <dlfcn.h>
void *dlopen(const char *file,int flag) #打开动态链接库,flag参数一般选RTLD_LAZY,表示推迟符号解析到执行库中代码
void *dlsym(void *handle,char *symbol) #打开链接库句柄,取符号的执行地址
int dlclose(void *handle) #关闭共享库
const char *dlerror() #检查动态链接库操作是否失败
利用这些接口我们就可以使用自己开发的动态链接库了,然后再调用共享库里的函数和对象。调用步骤还是比较简单的:打开动态链接库文件,取得调用函数的地址,调用它它们,最后关闭动态链接库。注意编译时的命令行参数-rdynamic和-ldl
gcc -rdynamic xxx.c -o p -ldl #-rdynamic表示解析共享库中的全局符号,-ldl表示链接dl库