目录
哈喽,小伙伴们大家好。大家有没有好奇一个问题,我们写代码时,都是包含头文件后直接调用printf,scanf等函数,那么代码的实现是在哪里呢?这就要设计的库的知识。
库包括动态库和静态库,统称为动静态库。动静态库的本质是可执行程序的半成品。程序在进行完汇编阶段后生成.o二进制文件,然后这些二进制文件打包形成库。
库的本质:一堆.o文件的集合,不包含main,但是包含了大量的实现方法。
我们编写如下代码:
编译生成可执行程序 mytest,使用命令ldd 可以查看可执行程序调用的库。
画红线的位置为c库,查看后发现这是一个软链接,然后可以进一步查看找到真正的c库。
linux下编译生成的默认是动态库。
Linux下:
windows下:
动态库libc.so.6,去掉前缀lib,去掉后缀,就是库的名字c。
再编译生成一个静态库,可以对比动静态库的链接信息。
(1)静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
(2)动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
(3)如果多个进程同时进行,而可执行程序中又静态链接了许多相同的库,那么内存中就会有大量重复的代码,造成空间浪费。而动态库可以在多个进程间共享,只在内存中加载一份。动态库的地址存在地址空间的共享区,不同的进程可以通过地址空间与页表的映射找到动态库。
(1)先生成.o文件
(2)用ar -rc命令把.o文件打包生成静态库
ar是gnu归档工具,rc表示(replace and create),生成静态库libcal.a
(3)把静态库交给别人
给别人库本质上是给别人一份头文件(库的使用说明书)+库文件。把静态库和.h文件分别打包放在mathlib的不同路径下,传给上级目录模拟交付其它用户
(4)使用静态库
编写test.c:
- #include
- E>#include
- int main()
- {
- int a=10;
- int b=20;
- E> int z=my_add(a,b);
- printf("%d",z);
- return 0;
- }
使用命令:
gcc test.c -I./mathlib/include -L./mathlib/lib -lcal
其中-I后面跟的是头文件所在的路径,-L后面跟的是静态库所在的路径,-l后面跟的是静态库的名字。
(5)把库和头文件拷贝到系统默认的查找路径下
把库和头文件拷贝到默认查找路径下后,生成可执行程序时不需要再指明,但是库的名字依旧要指明。平时我们在编译程序时不需要指明是因为我们写的是c语言,编译器会默认区c库查找。
注意:拷贝库到系统路径下的过程本质就是安装库的过程。
生成静态库时和动态库时有两点不同:
一是在生成.o文件时需要加上fPIC生成位置无关码。二是在打包时候使用gcc命令,加上shared,表示生成共享库格式。
之后和静态库的流程一样,打包好后传到上级目录,然后用动态库编译生成可执行程序。但是这时候发现生成的可执行程序是不能直接运行的。因为系统找不到这个库。
这时候我们可以更改环境变量 LD_LIBRARY_PATH,该环境变量为系统默认搜索的动态库的路径。
更改环境变量后发现程序可以正常运行。
本文主要讲解了动静态库的理解和制作,希望能给大家带来帮助。如果感觉有收获的话可以点个赞支持一下博主。感谢阅读,来日方长,我们下次见。