UNIX/Linux学习笔记(3)函数库
引言:小编又回来啦,这次让我来说一说我对静态库与共享库的肤浅认知
库文件
1)我们可以将库看成目标文件的集合,将不需要升级、更新、维护的代码打包合并在一起可以方便使用,同时起到了对源代码保密的效果(因为库文件以二进制形式提供给用户)
2)库文件通过头文件向外导出接口。用户通过头文件找到库文件中的函数声明,库文件则实现函
数的定义
3)举个栗子:printf
函数,在stdio.h
这个头文件中,我们所能看到的只有函数的声明
4)因此,我们在执行一个程序前需要链接,目的便是使我们的程序能找到对应的函数定义并将其内容链接到相应的代码段中
小编在初学时,总觉得这和我在一个文件夹下写一个
.h
和对应的一个.c
,再用make
命令执行一下没什么区别。后来发现是自己钻牛角尖了,因为库文件的目的是保密+打包以起到方便的作用
静态库(.a)
1)静态库在使用时是把被调用的代码复制到调用模块中,因此在执行程序时便不需要静态库了
2)优点:执行速度快(因为是代码内容的直接复制)
缺点:占用空间大,不能轻易修改库中的内容(库中内容变化需要重新编译出新程序)
3)创建静态库
1、编写源代码:vi mysta.h
vi mysta.c
2、生成目标文件:gcc -c mysta.c
→ 链接是将多个目标文件合并成一个可执行文件
3、打包生成静态库:ar -r libxxx.a mysta.o xxx.o xxx.o
ar命令
的参数:
ar -r
:把目标文件添加到静态库libxxx中,目标文件已存在则更新
ar -q
:把目标文件追加到静态库的末尾
ar -d
:从静态库中删除指定的目标文件
ar -t
:显示静态库中有哪些目标文件
ar -x
:将静态库拆分,即生成静态库所包含的所有目标文件
4)调用静态库
1、直接调用:
要求调用者和库在同一路径下
gcc test.c libxxx.a
2、设置库的环境变量
进入配置文件vi ~/.bashrc
文件末尾添加配置内容export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径
重新配置文件source ~/.bashrc
生成可执行文件gcc test.c -I头文件路径 -l库简称
3、设置命令行参数
gcc test.c -I头文件路径 -L库路径 -l库的简称
库的简称是有标准格式的,库名一般都是以
lib
字符串开头,如libmymath.a
libmymath.so
,把库文件名的lib
和.a
.so
去掉就是这个库的简称了
共享库(.so)
1)共享库在使用时只是在调用模块中嵌入所调用代码在库中的相对位置地址,在程序执行时,共享库需要和程序一同加载到内存中,当执行到调用库中的代码时跳转到共享库,执行该函数完毕后跳转回来
2)优点:占用空间小,方便更新(库中内容变化,不需要重新编译出新程序)
缺点:相对静态库执行效率略低,因为函数调用时通过跳转实现的
3)创建共享库
1、编写源代码:vi myso.h
vi myso.c
2、生成位置无关目标文件:gcc -c -fpic myso.c
→ 不影响内存中的代码段
3、链接生成共享库:gcc -shared myso.o xxx.o xxx.o -o libxxx.so
注意:共享库所生成的目标文件是位置无关性的,并且链接时与静态库也大不相同
4)调用共享库
静态库和共享库的本质区别在于前者是代码的复制,后者是代码的指向。因此在使用共享库时,需要共享库同时被加载。这就像你的朋友邀请你去他家玩耍,给了你地址后却死不开门。程序若要跳转到该代码地址的前提是该代码也与你同时被加载了。
操作系统会根据环境变量
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库文件的路径
的设置来加载共享库文件,若不加载该环境变量,则./a.out
无法成功执行
1、直接调用:
要求调用者和库在同一路径下
gcc test.c libxxx.so
2、设置库的环境变量
进入配置文件vi ~/.bashrc
文件末尾添加配置内容export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径
重新配置文件source ~/.bashrc
生成可执行文件gcc test.c -I头文件路径 -l库简称
3、设置命令行参数
gcc test.c -I头文件路径 -L库路径 -l库的简称
注意:当静态库和动态库的库简称相同时,优先调用动态库
总结
以上是小编对共享库与静态库的整理,其实还有动态加载共享库的四个函数,但是小编想了想这四个函数还是大家自己亲自去试验一下更好,小编在最后列出给大家
void *dlopen(const char* filename, int flag);
void* dlsym(void* handle, const char *symbol);
int dlclose(void* handle);
char* dlerror(void);
共勉!