Linux之静态库和动态库
目录一、媒介
二、对于库的理解
三、静态库
四、动态库
五、动静态库的加载
一、媒介
在之前,我们讲了静态库和动态库,详情请跳转:静态库和动态库
下面我们将从工程师的角度,去相识静态库和动态库的形成过程,以及实现它们的制作。并且相识如何将自己的库交给别人,让别人也可以使用。
二、对于库的理解
Linux的库一样平常分为动态库和静态库:
静态库:库文件以 .a 为后缀,步伐在编译链接的时候把库的代码链接到可执行文件中。步伐运行的时候将不再必要静态库。
动态库:库文件以 .so 为后缀,步伐在运行的时候才去链接动态库的代码,多个步伐共享使用库的代码。
gcc 在编译时默认使用动态链接,链接动态库,而如果想天生静态链接,我们必要在末端带上 -static。
而我们知道,步伐编译链接的最后,实在就是将各种 .o 可重定位目的二进制文件包括 main 函数的 .o文件,与所包含的 .h 文件全部链接起来,形成可执行步伐。以是,这是不是就意味着,用户真正必要的库文件实在是 .o 文件,设计者可以不用将源文件提供给用户,而直接将.o和.h文件提供给用户,以供用户链接。如许不仅方便,而且能够掩护源码。如许可以吗?
如下图,在该目录下,我们只有.h和.o文件,没有这些文件的源码。那么能编译乐成吗?
https://img-blog.csdnimg.cn/direct/67134ee4252a44628af42f5c2bbd6ac4.png
编译效果如下:
https://img-blog.csdnimg.cn/direct/8e5dccba781a48e58acab6bd710ea31f.png
我们发现,编译出的可执行步伐能够运行。
但是如果存在许多.c文件呢?岂非我们要把几千个.c文件全部编译成.o在加上头文件全部一个一个提供吗?那样太过于贫困,为了让用户更好的使用库,我们就有把所有的.o文件打成一个包,给对方提供一个库文件。
以是,库中包含了多个.o文件。
三、静态库
我们可以使用 ar 命令(把所有的.o打包起来),来制作一个静态库。比如:我们要打包二中所讲到的.o文件:
ar -rc libexe.a myadd.o myprintf.o https://img-blog.csdnimg.cn/direct/1447ef9041754df5aa10fddd8388f2e0.png
当然,我们也可以写一个Makefile来快速制作一个库。
https://img-blog.csdnimg.cn/direct/89415563e75d4059bbd5f7b62a1804b5.png
output:而我们要交付库,实际上要把库文件 .a 以及匹配的头文件都交付给用户,而output就相称于一个发布的过程。
https://img-blog.csdnimg.cn/direct/2d4cc875ffc34bd383bc43276a5b705e.png
好了,那么静态库我已经制作好了,且已经发布了,那么我们来使用一下自己制作的库。首先,我们将库拷贝到 mylib 目录下去使用。
https://img-blog.csdnimg.cn/direct/56774d9dcfd341dda7b72ccc6241704a.png
但是,当我们编译时,却堕落了:
https://img-blog.csdnimg.cn/direct/739a34b6d0d149a1a4c60e7af4d00bfd.png
gcc在编译时,找不到头文件!!!
办理方法:编译器搜索头文件时默认在当前目录下搜索,在系统默认指定路径下搜索。虽然此时的mylib在当前路径下,但是头文件太深了,编译器找不到头文件,以是我们必要给gcc指定路径。如下:使用选项 -I 告诉编译器头文件所在路径。
https://img-blog.csdnimg.cn/direct/ee058978b0cb4dc480df15d05ad12dea.png
问题又来了,gcc找不到库函数的实现。我们在形成可执行步伐的时候,库文件要使用的话也要知道库所在的路径在哪里,系统的默认路径是/lib64,而这是我们自己制作的库,不在内里。以是我们要带上 -L。告诉库的路径在哪里。由于该路径下大概有多个库,以是我们还要使用 -l 选项,加上库名字去掉前缀和后缀 .a。
https://img-blog.csdnimg.cn/direct/09c0eed3711e42cb9d66ecd49366bd7d.png
如上图,我们编译并且运行乐成了。
总结:
-I:指明头文件的搜索路径
-L:指明库文件的搜索路径
-l:指明要链接哪个库,带上库的名称(去掉前缀和后缀)
四、动态库
首先我们必要把库文件全部编译成.o文件,这里与静态库不同,必要带上选项 -fPIC,形成与位置无关码。我们照旧以上面的文件为例:
gcc -fPIC -c myadd.c -o myadd.o gcc -fPIC -c myprintf.c -o myprintf.o https://img-blog.csdnimg.cn/direct/9670f8102b044257a347246a76cf7cd1.png
动态库打包必要加上选项:-shared。
gcc -shared myprintf.o myadd.o -o lib.so https://img-blog.csdnimg.cn/direct/9f01c45bec664454a1588f71c2908d27.png
我们可以创建一个makefile,同时形成静态库和动态库。
https://img-blog.csdnimg.cn/direct/e34996a81ae94d35b5aadc73a17445e3.png
https://img-blog.csdnimg.cn/direct/e252a1a178934c0ba403e3e979c47640.png
然后我们发布:
https://img-blog.csdnimg.cn/direct/57ceee7aa74343669e615f9986908209.png
接下来,我们就来使用一下我们自己制作的动态库。
https://img-blog.csdnimg.cn/direct/7f4c2840ca784867955d45d8568a0b2a.png
下图中,我们编译乐成,且形成了可执行步伐。 https://img-blog.csdnimg.cn/direct/9fbdd2f6256f488ca6f00feae36e8bdd.png
但是,当我们运行可执行步伐时,却失败了:
https://img-blog.csdnimg.cn/direct/88889b129b884b69a4db68317780f61d.png
由于我们的lib目录下,既有动态库,也有静态库,以是gcc在编译时默认使用的是动态库。可是,既然我已经指明白库所在的路径,那为什么在运行可执行步伐时还会动态链接失败呢?
原因就是:那只是在编译时,告诉了gcc编译器动态库在哪里,然后编译乐成且形成了可执行步伐,如果你在编译时没有告诉库在哪,编译就不会乐成,且不会形成可执行步伐。而我们运行可执行步伐是由操纵系统加载到内存来运行的,运行时也必要告诉操纵系统库在哪里。我们还没有告诉操纵系统动态库在哪里呢!!!
办理方法:
1、添加到情况变量里:把库路径添加到情况变量LD_LIBRARY_PATH
比如:我的动态库所在路径为:/home/zdl/mylib/output/lib
https://img-blog.csdnimg.cn/direct/10c2907830c5492d8e0fb0947e760699.png
但是我们自己界说的情况变量只是本次登录有效,如果想永久有效只能修改情况变量的配置,但是比较贫困。想永久有效,我们另有其他的方法。
2、配置文件(/etc/ld.so.conf.d/):动态库进行对应搜索时可以采用自己界说conf文件找到动态库
直接在该路径 /etc/ld.so.conf.d/ 下创建一个以.conf为后缀的文件。
https://img-blog.csdnimg.cn/direct/dc4c809ba67e4dae9558c66044c068f5.png
然后将动态库所在的路径添加到文件中即可。
https://img-blog.csdnimg.cn/direct/9ca338f4389744e192d28be3e4b25e50.png
最后,使用sudo ldconfig使文件生效。
3、创建软链接直接找到对应的库
可以将库的路径创建软链接到 /lib64/ 路径下。
五、动静态库的加载
静态库:静态库是直接将自己的代码和数据拷贝到可执行步伐中,然后随可执行步伐一同加载到内存中。它们相称于已经是一体的了。静态库的代码随可执行步伐的代码一起加载到步伐地址空间的代码区。
动态库:动态库可以和可执行步伐分批加载。
动态库加上fPIC选项形成位置无关码,采用相对编址的方法,在步伐链接时对应库当中的偏移量添加到可执行步伐,运行时一旦库加载进来,经过地址空间映射,把库映射到地址空间之后,库也就具备了起始地址,通过偏移地址和起始地址如许就可以找到访问的函数。
具体过程:可执行步伐在运行时,如果遇到某处代码必要调用库的方法,库的代码和数据就会加载到物理内存中,然后将你必要使用的方法通过页表映射到共享区。然后代码直接到共享区去找,再通过页表找到物理内存中的具体方法,使用完后,代码继承向后执行,如又遇到库里的方法,就再去找。
https://img-blog.csdnimg.cn/direct/90dafbae28464562834634eb01f307d5.png
如果有多个进程必要使用同一个库,那么其他的进程可以直接通过页表和物理内存中的代码直接创建联系。以是动态库加载一次就可以被多个进程共同使用了。
而静态库大概有多个步伐用了C库,加载到内存时,内存里大概会存在许多份重复的代码。而动态链接不会出现重复的代码,减少内存占用。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]