linux下的动态库与静态库

来源:互联网 发布:2017好看的网络大电影 编辑:程序博客网 时间:2024/04/29 11:31

linux下的动态库与静态库


原文链接:http://blog.csdn.net/Payshent/article/details/73277914?locationNum=1&fps=1
因为在原文页面没看到收藏功能,自己就转载了一下,相当于收藏吧。

今天就来谈一下linux中比较重要的一个知识点–静态库和动态库。说到静态库和动态库啊,不得不提的就是程序编译链接的过程,现在有很多的IDE我们很少去关注程序编译链接的本质,但是其背后的运行机制却是必须要我我们熟悉的,我之前写过一片就是C、C++程序的编译链接过程的博客,详情见下: 
http://blog.csdn.net/payshent/article/details/72314685 
库: 
说到库那么什么是库呢?库从本质上来说就是一种可执行代码的二进制形式,可以被操作系统载入内存中执行。 
所谓库就是一些功能代码经过编译链接的可执行形式。 
我们通常使用的库就是库就是别人写好的,现有的、可以用的、成熟的代码,在我们开发的过程中只用引入文件链接到我们的程序中即可。 
在说链接的时候,链接的主要内容就是把各个模块之间相互引用的部分处理好,使得各个模块之间可以正确的衔接。而链接也是有两种的链接形式:静态链接与动态链接。 
静态链接: 
所谓的静态链接就是:在编译链接的时候直接把需要执行的代码拷贝到要执行的地方(要调用的地方)。 
优点: 
1、程序发布的时候不需要依赖库,也即是不需要带着库一起发布,程序可以独立运行。 
2、代码装载的速度快,执行速度略比动态链接快。
 

缺点:缺点就是它的体积就会变大,包含相同的公共代码造成浪费。 
在linux中静态链接的文件就是.a的文件。

动态链接: 
动态链接就是在编译的时候不直接拷贝可执行的代码,而是通过记录一些符号和参数。在程序运行或加载的时候将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中去,程序在运行大指定代码的时候,去共享内存中已经加载的动态库可执行代码,最终达到运行时链接的目的。 
优点: 
1、多个程序可以共享同一段代码,不需要在磁盘上存储多个拷贝,引用程序小比较节省空间。 
2、DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性 
3、不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数 
4、适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试
 

缺点:由于是运行加载可能会影响程序前期的执行性能,速度较慢。 
在linux下动态链接的文件是.so的文件。 
linux下库分为两种:静态库和动态库。 
静态库: 
静态库的命名方式是“libxxx.a”,库名前面加lib,后缀为.a,xxx为静态库名。 
链接时间:静态库的代码是在编译的过程中被载入到程序中。 
链接方式:静态库的链接是将整个函数库的所有数据都整合进了目标代码。优点就是编译后的执行程序不需要外部的函数库的支持(所用的函数已经被编进去了),缺点就是所使用的静态库发生更新改变,程序必须重新编译。 

动态库: 
动态库的命名方式与静态库相似,前缀相同为“lib”,后缀为“.so”。 
链接时间:动态库在编译的时候并没有被编译进目标代码,而是当你的程序执行到相关函数的时候才调用函数库里相关的函数。 
优点:动态库的改变不影响你的程序,动态函数库升级比较方便。 
缺点:函数库没有整合进程序,程序的运行环境必须提供相应的库。 
不同点: 
当一个程序分别使用动态库和静态库两种方式生成两个可执行文件时候,静态链接生成的文件所占用的内存要比动态链接生成的文件所占用的内存要大。(静态链接在编译的时候把所有的函数都编译进了程序,动态链接在运行的时候才调用库里的函数) 

静态库的创建、使用的实例: 
下面我们先来介绍命令与常用的选项 
ar命令:用来维护链接编辑库所使用的库索引,ar命令将一个或多个指定的文件并入单个并写成ar压缩文档格式的压缩文档文件。当ar命令创建库的时候,可以创建可传输格式的报头,当创建和更新库的时候会重建符号表。 
常用的选项: 
-c:创建一个库,不管这个库存不存在,都将创建。 
-r:在库中插入模块(替换)。若插入的模块在库中存在,则会进行替换。 
-s:创建目标文件索引,在创建较大的库时能加快时间。不困是否修改了库内容,都将重新符号表。
-t:将库目录写到标准输出,如果指定文件名称,则显示指定的文件。如果不指定文件名称的话,则显示库目录的所有文件。 
-v:将建立新库的详细的文件逐个写到标准输出 

实例如下: 
准备两个库源码文件test1.c test2.c: 
这里写图片描述 
将这两个文件制作库libmytest.a 
这里写图片描述 
静态库libmytest.a已经生成,用file命令查看其属性,发现它确实是归档压缩文件 
这里写图片描述 
test.c这个主程序是用来测试libmytest.a中的两个接口print1()和print2() 
这里写图片描述 
gcc -o test test.c -L. -lmytest 中,-lmytest表示要使用的库,“-L.”表示这个库再当前目录下,-L表示定制目录。 

动态库的创建和实例: 
我们创建了3个文件,分别是test1.c、test2.c、test.h这三个文件 
这里写图片描述 
下面为创建动态库: 
-shared:该选项指定生成动态连接库 
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的 

我们在进行动态链接的时候有两种方法:一就是运行时的动态链接 还有一种就是通过函数进行动态链接。 
这里写图片描述 

1、运行时的动态链接: 
我们使用“-lmytest”标记来告诉GCC驱动程序在连接阶段引用共享函数库libmytest.so,然后用ldd查看一个可执行程序的依赖文件,然后ldd检测说libmytest.so没有找到。 
这就是动态链接执行、搜索的路径有关 
1、编译目标代码指定的动态库搜索路径 
2、环境变量LD_LIBRARY_PATH指定的动态库搜索路径 
3、配置文件/etc/ld.so.conf中指定的动态库搜索路径 
4、默认的动态库搜索路径/lib 
5、默认的动态库搜索路径/usr/lib 
解决上面的问题的话,我们自己开发的共享库就可以将其拷贝到/lib、/etc/lib目录里,又或者修改/etc/ld.so.conf文件将我们自己的库路径添加到该文件中,再执行ldconfig命令。 当把上面的问题解决之后我们就可以使用自己的动态库来进行运行时的动态链接。 
这里写图片描述 

2、通过函数来进行动态链接 
先关的函数:

const char *dlerror(void)

当动态链接库操作函数失败的时候,dlerror返回出错的信息,返回NULL表示操作函数执行成功。

void *dlopen(const char *filename, int flag)

功能:用于打开指定名字(filename)的动态链接库,并返回操作句柄。调用失败时,将返回NULL值,否则返回的是操作句柄。 
flag:表示在什么时候解决未定义的符号(调用)。取值有两个: 
1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。 
2) RTLD_NOW :表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

void *dlsym(void *handle, char *symbol)

功能: 根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。

int dlclose (void *handle)

功能:用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。2.2在程序中使用动态链接库函数。 
这里写图片描述 
在使用动态链接库的源程序要包含dlfcn.h这个头文件,写程序应该注意dlopen等函数的正确调用,编译时要采用-rdynamic选项与-ldl选项(不然编译无法通过),以产生可调用动态链接库的执行代码。 
这里写图片描述

版权声明:文章转载需注明出处,谢谢合作。
  • 本文已收录于以下专栏:
  • linux学习历程
原创粉丝点击