三、库文件
单一模型:将程序中所有功能全部实现于一个单一的源文件内部。编译时间长,不易于维护和升级,不易于协作开发。分离模型:将程序中的不同功能模块划分到不同的源文件中。缩短编译时间,易于维护和升级,易于协作开发。1.静态库静态库的本质就是将多个目标文件打包成一个文件。链接静态库就是将库中被调用的代码复制到调用模块中。使用静态库的程序通常会占用较大的空间,库中代码一旦修改,所有使用该库的程序必须重新链接。使用
单一模型:将程序中所有功能全部实现于一个单一的源文件内部。编译时间长,不易于维护和升级,不易于协作开发。
分离模型:将程序中的不同功能模块划分到不同的源文件中。缩短编译时间,易于维护和升级,易于协作开发。
1.静态库
静态库的本质就是将多个目标文件打包成一个文件。
链接静态库就是将库中被调用的代码复制到调用模块中。
使用静态库的程序通常会占用较大的空间,库中代码一旦修改,所有使用该库的程序必须重新链接。
使用静态库的程序在运行无需依赖库,其执行效率高。
静态库的形式:libxxx.a构建静态库的终端命令:ar -r libxxx.a x.o y.o z.o
使用静态库:
gcc … -lxxx -L <库路径>
或者终端命令export LIBRARY_PATH=<库路径>,此时在此终端下可缺省编译
或者在.bashrc文件下export LIBRARY_PATH=<库路径>,此时在此环境下可缺省编译
2.动态(共享)库
动态库和静态库最大的不同就是,链接动态库并不需要将库中被调用的代码复制到调用模块中,相反被嵌入到调用模块中的仅仅是被调用代码在动态库中的相对地址。
如果动态库中的代码同时为多个进程所用,动态库的实例在整个内存空间中仅需一份,因此动态库也叫共享库或共享对象(Shared Object,so)。
使用动态库的模块所占空间较小,即使修改了库中的代码,只要接口保持不变,无需重新链接。
使用动态库的代码在运行时需要依赖库,执行效率略低。
动态库的形式:libxxx.so构建动态库:
gcc -c -fpic xxx.c -> xxx.o生成位置无关码,库内部的函数调用也用相对地址表示
gcc -shared -o libxxx.so x.o y.o z.o开始构建使用动态库:
gcc … -lxxx -L<库路径>
或者终端命令export LIBRARY_PATH=<库路径>,此时在此终端下可缺省编译
gcc … -lxxx 运行时所调用的动态库必须位于LD_LIBRARY_PATH环境变量所表示的路径中。
gcc缺省链接共享库,可通过-static选项强制链接静态库。
动态库的搜索路径搜索的先后顺序是:
1.编译目标代码时指定的动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4.默认的动态库搜索路径/lib /usr/lib。
3.动态加载动态库
有时候库内函数不知道能不能用,可以自己通过动态加载动态库的方式查看函数地址是否可获取得到
#include <dlfcn.h> 系统提供的针对动态
gcc -ldl -o xxx xxx.c 库的动态加载函数集void* dlopen(const char* filename, int flag):
成功返回动态库的句柄,失败返回NULL。
filename - 动态库路径,若只给文件名,则根据LD_LIBRARY_PATH环境变量搜索动态库
flag - 加载方式,可取以下值:
RTLD_LAZY - 延迟加载,使用动态中的符号时才加载
RTLD_NOW - 立即加载
该函数所返回的动态库句柄唯一地标识了系统内核所维护的动态库对象,将作为后续函数调用的参数。void* dlsym(void* handle, const char* symbol);
成功返回函数地址,失败返回NULL。
handle - 动态库句柄
symbol - 符号(函数或全局变量)名 该函数所返回的函数指针是void*类型,需要强制类型转换为实际的函数指针类型才能调用。int dlclose(void* handle):
成功返回0,失败返回非零。
handle - 动态库句柄。char* dlerror(void):
之前若有错误发生则返回错误信息字符串,否则返回NULL。*/ #include <stdio.h> #include <dlfcn.h> int main(void) { // 动态加载动态库libmath.so void* handle = dlopen("shared/libmath.so", RTLD_NOW); if (! handle) { fprintf(stderr, "dlopen: %s\n", dlerror()); return -1; } // 从动态库中获取add函数的入口地址 int (*add)(int, int) = (int (*)(int, int))dlsym(handle, "add"); if (! add) { fprintf(stderr, "dlsym: %s\n", dlerror()); return -1; } // 从动态库中获取sub函数的入口地址 int (*sub)(int, int) = (int (*)(int, int))dlsym(handle, "sub"); if (! sub) { fprintf(stderr, "dlsym: %s\n", dlerror()); return -1; } // 从动态库中获取show函数的入口地址 void (*show)(int, char, int, int) = (void (*)(int, char, int, int))dlsym( handle, "show"); if (! show) { fprintf(stderr, "dlsym: %s\n", dlerror()); return -1; } int a = 30, b = 20; show(a, '+', b, add(a, b)); show(a, '-', b, sub(a, b)); if (dlclose(handle)) { fprintf(stderr, "dlclose: %s\n", dlerror()); return -1; } return 0; }
更多推荐
所有评论(0)