婚庆网站开发计划书,wordpress 模板 学校,济南将开展治堵十大行动,网络规划设计师视频徐朋百度网盘#x1f320; 作者#xff1a;阿亮joy. #x1f386;专栏#xff1a;《学会Linux》 #x1f387; 座右铭#xff1a;每个优秀的人都有一段沉默的时光#xff0c;那段时光是付出了很多努力却得不到结果的日子#xff0c;我们把它叫做扎根 目录#x1f449;动静库和静… 作者阿亮joy. 专栏《学会Linux》 座右铭每个优秀的人都有一段沉默的时光那段时光是付出了很多努力却得不到结果的日子我们把它叫做扎根 目录动静库和静态库制作动静态库制作静态库制作动态库库的意义总结动静库和静态库 静态库.a程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。动态库.so程序在运行的时候才去链接动态库的代码多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表而不是外部函数所在目标文件的整个机器码。在可执行文件开始运行以前外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中这个过程称为动态链接dynamic linking。动态库可以在多个程序间共享所以动态链接使得可执行文件更小节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用节省了内存和磁盘空间。而静态链接是将库的代码链接到可执行文件中因此该可执行文件往往比较大。 制作动静态库
在工程项目开发中我们往往会用到第三方提供的库。那第三方的库是如何制作出来的呢第三方制作出来的库是如何提供给我们使用的呢为了回答两个问题我们现在就来学习一下动静态库的制作。
制作静态库
为了更好地说明演示库的制作我们先回顾一下以前的多文件的写法。头文件中放库中的头文件的包含和函数的声明等源文件中放函数的实现等。
// myprint.h
#pragma once#include stdio.h
#include time.hextern void Print(const char* str);// mymath.h
#pragma once#include stdio.hextern int addToTarget(int from, int to);// myprint.c
#include myprint.hvoid Print(const char* str)
{printf(%s [%d]\n, str, (int)time(NULL));
}// mymath.c
#include mymath.hint addToTarget(int from, int to)
{int ret 0;for(int i from; i to; i){ret i;}return ret;
}// main.c
#include myprint.h
#include mymath.hint main()
{Print(hello world);int ret addToTarget(0, 100);printf(ret %d\n, ret);return 0;
}输入gcc main.c mymath.c myprint.c -o my.exe -stdc99指令就可以生成可执行程序 my.exe了。 假如现在我们是库的制作者如果我们将头文件 .h 和目标文件 .o 给别人别人是否可以实现我们所写好的库呢其实是可以的见下图所示 将目标文件提供给别人去编译是不方便别人使用的。因为目标文件多了编译起来就会比较麻烦而且传输的过程中还可能出现目标文件丢失的情况。所以我们需要将目标文件打包而形成的包就是传说中的静态库了。
将目标文件打包成静态库指令
ar -rc libhello.a mymath.o myprint.o
#以下是注释
#ar是GNU中的归档工具 archive 归档
#-r replace 替换
#-c create 创建
#lib 库的前缀 .a 静态库的后缀 两者之间的内容就是静态库的名字使用Makefile来生成静态库
libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o -stdc99
myprint.o:myprint.cgcc -c myprint.c -o myprint.o -stdc99.PHONY:clean
clean:rm -rf *.o libhello.a现在我们已经制作好了静态库那么如果将这个静态库发布给别人使用呢发布给别人使用的库中是包含 include 和 lib 两个文件夹其中 include 中包含库的所有头文件lib 包含的是对应的库文件。
那么我们修改一下 Makefile让它可以自动生成上方所述的路径。
libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o -stdc99
myprint.o:myprint.cgcc -c myprint.c -o myprint.o -stdc99.PHONY:hello
hello:mkdir -p hello/includemkdir -p hello/libcp -rf *.h hello/includecp -rf *.a hello/lib.PHONY:clean
clean:rm -rf *.o libhello.a hello将其他文件清理后就剩下静态库和我们写的程序了。 接下来我们就来学习一下如何使用静态库。
将静态库拷贝到系统的默认搜索路径。头文件的默认搜索路径是/usr/include/库文件的默认搜索路径是/lib64/或者/usr/lib64/。 现在我们已经将静态库拷贝到了对应的路径下那我们使用gcc main.c指令将代码编译一下就会发现无法通过编译。原因是 gcc 默认链接的静态库是/lib64/libc.a如果想让 gcc 链接我们写的静态库就需要使用下方的指令了。
gcc main.c -lhello
#-l 链接 hello是静态库的名字 注将库拷贝到系统的默认路径下就叫做库的安装。
将我们自己写的静态库拷贝到系统的默认链接下这种做法是不推荐的。因为我们自己写的库并没有经过可靠性验证所以不太建议这种做法。那么我们需要将自己写的静态库移出系统的默认路径该过程也称为库的卸载。 指定头文件、库的路径和要链接的库
gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello
#-I 指明头文件所在的路径
#-L 指明库的路径
-l 指明所要路径的库(因为库路径下可能不止一个库)制作动态库
静态库的代码是会被拷贝进可执行程序中而动态库在没有被链接前会被编译好当使用动态库时并不是将代码拷贝到可执行程序中而是让可执行程序与动态库产生关联。
生成目标文件
gcc -fPIC -c mymath.c -o mymath.o -stdc99
gcc -fPIC -c myprint.c -o myprint.o -stdc99
readelf -S 目标文件名 #查查看ELF格式的文件信息-fPIC 选项的意思是形成与位置无关的目标二进制文件。动态库形成后可以在内存的任意位置加载。而静态库的代码是拷贝到可执行程序中可执行程序是有自己的地址空间的所以静态库的代码需要拷贝到地址空间的特定位置这就是与位置有关。静态库是按照绝对编址的方式而动态库是按照相对编址段地址偏移量的方式。
将目标文件打包
动态库的打包并不是使用 ar 指令而是采用 gcc 加上 -shared 选项将目标文件打包成库。注意一定要加上 -shared 选项不然会被 gcc 识别成要生成可执行程序从而报出没有 main 函数的错误。
gcc -shared myprint.o mymath.o -o libhello.so以上就形成了动态库了那么我们也来学习一下用 Makefile 来生成动态库。
.PHONY:all
all:libhello.so libhello.alibhello.so:mymath_d.o myprint_d.ogcc -shared mymath_d.o myprint_d.o -o libhello.so
mymath_d.o:mymath.cgcc -fPIC -c mymath.c -o mymath_d.o -stdc99
myprint_d.o:myprint.cgcc -fPIC -c myprint.c -o myprint_d.o -stdc99libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o -stdc99
myprint.o:myprint.cgcc -c myprint.c -o myprint.o -stdc99.PHONY:output
output:mkdir -p output/includemkdir -p output/libcp -rf *.h output/includecp -rf *.a output/libcp -rf *.so output/lib.PHONY:clean
clean:rm -rf *.o *.a *.so output将动静态库拷贝到 uselib 路径下 链接动态库
gcc main.c -I output/include/ -L output/lib/ -lhello当存在同名的动静态库时使用上方的指令形成的可执行程序是无法执行的其报错原因是无法找到对应的动态库。那为什么会这样呢 当output/lib/路径下只有静态库时却又可以生成对应的可执行程序这又是为什么呢 原因是 gcc 默认链接的是动态库而如果只有我们自己制作的静态库没有自己制作的动态库那么就只能链接该静态库了。注意系统的动态库还是动态链接的只是静态链接自己制作的静态库。如果想让全部库都是静态链接的话需要加上 -static 选项。-static 的意义就是摒弃优先使用动态库的原则而是直接使用静态库。 如果存在同名的动静态库默认使用的就是动态库上面的报错只是找不到而已。那如何解决呢解决这个问题就需要了解动态库的加载了。 动态库的加载
如果是静态链接静态库中的代码会被拷贝到可执行程序中。当可执行程序运行时静态库的代码也被加载到内存了。而如果采用的是动态链接可执行程序和动态库是分批加载的并不是一起加载的。我们知道栈区和堆区之间存在一个共享区而动态库的代码就是被加载到进程地址空间的共享区中去了。 当有多个进程使用同一个动态库的代码这时候就不需要加载动态库的代码只需要建立页表映射关系就行了。如果多个进程使用同一个静态库那么内存中就会有多份静态库的代码这样就会浪费内存空间了。这也就是动态库的意义。
当我们执行可执行程序时不是已经指定了动态库所在的路径了吗为什么还是找不到动态库呢其实这是告诉 gcc 编译器并不是告诉给操作系统的加载器。当程序运行加载时就和 gcc 没有关系了所以我们需要将动态库所在的路径告诉给操作系统的加载器这样才能够找到动态库。 因为 C语言的动态可以就在系统的默认路径下所以操作系统就能够找到对应的动态库而静态库的代码是直接拷贝到可执行程序中的不存在需要找的问题。那么我们如果让操作系统找到自己制作的动态库呢第一种方式就是将自己制作的动态库拷贝到系统的默认路径下但这种方式不好。我们可以采用下方的方法
将动态库所在的路径导入到环境变量 LD_LIBRARY_PATH 中
系统可以通过环境变量 LD_LIBRARY_PATH 找到需要的动态库将其加载到内存中。 这种方法有一个缺点就是当我们将 Xshell 关掉时再次启动时会将导入到 LD_LIBRARY_PATH 中的路径都清空掉。
新增配置文件
我们只需要在/etc/ld.so.conf.d/路径下创建一个.conf后缀的文件该文件中保存动态库的路径最后输入sudo ldconfig指令更新配置文件即可。 将配置文件删除后还是找到我们的动态库的。原因是缓存中还有该配置文件只要将配置文件更新一下就可以了。
在/lib64/路径下建立一个与动态库的软链接 还有一种方法就是修改登录脚本Linux 的登录脚本文件有两个分别是 .bashrc 和 .bash_profile它们都是在家目录下的。.bash是被.bash_profile所调用的那么我们可以在.bash_profile文件中增加动态库所在的路径即可但这种方式不建议现在做。 以上就是动态库的制作了现在我们来了解一下为什么要有库。
库的意义 站在使用库的角度库的存在可以大大减少我们开发的周期提高软件本身的质量健壮性等。站在写库的人的角度1. 简单 2.代码安全。好玩的库ncurses基于字符的界面库搜索关键词 Centos 7 yum 安装 ncurses。boostC 的准标准库。 总结 本篇博客主要讲解了什么是动静态库以及动静态库的制作等等。那么以上就是本篇博客的全部内容了如果大家觉得有收获的话可以点个三连支持一下谢谢大家❣️