转自:https://blog.csdn.net/u010649766/article/details/78528601linux
咱们在编写一个 C 语言程序的时候,常常会遇到好多重复或经常使用的部分,若是每次都从新编写当然是能够的,不过那样会大大下降工做效率,而且影响代码的可读性,更不利于后期的代码维护。咱们能够把他们制做成相应的功能函数,使用时直接调用就会很方便,还能够进行后期的功能升级。程序员
例如我要在一段代码中屡次交换两个变量的值,我能够在代码中屡次写入windows
i=x; x=y; y=i;
不过这样未免有点麻烦咱们能够编写一个change_two_int()函数进行简化。
定义以下函数:函数
void change_two_int( int *a,int *b ) { int c; c=*a; a=b; *b=c; }
这样每次要进行交换时只需调用 change_two_int(&x , &y); 便可,是否方便了许多?优化
那么咱们要讨论的和这些有什么关系呢?库通俗的说就是把这些经常使用函数的目标文件打包在一块儿,提供相应函数的接口,便于程序员使用。库是别人写好的现有的,成熟的,能够复用的代码,咱们只须要知道其接口如何定义,即可以自如使用。spa
共享库=动态库操作系统
现实中每一个程序都要依赖不少基础的底层库,不可能每一个人的代码都从零开始,所以库的存在乎义非同寻常。好比咱们常使用的printf函数,就是 C 标准库提供的函数。咱们在使用时只须要包含相应的头文件就可使用(非静态编译还要有相应的库文件)。而不用关心printf函数具体是如何实现的,这样就大大提升了程序员编写代码的效率。从使用方法上分库大致上能够分为两类:静态库和共享库。在windows中静态库是以 .lib 为后缀的文件,共享库是以 .dll 为后缀的文件。在linux中静态库是以 .a 为后缀的文件,共享库是以 .so为后缀的文件。
以 linux 下的静态库和动态库为例咱们研究一下,首先咱们看一下他们的生成方式:.net
静态库:命令行
首先将源文件编译成目标文件:gcc –c a.c b.c
生成静态库:ar –rc libstatic.a a.o b.ocode
共享库:
同静态库同样编译成目标文件:gcc –c a.c b.c
生成共享库:gcc –fPIC –shared –o libshared.so a.o b.o
因而可知静态库和动态库都是对目标文件的处理,也能够说库文件已是机器码文件了,静态库和共享库的加载过程有很大的区别。
静态库的连接方法:
gcc –o staticcode –L. –lstatic main.c –static (默认库在当前文件夹)
共享库的连接方法:
gcc –o sharedcode -L. –lshared main.c (默认库在当前文件夹)
当程序与静态库链接时,库中目标文件所含的全部将被程序使用的函数的机器码被 copy 到最终的可执行文件中。这就会致使最终生成的可执行代码量相对变多,至关于编译器将代码补充完整了,优势,这样运行起来相对就快些。不过会有个缺点: 占用磁盘和内存空间. 静态库会被添加到和它链接的每一个程序中, 并且这些程序运行时, 都会被加载到内存中. 无形中又多消耗了更多的内存空间。
与共享库链接的可执行文件只包含它须要的函数的引用表,而不是全部的函数代码,只有在程序执行时, 那些须要的函数代码才被拷贝到内存中。优势,这样就使可执行文件比较小, 节省磁盘空间,更进一步,操做系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用,也同时节约了内存。缺点,不过因为运行时要去连接库会花费必定的时间,执行速度相对会慢一些,总的来讲静态库是牺牲了空间效率,换取了时间效率,共享库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体须要了。
另外,一个程序编好后,有时须要作一些修改和优化,若是咱们要修改的恰好是库函数的话,在接口不变的前提下,使用共享库的程序只须要将共享库从新编译就能够了,而使用静态库的程序则须要将静态库从新编译好后,将程序再从新编译一便。这也是使用过程中的差异,以如今的项目举例,在远程更新的时候,若是只是*.so动态库封装内容变化了,那么只须要更新*.so便可。
.dll 动态库
.lib 静态库
库即为源代码的二进制文件
Linux下
.so 动态库
.a 静态库
静态库在程序编译时会被链接到目标代码中,程序运行时将再也不须要该静态库。
动态库在程序编译时并不会被链接到目标代码中,而是在程序运行是才被载入,所以在程序运行时还须要动态库存在。
静态库的后缀是.a,它的产生分两步
Step 1.由源文件编译生成一堆.o,每一个.o里都包含这个编译单元的符号表
Step 2.ar命令将不少.o转换成.a,成文静态库
动态库的后缀是.so,它由gcc加特定参数编译产生。
例如:
gcc−fPIC−c∗.cgcc−fPIC−c∗.c gcc -shared -Wl,-soname, libfoo.so.1 -olibfoo.so.1.0 *.
在linux下,库文件通常放在/usr/lib和/lib下,
静态库的名字通常为libxxxx.a,其中xxxx是该lib的名称
动态库的名字通常为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号
ldd命令能够查看一个可执行程序依赖的共享库,
例如# ldd /bin/lnlibc.so.6
=> /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 => /lib/ld- linux.so.2 (0×40000000)
能够看到ln命令依赖于libc库和ld-linux库
当系统加载可执行代码时候,可以知道其所依赖的库的名字,可是还须要知道绝对路径
此时就须要系统动态载入器(dynamiclinker/loader)
对于elf格式的可执行程序,是由ld-linux.so*来完成的
它前后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib目录
找到库文件后将其载入内存
若是安装在/lib或者/usr/lib下,那么ld默认可以找到,无需其余操做。
若是安装在其余目录,须要将其添加到/etc/ld.so.cache文件中,步骤以下
1.编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
2.运行ldconfig,该命令会重建/etc/ld.so.cache文件
############################################################
linux中编译静态库(.a)和动态库(.so)的基本方法
在linux环境中, 使用ar命令建立静态库文件.以下是命令的选项:
d -----从指定的静态库文件中删除文件 m -----把文件移动到指定的静态库文件中 p -----把静态库文件中指定的文件输出到标准输出 q -----快速地把文件追加到静态库文件中 r -----把文件插入到静态库文件中 t -----显示静态库文件中文件的列表 x -----从静态库文件中提取文件
还有多个修饰符修改以上基本选项,详细请man ar 如下列出三个:
a —–把新的目标文件(*.o)添加到静态库文件中现有文件以后
b—–*****以前
v —–使用详细模式
ar 命令的命令行格式以下:
ar[-]{dmpqrtx}[abcfilNoPsSuvV][membername] [count] archive files…
参数archive定义库的名称, files是库文件中包含的目标文件的清单, 用空格分隔每一个文件.
好比建立一个静态库文件的命令以下:
ar r libapue.a error.oerrorlog.o lockreg.o
这样就了libapue.a静态库文件, 能够用 t 选项显示包含在库中的文件
建立库文件以后,能够建立这个静态库文件的索引来帮助提升和库链接的其余程序的编译速度:
使用ranlib程序建立库的索引,索引存放在库文件内部.
ranlib libapue.a
用nm程序显示存档文件的索引,它能够显示目标文件的符号
nm libapue.a | more
若是是显示目标文件的符号:
nm error.o | more
如何使用呢?以下所示:
gcc -o test test.c libapue.a
这样就能够在test.c中调用在libapue.a中的函数了.
gcc -shared -o libapue.soerror.o errorlog.o
这样就建立了共享库!
假设共享库位于当前目录(即跟程序文件相同的目录中)
gcc -o test -L. -lapue test.c
这样就编译出了不包含函数代码可执行文件了,可是但你运行时会发现linux动态加载器找不到libapue.so文件.
能够用ldd 命令查看可执行文件依赖什么共享库:
ldd test
如何才能让动态加载器发现库文件呢?有两种方法能够解决:
环境变量
exportLD_LIBRARY_PATH=”$LD_LIBRARY_PATH:.”
修改/etc/ld.so.conf文件.
通常应用程序的库文件不与系统库文件放在同一个目录下,通常把应用程序的共享库文件放在 /usr/local/lib 下,新建一个属于本身的目录 apue,而后把刚才 libapue.so 复制过去就好了
同时在 /etc/ld.so.conf 中新增一行:
/usr/local/lib/apue
之后在编译程序时加上编译选项:
-L /usr/local/lib/apue -lapue
参数的配置经过 mangcc 能够看到
-llibrary
链接名为 library 的 库文件.
链接器 在 标准搜索目录 中 寻找 这个 库文件, 库文件 的 真正 名 字