目录
静态库和动态库
gcc规则使用动静态库的规则:
制作静态库
使用静态库
方法1.
方法2.
制作动态库
使用动态库
方法1:
方法2:
方法3:
方法4:
进程,静态库,动态库
静态库和动态库
1. 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库,生成的可执行程序中自己的代码和静态库的代码是一体的,进程运行起来之后,全部都在代码区。
2. 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
所以,在编译链接时,静态库就会和自己的源文件合并,生成一个可执行程序,之后再执行此可执行程序时,不再需要静态库,因为已经在可执行程序内部了。而使用动态库时,动态库并不在可执行程序内部,每次运行过程中,才会去加载动态库。
gcc规则使用动静态库的规则:
1. gcc默认使用动态库,若只有静态库,gcc只能对该库进行静态链接。
2. 若动静态库同时存在,则gcc默认使用动态库
3. 若动静态库同时存在,-static 即可指定使用静态库,进行静态链接。
制作静态库
如上,两个.c 两个.h .h头文件包含库里面的函数声明 .c文件包含函数定义。
1. 将源文件,预处理,编译,汇编为.o可重定向二进制目标文件。
gcc -c mymath.c -o mymath.o gcc -c myprint.c -o myprint.o
2. 将所有.o文件归档为静态库(静态库文件)至此,静态库就生成好了
ar -rc *.o -o libplus.a (静态库文件的格式: libxxx.a)
3. 创建一个文件夹(目录),比如名为plus,将所有的头文件放在文件夹的include子目录下,将所有归档打包好的静态库放在plus的lib子目录下。 至此,这个plus文件就可以用来发布或者发给别人使用了。
使用静态库
方法1.
1. 将我们的第三方头文件和静态库放在系统存放头文件和库文件的默认路径下。
(或者头文件放在当前路径下也行,因为#include <>会先去系统默认路径下找,然后去当前路径下找,但是,你使用的头文件一般不会在当前路径下)
因为gcc在编译链接时,会去系统默认路径下去查找所需要的头文件和库文件。同时gcc也能自动链接C标准库。但是没法自动链接我们的第三方库.
Linux下,头文件gcc默认搜索路径:/usr/include 库文件默认搜索路径: /lib64 or /usr/lib64
2. gcc test.c -lplus -o test.exe
-lplus表示你要使用libplus.a这个静态库,而头文件不需要你在gcc编译时指定,因为你的test.c内部就已经说明了需要哪些头文件。 以上是在将头文件和静态库文件放在系统默认路径之后的操作。
方法2.
不将头文件和库文件放在系统默认路径下,则
gcc test.c -I ./plus/include -L ./plus/lib -lplus -o test.exe
通过gcc时添加指令的方式,说明头文件的位置,库文件的位置,你要链接哪个静态库文件。即可生成可执行程序。
相比之下,第二种方法更好点。因为不会污染系统默认路径下的环境。
我们将库拷贝到系统默认路径下,就叫做库的安装。
制作动态库
还是基于 myprint.h myprint.c mymath.h mymath.c
1. gcc -fPIC -c myprint.c -o myprint_d.o
gcc -fPIC -c mymath.c -o mymath_d.o
编译.c文件生成.o可重定向二进制目标文件时,加-fPIC指令,表示与位置无关地生成.o文件(这块和动态库使用的本质有关)
2. gcc -shared mymath_d.o myprint_d.o -o libplus.so
不用ar,用gcc -shared即可。将.o文件合并归档打包生成libxxx.so动态库 (这里若不加-shared,就等于生成可执行程序了)
3. 可以将.h放在plus/include/下 将.so放在plus/lib/下,这样plus文件就可以用来发布或者传给使用库的人了。
使用动态库
若我们还是gcc test.c -I ./plus/include -L ./plus/lib -lplus -o test.exe 生成test.exe文件(这里的/plus/lib下存储的是动态库),然后运行./test.exe 会直接报错。
./haha_dong: error while loading shared libraries: libplus.so: cannot open shared object file: No such file or directory
显示无法找到动态库,这里和动态库和静态库的本质区别有关,因为动态库不是编译链接生成可执行之后就可以随意运行了。在程序运行过程中,会跳转到动态库。而上方报错就是因为查找不到libplus.so
方法1:
拷贝.so文件到系统共享库路径下
Linux下,头文件gcc默认搜索路径:/usr/include 库文件默认搜索路径: /lib64 or /usr/lib64
因为程序运行过程中,需要动态库时,会自动去系统默认路径下查找动态库。这里不需要头文件,因为生成可执行的时候,头文件已经在你的源文件内部展开的。
方法2:
配置Linux系统环境变量:LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/yzl/aandso/plus2/lib
相当于,搜索动态库的时候,除了去系统默认路径下找,如果这个环境变量被配置了,还会在这个环境变量指定的路径下去找动态库。这里需要绝对路径。
缺点:这个环境变量在再次登录时,就没有了,因为环境变量的初值是通过系统的配置文件获取的。
方法3:
添加系统配置文件
/etc/ld.so.conf.d/ 路径下添加一个xxx.conf配置文件,将其内容设置为动态库的所在目录路径。
再sudo ldconfig 一下,表示更新配置文件,使其生效。
即可,这个是最安全最有效的了。退出重新登录也还在。
方法4:
在系统默认搜索库的路径下添加一个软链接
sudo ln -s /home/yzl/aandso/plus2/lib/libplus.so /lib64/libplus.so
不太推荐,类似方法1
综上,其实所有方法的目的都是为了在程序运行过程中能够找到动态库,而使用静态库的程序只要编译好之后,就不用再找静态库了,因为静态库已经在可执行程序内部了,目标文件生成后,静态库删掉,程序照样可以运行。。
进程,静态库,动态库
静态库在你的源文件编译汇编,最后链接时,已经进入可执行程序内部了,生成可执行程序之后,不再需要静态库文件。可以独立运行,所有代码都存在于进程地址空间的代码段中。
动态库和可执行程序可以分批加载,先运行可执行,若需要跳转动态库时,加载动态库代码到内存,建立进程地址空间中共享区(栈堆之间),页表,内存中的动态库代码的映射关系。执行动态库代码时,从代码段跳转到共享区,然后执行内存中的动态库代码即可。
这也是为什么动态库的.o文件编译时,要加-fPIC选项,这表示生成的.o文件是一种与位置无关的模式,即动态库的模式。
动态库是一种共享库,动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。 即,如果多个进程需要用到内存中的一个共享库,则利用虚拟地址空间机制,建立映射关系即可。