Linux静态库与动态库的创建

来源:互联网 发布:常见网络故障诊断工具 编辑:程序博客网 时间:2024/05/17 08:20
学习C语言时,第一个例子肯定是Hello world的程序,里面用到printf函数,可是我们很少有人会知道,printf函数与我们自己程序的关系,查查资料后知道,这里涉及到动态库和静态库的概念,深入了解后发现静态库很简单,但动态库有点麻烦,继续探究后发现麻烦的制造者是一个叫soname的家伙,下面我们从动态库和静态库的基本概念讲起,一步步剖析。对于程序员来说,很多常用的和与底层有关的函数不需要我们自己去编写,已经有人替我们编好了,它们是以库的形式呈现在我们程序员眼前供我们调用,库的本质就是很多个目标代码(可执行程序,后缀为o)的集合,这些库分为动态库和静态库。程序编译后方可以执行,动态库和静态库的区别主要在编译和执行过程,使用静态库,程序编译时把静态库里的相关可执行程序编译到可执行程序里,这样程序执行时就可以独立执行,相反使用动态库就不一样了,程序编译时动态库里的相关可执行程序并没有编译到程序里,而是执行的时候动态加载进去。这两种做法各有优缺点,使用静态库的程序可移植性好,但程序比较大,程序升级很不方便,同时使用动态库的程序可移植性不好,但程序小,程序升级很方便。从他们的优缺点分析,对于静态库,相同的代码可能存在于很多不同的程序中,但动态库只需要一个,不同的程序可以一块共享,这样对资源的节省是很给力的,同时给动态库的升级带来很大的方便。静态库的创建和使用。1、静态库创建。gcc –c x.car crs libname.a x.o gcc –c x.c:生成x.o。libname.a:静态库名称。x.o:共享库中的目标文件,后面可以跟很多个,x为目标文件名。2、静态库的使用gcc –static test.c –lname –L .–static:声明使用静态库test.c:要编译的文件-lname:要使用的静态库,name对应上面的。-L .:静态库libname.a所在目录。静态库就这两步,很简单,它对空间的要求和升级的不便是不可忍受的,所以我们一般选择动态库。既然我们选择了动态库,那就带来个问题,我们在程序执行的时候怎么去找动态库和实现版本兼容?有人可能想,这还不简单,去动态库文件所在目录去搜索你想要的函数,我只能说想法是好的,但不现实,一般我们有很多不同的库,万一你要的函数在最后一个库里怎么办,解决办法是让可执行程序中包含你所使用的动态库名,同时还有版本兼容问题,对于同一个函数,可能有好几个版本的库文件,他们是不兼容的,万一你选错了怎么办,解决办法是给动态库名加上有等级的版本号。要解决上面的问题,要用到soname这个概念,理解它分为三步:动态库的创建阶段。gcc –fPCI –c x.cgcc –shared –Wl,-soname,libname.so.x –o libname.x.x.x x.ogcc –fPCI –c x.c:生成相对地址的目标文件。-shared:生成的是共享库。-Wl,-soname,libname.so.x:给生成的动态库起别名,其中name和x是可变的。-o libname.x.x.x:共享库的名字,3个x为版本号,name和x是可变的。x.o:共享库中的目标文件,后面可以跟很多个,x为目标文件名。  这样就可以创建动态库,同时给动态库起了个别名(soname),通过这个别名就能解决上面的找动态库和版本兼容问题,很神奇吧,原理是什么呢,这要先讲讲动态库的实际名libname.so.x.x.x,name是动态库标识名,它后面的3个x分别是大版本号,小版好,维护号。它们的区别是,大版本号在改变库里的任何函数接口时才进行改变,接口变以后,前面用到这个函数的程序就不能运行了,小版本号是不改变任何函数的接口,只加了几个新的函数,这样前面的程序也能运行,维护号是修改现有函数的bug时才改变。而我们的soname中name和实际名是一样的,但只有大版本号,这样就能解决版本兼容问题,如果你没有改大版本号,这时只需要把新动态库库覆盖掉旧动态库就行了,但如果大版本号改了,那新旧动态库要同时存在,同时soname的x也有新旧之分,新程序需要新soname,旧程序需要旧soname。程序的编译阶段。gcc test.c –lname –L .-lname:要使用的动态库,name对应上面的。-L .:动态库libname.so所在目录。第一步把动态库建好了,我们现在是在使用动态库,我们知道编译过程中是不会把实际目标代码编译进可执行程序的,这是动态库的特点,那这一步的-lname的目的是什么呢?它的目的是给可执行文件传递个动态库的信息,你执行的时候需要这个动态库,那-L .又是干什么的呢?我们从第一步知道,动态库为了实现版本兼容,后面会跟版本号,问题来了,我们又不知道版本号,那怎么办呢?-L .指定libsoname.so所在的目录,而libname.so是个软链接文件,它链接到实际的库文件,而实际的库文件中会有soname的信息,这样就把soname的信息保存在生成的可执行代码中。这样程序执行的时候就回去找soname,同时使我们编译时不需要知道实际的版本号。ln –s libname.so.x.x.x libname.so 程序的执行阶段这是看结果的一步,看程序能否正确执行,也就是说能否找到动态库并保持版本兼容,由于程序执行时会去找soname这个动态库,但我们发现soname和实际动态库名是不一样,soname只有大版本,而实际的动态库有三个版本号,这可怎么办?不要当心,和第二步一样,创建软连接指向实际的动态库文件就可以了。也可以指向libsoname.so,这样实现了双重软链接,但本质是不变的,就是指向实际的动态库文件。ln –s libname.so.x.x.x libname.so.x或者ln –s libname.so libname.so.x(双重链接)

0 0
原创粉丝点击