一、从动态库的编译说起
下边通过一个反例来介绍怎样生成一个动态库。
这儿有一个头文件:so_test.h,
三个.c文件:test_a.c、test_b.c、test_c.c,
我们将这几个文件编译成一个动态库:libtest.so。
将这几个文件编译成一个动态库:libtest.so
关于gcc编译的这几个参数前面会再说明的。
二、动态链接库的使用
在前面的中学,我们早已成功生成了一个自己的动态链接库libtest.so,下边我们通过一个程序来调用这个库里的函数。程序的源文件为:test.c。
将test.c与动态库libtest.so链接生成执行文件test:
如今生成了一个可执行文件test,这么这个可执行文件究竟有没有成功链接到动态链接库呢?我么可以使用下边的命令来查看:
测试是否动态联接,假如列举libtest.so,这么应当是联接正常了
执行test,可以看见它是怎样调用动态库中的函数的。
关于ldd命令前面也会有所总结,这是一个专门查看应用程序中使用了哪一些动态链接库的程序。
三、GCC编译参数解析
3.1动态编译
最主要的是GCC命令行的一个选项:
(1)-shared。该选项指定gcc编译器生成动态联接库,而不是可执行文件
(2)-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方法来满足不同进程的须要,而不能达到真正代码段共享的目的。正是使用这个,促使动态链接库不用再编译时拷贝库函数的完整代码,实现真正的动态链接。
(3)-L:指定编译的时侯动态链接库的位置,这儿使用-L.旁边跟了一个点表示要联接的库在当前目录中
(4)-ltest:编译器查找动态联接库时有蕴涵的命名规则,即在给出的名子后面加上lib,前面加上.so来确定库的名称
另外:
(1)LD_LIBRARY_PATH:这个环境变量指示动态联接器可以装载动态库的路径。
(2)其实假如有root权限的话,可以更改/etc/ld.so.conf文件,之后调用/sbin/ldconfig来达到同样的目的,不过若果没有root权限,这么只能采用输出LD_LIBRARY_PATH的方式了。
3.2静态编译
注意,gcc会在静态库名前加上前缀lib,之后追加扩充名.a得到的静态库文件名来查找静态库文件,因而,我们在写须要联接的库时,只写名子就可以,如libmyhello.a的库,只写:-lmyhello
-static代表使用静态链接库,-L.代表静态链接库搜索路径.代表当前路径
3.3动态编译可能存在的问题
使用如下命令进行编译,使用libmyhello.so动态链接库编译成一个hello的可执行文件
生成hello可执行文件,注意执行的时侯可能会报错,说找不到这个
libmyhello.so文件,假如置于/lib或则/usr/lib下,这么默认才能找到,假如置于其他目录下,须要编辑/etc/ld.so.conf文件,加入库文件所在目录的路径,之后运行ldconfig目录名子,该命令会重建/etc/ld.so.cache文件即可。
注意:关于哪些是/etc/ld.so.conf、/etc/ld.so.conf.d、/etc/ld.so.cache、什么是ldconfig?前面会介绍
四、Linux下静态库,动态库,以及arm平台下库的基本概念
4.1、什么是库
在windows平台和Linux平台下都大量存在着库。
本质上来说库是一种可执行代码的二补码方式,可以被操作系统载入显存执行。
因为windows和linux的平台不同(主要是编译器、汇编器和联接器的不同),因而两者库的二补码是不兼容的。
本文仅限于介绍linux下的库。
4.2、库的种类
linux下的库有两种:静态库和共享库(动态库)。
两者的不同点在于代码被载入的时刻不同。
(1)静态库的代码在编译过程中早已被载入可执行程序,因而容积较大。
静态用.a为后缀,比如:libhello.a
(2)共享库(动态库)的代码是在可执行程序运行时才载入显存的,在编译过程中仅简单的引用,因而代码容积较小。
动态一般用.so为后缀,比如:libhello.so
共享库(动态库)的益处是,不同的应用程序假如调用相同的库,这么在显存里只须要有一份该共享库的实例。
为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,比如:libhello.so.1.0,因为程序联接默认以.so为文件后缀名。所以为了使用这种库,一般使用构建符号联接的形式。
ln-slibhello.so.1libhello.so
4.3、静态库,动态库文件在linux下是怎样生成的
以下边的代码为例linux系统编程,生成后边用到的hello库:
首先用gcc编绎该文件,在编绎时可以使用任何合法的编绎参数,比如-g加入调试代码等:
(1)生成静态库生成静态库使用ar工具,虽然ar是archive的意思
(2)生成动态库用gcc来完成,因为可能存在多个版本,因而一般指定版本号:
4.4、库文件是怎样命名的,有没有哪些规范:
在linux下,库文件通常置于/usr/lib和/lib下,
注意:
在静态库和动态库中linux ldd 命令,Linux有自己的命名约定,我们在使用的时侯可以使用全名,也可以使用简单简写名,即
所以假如是一个程序中须要同时链接到同名称的静态库和动态库如何办呢?
当一个库同时存在静态库和动态库时,例如libmysqlclient.a和libmysqlclient.so同时存在时:
在Linux下,动态库和静态库朋友存在时,gcc/g++的链接程序,默认链接的动态库。
可以使用下边的方式,给联接器传递参数,看是否链接动态库还是静态库。
使用:
使用:
假如要完全静态加在,使用-static参数,正式所有的库以静态的形式链入可执行程序,这样生成的可执行程序linux ldd 命令,不再依赖任何库,同学出现的问题是,这样编译下来的程序十分大,占用空间。
1.5、可执行程序在执行的时侯怎么定位静态库与共享库(动态库)文件:
当系统加载可执行代码(即库文件)的时侯,才能晓得其所依赖的库的名子,而且还须要晓得绝对路径,此时就须要系统动态载入器(dynamiclinker/loader),通常有如下的搜索次序
(1)静态库链接时搜索路径的次序:
(2)动态链接时、执行时搜索路径次序:
五、一些常用的可执行程序工具
(1)ldd工具
使用ldd工具,查看可执行程序依赖这些动态库或着动态库依赖于这些动态库:
ldd命令可以查看一个可执行程序依赖的共享库,
比如
(2)nm工具
使用nm工具,查看静态库和动态库中有这些函数名(T类表示函数是当前库中定义的,U类表示函数是被调用的,在其它库中定义的,W类是当前库中定义,被其它库中的函数覆盖)。:
有时侯可能须要查看一个库中究竟有什么函数,nm工具可以复印领料中的涉及到的所有符号,这儿的库既可以是静态的也可以是动态的。
nm列举的符号有好多,常见的有三种:
比如,假定开发者希望晓得上文提及的hello库中是否引用了printf():
发觉printf是U类符号,说明printf被引用,然而并没有在库中定义。
由此可以推测,要正常使用hello库,必须有其它库支持,使用ldd工具查看hello依赖于什么库:
从前面的结果可以继续查看printf最终在那里被定义。
(3)ar工具
使用ar工具,可以生成静态库,同时可以查看静态库中包含这些.o文件linux开源软件,即有这些源文件构成。
可以使用ar-tlibname.a来查看一个静态库由这些.o文件构成。
可以使用arqlibname.axxx1.oxxx2.oxxx3.o…xxxn.o生成静态库
静态库的后缀是.a,它的形成分两步
(4)ld工具
ld命令是二补码工具集GNUBinutils的一员,是GNU链接器,用于将目标文件(.o)与库链接为可执行文件或库文件