库文件
什么是库文件
库文件本质上是经过编译后生成的可被计算机执行的二进制代码。但注意库文件不能独立运行,库文件需要加载到内存中才能执行。库文件大量存在于Windows,Linux,MacOS等软件平台上。
库文件的分类
- 静态库
- Windows:xxx.lib
- Linux:libxxx.a
- 动态库(共享库)
- Windows:xxx.dlll
- Linux:libxxxx.so.major.minor(libmy.so.1.1)
注意:不同的软件平台因编译、链接器的不同,所生成的库文件是不兼容的。
静态库与动态库的区别
- 静态库链接时,将库中所有内容包含到最终的可执行程序中。
动态库链接时,将库中的符号信息包含到最终可执行文件中,在程序运行时,才将动态库中符号的具体实现加载到内存中。
静态库与动态库的优缺点
- 静态库
- 优点:生成的可执行程序不再依赖静态文件
- 缺点:可执行程序体积较大
- 动态库
- 优点:生成的可执行程序体积小;动态库可被多个应用程序共享
- 缺点:可执行程序运行依然依赖动态库文件
静态库与动态库对比
库文件创建
Linux系统下库文件命名规范:libxxxx.a(静态库) libxxxx.so(动态库)
静态库文件的生成
- 将需要生成库文件对应的源文件( *.c )通过编译(不链接)生成 *.o 目标文件
- 用
ar
命令将生成的*.o
打包生成libxxxx.a
库的生成:
库的使用 :
动态库文件的生成
- 利用源文件(
*.c
)通过编译(不链接)生成位置无关*.o
目标文件 - 将目标文件链接为
*.so
文件
库的生成:
库的使用:
注意:如果在代码编译过程或者运行中链接了库文件,系统会到 /lib
和 /usr/lib
目录下查找库文件,所以建议直接将库文件放在 /lib
或者/usr/lib
,否则系统可能无法找到库文件,造成编译或者运行错误 。
扩展内容
查看应用程序(例如:app)依赖的动态库
动态库使用方式:
编译时链接动态库,运行时系统自动加载动态库
程序运行时,手动加载动态库
实现:
涉及内容
- 头文件:#include <dlfcn.h>
- 接口函数:dlopen、dlclose、dlsym
- 依赖库:-ldl
- 句柄handler:资源的标识
示例代码
#include <stdio.h> #include <dlfcn.h> int main(int argc,char *argv[]) { // 1. 加载动态库 "/lib/libdlfun.so" // - RTLD_LAZY: 延迟绑定(使用时才解析符号,提高加载速度) // - 返回 handler 是动态库的句柄,失败时返回 NULL void* handler = dlopen("/lib/libdlfun.so", RTLD_LAZY); if (handler == NULL) { // 打印错误信息(dlerror() 返回最后一次 dl 相关错误的字符串) fprintf(stderr, "dlopen 失败: %s\n", dlerror()); return -1; } // 2. 从动态库中查找符号 "sum"(函数名) // - dlsym 返回 void*,需强制转换为函数指针类型 int sum(int*arr, int size); // - 这里假设 "sum" 是一个接受两个int*,int参数、返回 int 的函数 int (*paddr)(int*, int) = (int (*)(int*, int))dlsym(handler,"sum"); if (paddr == NULL) { fprintf(stderr, "dlsym 失败: %s\n", dlerror()); dlclose(handler); // 关闭动态库(释放资源) return -1; } // 3. 调用动态库中的函数 "sum",计算{11,12,13,14,15}的累加和 int arr[5] = {11,12,13,14,15}; printf("sum=%d\n", paddr(arr, sizeof(arr)/sizeof(arr[0]))); // 4. 关闭动态库(释放内存和资源) dlclose(handler); return 0; }
编译命令
gcc demo06.c -ldl