3. Linux库使用说明
3.1. 生成静态库
生成静态库使用ar工具,其实ar是archive的意思
$ar -cr libhello.a hello.o # 生成一个名字为libhello.a的静态库
3.2. 生成动态库
用gcc来完成,由于可能存在多个版本,因此通常指定版本号:
$gcc -shared -fpic -o libhello.so.1.0 hello.o # 生成一个主版本号为1.0名字为libhello.so的一个动态库
3.3. 库文件命名规范
在 linux 下,库文件一般放在/usr/lib和/lib下,
静态库的名字一般为
libxxxx.a,其中 xxxx 是该lib的名称;动态库的名字一般为
libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号
3.4. 库搜索路径
动态库:
编译链接时:
-L、-rpath和-rpath-link指定库搜索路径;环境变量
LD_LIBRARY_PATH指定的库搜索路径;默认的动态库搜索路径
/lib;默认的动态库搜索路径
/usr/lib。
运行时:
-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中);环境变量
LD_LIBRARY_PATH指定的动态库搜索路径;/etc/ld.so.conf中所缓存的动态库路径;默认的动态库搜索路径
/lib;默认的动态库搜索路径
/usr/lib。
静态库:
编译链接时:
-L指定库的搜索路径;
环境变量
LIBRARY_PATH, 指定的动态库搜索路径;默认的动态库搜索路径
/lib默认的动态库搜索路径
/usr/lib。
运行时:不存在,因为可执行程序已经把.a文件打包到可执行程序中。
3.5. 常用的命令
3.5.1. -Wl、-rpath、-I、-L、-l命令
CFLAGS = -g \
-I$(CURDIR) \ # -I:指定头文件路径
LIBS := -L/$(CURDIR)/lib \ # -L:指定编译时候库搜索路径
-lpthread \ # -l:指定编译时候库名字
-Wl,-rpath=/home/xym/Demo/lib \ #-Wl,-rpath :同时指定动态库编译和运行时的路径
3.5.2. 修改库环境变量LD_LIBRARY_PATH和LIBRARY_PATH
动态库:LD_LIBRARY_PATH
静态库:LIBRARY_PATH
export LD_LIBRARY_PATH =$LIBRARY_PATH:/home/xym/Demo/lib
如果有多个路径需要添加:中间用:隔开
export LD_LIBRARY_PATH=/home/book/Demo/arm/sqlite/lib:/home/book/nfs_rootfs/lib:$LD_LIBRARY_PATH
注意:
在终端执行,会临时生效,关闭终端后就失效了;
如果一直生效,可以在
~/.bashrc文件的最后追加这段代码,执行source ~/.bashrc立即生效即可。
3.5.3. 修改/etc/ld.so.conf中所缓存的动态库路径
sudo vim /etc/ld.so.conf #末尾添加自己的库搜索路径
sudo ldconfig #配置生效
注意:在嵌入式Linux系统的实际应用中,使用的比较少, 因为有很多系统根本就不支持ld.so.conf。并且该配置只在程序运行时有效。
3.5.4. ldd命令
查看可执行程序依赖那些动态库或着动态库依赖于那些动态库例如 :
xym@pc:~/scons_demo/build/bin$ ldd Demo
linux-vdso.so.1 (0x00007ffd2c31a000)
libmathfuns.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7a04a3d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7a05030000)
可以看到 应用程序Demo命令依赖于linux-vdso.so.1、 libmathfuns.so库和libc.so.6 ld-linux-x86-64.so.2 库 ,这里很明显可以看到libmathfuns.so => not found 这个库有问题,那么我么就可以find命令找到这个库,然后采用上刚章节来添加该库的搜索路径来解决这个问题,例如:

此时再次用ldd命令查看,可以看到libmathfuns.so => /home/xym/scons_demo/build/lib/libmathfuns.so已经链接成功
xym@pc:~/scons_demo/build/bin$ ldd Demo
linux-vdso.so.1 (0x00007fffecffc000)
libmathfuns.so => /home/xym/scons_demo/build/lib/libmathfuns.so (0x00007f5a3b24c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a3ae5b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5a3b650000)
xym@pc:~/scons_demo/build/bin$
3.5.5. nm命令
查看静态库和动态库中有那些函数名
T类:表示函数是当前库中定义的;
U类:表示函数是被调用的,在其它库中定义的;
W类:是当前库中定义,被其它库中的函数覆盖,即“弱态”符号。
例如,假设开发者希望知道上文提到的libmathfuns.so库中是否引用了 puts():
$ nm libmathfuns.so | grep puts
U puts@@GLIBC_2.2.5
发现puts是U类符号,说明puts被引用,但是并没有在库中定义。
由此可以推断,要正常使用libmathfuns.so库,必须有其它库支持,使用ldd工具查看libmathfuns.so依赖于哪些库即可。然后找到库,并添加到搜索路径。
xym@pc:~/scons_demo/build/lib$ ldd libmathfuns.so
linux-vdso.so.1 (0x00007fffb11ff000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4615561000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4615b54000)
xym@pc:~/scons_demo/build/lib$
3.5.6. ar命令
可以生成静态库,同时可以查看静态库中包含那些.o文件,即有那些源文件构成
xym@pc:~/scons_demo/build/lib$ ar -t libmathfuns.a
mathfuns.o
#可以看出库libmathfuns.a是有mathfuns.o文件组成的
3.6. Linux程序设计关于库的使用细节
3.6.1. gcc/g++命令中关于库的参数
-shared: 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件;-fPIC:表示编译为位置独立(地址无关)的代码,不用此选项的话,编译后的代码是位置相关的,所以动态载入时,是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的;-L:指定链接库的路径,-L. 表示要连接的库在当前目录中;-lmathfuns:指定链接库的名称为mathfuns,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称;LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。 当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用/sbin/ldconfig来达到同样的目的;不过如果没有root权限,那么只能采用修改LD_LIBRARY_PATH环境变量的方法了。
**注:**调用动态库的时候,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH指定动态库的目录。通常这样做就可以解决库无法链接的问题了。
3.6.2. 静态库和动态库同时存在的问题
当一个库同时存在静态库和动态库时,比如libmathfuns.a和libmathfuns.so同时存在时:在Linux下,gcc/g++的链接程序,默认链接的动态库。可以使用下面的方法,给连接器传递参数,指定链接动态库还是静态库。
gcc/g++ test.c -o test -WI,-Bstatic -lmathfuns #指定连接静态库
gcc/g++ test.c -o test -WI,-Bdynamic -lmathfuns #指定连接动态库
如果要完全静态加载,使用-static参数,即将所有的库以静态的方式链入可执行程序,这样生成的可执行程序,不再依赖任何库,同时出现的问题是,这样编译出来的程序非常大,占用空间。
3.6.3. 动态库热升级问题
在动态链接库热升级时,不能直接使用cp newlib.so oldlib.so,这样有可能会使程序core掉;
而应该使用:
rm oldlib.so
cp newlib.so oldlib.so
或者
mv oldlib.so oldlib.so_bak
cp newlib.so oldlib.so