【嵌入式学习笔记-02】什么是库文件,静态库的制作和使用,动态库的制作和使用,动态库的动态加载
静态库的本质就是将多个目标文件打包成一个文件
链接静态库的过程就是将库中被调用的代码复制到调用模块中
静态库的拓展名是 .a 例: libxxx.a
以构建数学库为例,静态库的构建顺序如下:
1、编辑库的实现代码和接口声明:
计算模块:calc.h、calc.c
显示模块:show.h、show.c
接口文件:math.h
2、编译成目标文件
gcc -c calc.c
gcc -c show.c
3、打包成静态库
ar -r libmath.a calc.o show.o
ar 命令
ar[选项] <静态库文件> <目标文件列表>
编辑库的使用代码
编译并链接静态库
直接链接静态库
gcc main.c libmath.a
用-l指定库名,用-L指定库路径
gcc mian.c -lmath -L.
用-l指定库名,用LIBRARY PATH环境变量指定库路径
export LIBRARY PATH=$LIBRARY_PATH:
gcc main.c -lmath
以构建数学库为例,动态库的构建顺序如下:
gcc -c -fpic calc.c
gcc -c -fpic show.c
gcc -shared calc.o show.o -o libmath.so
编译链接也可以合并成一步完成。
gcc -shared -fpic calc.c show.c -o libmath.so
PIC(Position Independent Code,位置无关代码)。
-fPIC:大模式,生成代码比较大,运行速度比较慢,所有平台都支持
-fpic:小模式,生成代码比较小,运行速度比较快,仅部分平台支持
编辑库的使用代码
编译并链接动态库
直接链接动态库
`gcc main.c libmath.so
用-l指定库名,用-L指定库路径
gcc mian.c -lmath -L.
用-l指定库名,用LIBRARY PATH环境变量指定库路径
运行时需要保证LD LIBRARY PATH环境变量中包含共享库所在的路径用以告知链接器在运行时链接动态。
在可执行程序的链接阶段,并不将所调用函数的二进制代码复制到可执行程序中,而只是将该函数在共享库中的地址嵌入到调用模块中,因此运行时需要依赖共享库。
在程序执行的过程中,开发人员可以动态加载共享库 (什么时候用什么时候加载),这样可以提高内存的利用效率。
在程序中动态加载共享库需要调用一组特殊的函数,它们被声明于一个专门的头文件中,并在一个独立的库中予以实现。
使用这组函数需要包含此头文件,并链接该库
void* dlopen(char const* filename, int flag)
功能:将共享库载入内存并获得其访问句柄
参数:
filename 动态库路径,若只给文件名不带目录,则根据LD LIBRARY PATH环境变量的值搜索动态库
flag 加载方式,可取以下值
RTLD LAZY - 延迟加载,使用动态库中的符号时才真的加载进内存。
? RTLD NOW - 立即加载。
返回值: 成功返回动态库的访问句柄,失败返回NULL。
句柄: 句柄唯一地标识了系统内核所维护的共享库对象,将作为后续函数调用的参数
void* dlsym(void* handle, char const* symbol);
功能:从已被加载的动态库中获取特定名称的符号地址
参数: handle 动态库访问句柄
? symbol 符号名
返回值: 成功返回给定符号的地址,失败返回NULL。
该函数所返回的指针为void*类型,需要造型为与实际目标类型相一致的指针,才能使用。
int dlclose(void* handle)
char* dlerror(void)
辅助工具
查看符号表: nm
查看依赖: ldd
加载、使用和卸载共享库过程中所发生的错误
返回值: 有错误则返回指向错误信息字符串的指针,否则返回NULL。
辅助工具
查看符号表: nm
查看依赖: ldd