最近着手学习Linux的基本命令和操作,刚刚接触库文件,先来说两句。
一、概念
1. 库文件
库是一组预先编译好的函数集合,实现了程序上共享代码的功能,通常由一组相关关联的函数组成。
标准库文件一般存储在/lib和/usr/lib目录中,默认情况下,代码编译时的依赖只搜索标准库。
2. 库文件的分类
库文件的名字总以lib开头,随后的部分来指明库的名称,最后以.开始,然后分为如下的两种类型:
① .a:静态函数库。类似于windows下的 .lib文件。
② .so:共享函数库(shared object)。类似于windows下的 .dll文件。
3. 库文件的调用
通常函数库同时以静态库和共享库两种合适存在,可以使用ls命令查看。
①默认调用:
$ gcc test.c -o test -lm
这种情况下调用的是libm.a函数库,表示调用的是标准库目录下的函数库。
②当然,大部分情况下,我们自己编写代码的时候,会生成函数库,调用方式如下:
$ gcc test.c -o test /usr/lib/libm.a
或者通过gcc的-L选项来指定编译器增加库的搜索路径如下:
$ gcc test.c -o test -L /usr/test/lib -ltest
二、库文件的创建
当程序需要使用库函数中的某个函数时,必须包含一个声明该函数的头文件,然后使用-L选项来指明除标准库之外需要添加的库。
1. 静态库
也称归档文件(archinve),一般它们的文件名都以 .a结尾。命名规则为:lib*.a.*,第一个“*”为库的real name, 第二个“*”为库的主版本号和一个发行版本号(可选)。如果某个静态链接库不符合次合适,则Linux的链接库自动装入程序并搜不到此链接库,其他程序也无法共享。
(1)静态库的创建和维护
①库文件的创建
$ ar crv libtest.a test1.o test2.o test3.o
如果libtest.a库不存在,则创建新的文件并将所有的函数模块添加进去;若该库已经存在,则在不检查相同函数模块的情况下添加入新的函数模块。
②查看库文件的函数模块
$ ar -t libtest.a
列出库文件中所有的函数模块成员。
③删除库文件中的函数模块
$ ar -dv libtest.a test3.o
④提取库文件中的函数模块
$ ar -xv libtest.a test1.o
将函数模块test1.o释放到当前文件夹下,不会删除库文件中的该模块。
⑤在函数模块后面插入新成员
$ ar -ra test2.o libtest.a test1.o
将函数模块test2.o插入到库文件libtest.a中的test1.o后面。
⑥更新库中函数模块
$ ar -ru libtest.a test1.o
如果libtest.a库中没有test1.o模块,则将其添加到库的末尾,如果有的话就将之替换掉。
(2)静态库使用
①库文件内容表的生成
在有些系统中,要想成功的使用函数库,还需要为库函数生成一个内容表。通过ranlib命令来完成这一工作。
$ ranlib libtest.a
②库文件的使用
$ gcc test.c -o test -L . -ltest
表示使用当前路径下的libtest.a库文件。如需要查看哪些函数被包含在目标文件,函数库或可执行文件中,可以通过nm命令。
2. 共享库
静态库额一个缺点,当同时运行许多应用程序并且它们都是用来自同一个函数库的函数时,内存中都会有同一函数的多份副本而消耗内存空间。而共享库是在当编译好的程序被加载到内存中执行时,函数引用被解析并产生对共享库的调用,也就是在有必要时才调用共享库,并且共享库函数模块可以被多个函数同时调用。
①简单说明
通常是个elf格式的文件;应用程序在执行时加载动态库,一个动态库可以被多个应用程序共享(所以叫共享库);
②编译生成
$ gcc ***.c -fPIC -shared -o lib***.so
其中,-fPIC表示编译为位置独立的代码,-shared表示指定生成动态链接库。
③使用
假设编译了一个libtest.so,在使用动态连接库时要-ltest来使用。
linux系统默认的动态库路径: shell环境变量LD_LIBRARY_PATH。可以通过export LD_LIBRARY_PATH来修改路径。如果有root权限的话,可以直接修改/etc/ld.so.conf文件,然后ldconfig来实现。
链接了动态库编译生成的二进制文件,可以通过ldd命令来查看对动态库的依赖。
注意:编译函数以产生包含在库文件中的目标文件可以通过gcc的-c选项来完成,该选项会阻止编译器创建一个完成的程序。此时如果试图创建一个完整的程序将不会成功,因为可能没有定义main函数。