动静态库基本原理
动静态库时可执行程序的“半成品”。
所有的库本质就是可重定向二进制文件的集合,即目标文件的集合,其中包含了大量的执行方法。
使用ldd 可执行程序
命令查看可执行程序依赖的动静态库文件
认识动静态库
在windows中动态库以.dll
为后缀,静态库以.lib
为后缀。
在Linux中动态库以.so
为后缀,静态库以.a
为后缀。库的命名有规范,一个库的名字去掉前缀lib
,去掉后缀.so
或者.a
剩下的就是库的名字。例如libstdc++.so.6
的库名字就是stdc++
在使用gcc/g++
生成可执行程序的时候,默认情况下生成的可执行程序就是动态链接动态库,如果想要静态链接静态库的话,需要使用-static
选项来静态编译生成可执行程序。
动静态库的优缺点
静态库
- 缺点
- 浪费空间
- 占磁盘空间,因为静态链接是将静态库中的代码加载到可执行程序中,所以静态编译的文件自己体积比较大。
- 占内存空间,多个静态文件链接同一个静态库的时候,内存中会出现大量的重复代码
- 浪费空间
- 优点
- 与库文件弱相关,不需要依赖库文件
- 由于静态编译的时候,已经将静态库中的代码都放到可执行程序的正文代码中了,所以可执行程序本身是一个独立的文件
- 与库文件弱相关,不需要依赖库文件
动态库
- 缺点
- 与库文件强相关,必须依赖库文件
- 如果将一个动态库文件从内存和磁盘中删掉,这个动态库链接的可执行程序就都不能运行了,
- 与库文件强相关,必须依赖库文件
- 优点
- 节省空间
- 节省内存空间,动态库文件在内存中只有一份,通过页表映射到不同进程的进程地址空间中的共享区共享。在静态链接的文件中,静态库的代码直接映射进了进程地址空间的正文代码中。
- 节省空间
如何制作和使用动静态库?
我们在给被人静态库的时候,需要把.a/.so
库文件和.h
头文件给到对方。.a/.so
让别人可以调用库中的函数,.h
告诉别人库中有哪些函数可以被调用,相当于函数使用的说明书。
在使用第三方库的时候,需要指明库的名称。
假设有四个文件add.c
,add.h
,sub.c
,sub.h
,我们需要通过它们制作一个动静态库。
制作静态库
- 编译同名的目标文件
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
- 生成静态库
生成一个叫做cal
的静态库。
需要使用ar
命令,其中-r
选项表示replace
,-c
表示create
ar -rc libcal.a add.o sub.o
使用静态库
假设我们在test.c
中调用了add
函数和sub
函数。我们在链接静态库的时候,需要告诉编译器三个要素。
- 调用的函数的头文件在哪
- 使用
-I
+头文件的路径
- 使用
- 调用的函数的库文件在哪
- 使用
-L
+库文件的路径
- 使用
- 调用的库的名称
- 使用
-l
+库的名称
- 使用
我们使用的是上面使用ar
打包出的libcal.a
文件,库文件名就是cal
gcc test.c -I 头文件路径名 -L 库文件路径名 -l cal
注意:如果头文件和库文件在系统可以找到的路径下,例如在/usr/lib
等的话,就可以直接使用gcc/g++
链接动静态库而不使用很多复杂的选项了。将库文件拷贝到系统默认的路径下的过程就是安装库的过程。
制作动态库
- 生成目标文件
在生成同名的目标文件的时候,需要加上-fPIC
选项,即产生位置无关码,这样就可以让可执行程序找到对应的动态库。
gcc -fPIC -c add.c -o add.o
gcc -fPIC -c sub.c -o sub.o
- 生成动态库
在打包动态库的时候,需要加上-shared
轩昂
gcc -shared -o libcal.so add.o sub.o
使用静态库
和使用静态库一样,需要执行调用的函数所处路径,使用库文件的路径和使用库文件路径下的哪一个库文件
gcc -test.c -I 头文件路径名 -L 库文件路径名 -l cal
和使用静态库不同的时候,这个时候还是不能使用动态库链接的文件。因为上面是在生成文件gcc/g++
编译器需要知道库文件的位置,但是在运行的时候,系统需要动态地调用库中的函数,所以在运行要让系统知道要使用动态库的位置。
有三种方法可以让系统知道动态库的位置
- 将动态库拷贝到系统共享库路径下
- 做系统配置
在/etc/ld.so.conf.d/
下添加配置文件,配置文件中写入动态库的路径,然后使用ldcnfig
命令更新。
- 修改环境变量
LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库的绝对路径