头文件的作用:
include的作用就是复制内容到当前文件
井号开头的就是预处理指令,由预处理器处理,预处理阶段不关心代码,只处理预处理指令。
头文件主要 一是为了解决代码都写在一个文件太大了,二是把变量,结构体,函数声明这些固定的放在一起
函数只要声明了,第二个阶段(编译阶段)语法检查就能通过,如果没定义实现,则第四个阶段链接时会报错link失败
c++ 编译过程:
1阶段,预处理阶段, 处理代码中的预处理指令,比如复制include到当前文件
2阶段,编译阶段 6步: 扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成、目标代码优化
3阶段,汇编,把正确的汇编代码汇编位二进制代码
4阶段,链接,这时候才会找头文件中声明的函数的定义,如果没有函数具体实现,就会报错
链接作用:
链接主要是把多个目标文件(.o文件) 放在一集合,解决每个目标之前引用的外部定义的变量、函数等地址引用问题
首先会合并目标文件,这里可以理解为代码合并,然后函数调用的地方需要修改指向具体的函数位置,也就是重定位的原因。
动态库
动态库一般编译都会有-fPIC选项,也就是位置无关代码,代码的地址都是相对位置,加载到程序内存中任何位置都能正确执行。
因为同一个动态库可能被不同的进程加载,加载位置肯定不一样。
动态库在每个阶段的作用,来自AI
动态库(.so文件)在程序运行阶段的作用是允许程序按需加载和卸载库文件,从而提高程序的灵活性和效率。
在编译阶段,程序只需要连接动态库的符号信息,而不需要动态库的实际代码,因此生成的可执行文件体积通常比静态链接库更小。在运行阶段,程序会通过动态链接器将程序中引用的动态库加载到内存中,并将其映射到程序地址空间中的适当位置,然后程序就可以使用动态库中的函数和变量了。
当程序不再需要库文件时,动态链接器会自动卸载它们,从而释放内存空间。此外,由于多个程序可以共享同一个动态库实例,因此动态库可以减少系统资源的消耗,并提高程序的运行效率。
动态库的用法
g++ main.o -L 动态库的路径 -I 头文件路径 -l动态库名字(名字不需要前缀lib和后缀.so) // 可以链接多个库和头文件目录
静态库:
静态库可以为通过ar程序将多个目标文件.o 打包成一个文件,没做什么改动。
链接时,主程序和静态库(多个目标文件一起链接)
静态库的用法:
g++ main.o -L 动态库的路径 -I 头文件路径 -l动态库名字(名字不需要前缀lib和后缀.so) -static // 可以链接多个库和头文件目录
之所以加-stacic, 是因为链接命令都一样,都是-L, -I, -l, 所以gcc默认使用动态库链接,连接不上再尝试用静态库链接
由于静态库是目标文件的合体,所以可以当作一个目标文件直接写名字进行链接: gcc main.c -I include lib/libTest.a -o app
还有一个就是静态库的-fPIC选项, 当一个动态库依赖这个静态库时,由于动态库肯定是位置无关的,此时静态库被链接进去,也应该是位置无关的
所以被依赖的静态库也要用-fPIC选项编译,通常也个选项是关闭的。
如果静态库没有-fPIC,编译动态库链接会提示一堆重定位错误 reloaction 字样的信息
如何查看是不是位置无关代码:
动态库 readelf -d xxx.so |grp REL 存在REL就是,一般都是
静态库 readelf --relocs xxx.a |grep GOT ,存在就时位置无关的。
总个节:
头文件就是代码, 只有编译的预处理阶段有用,运行时就没用了
静态库只在编译时有用
动态库运行时有用。
编译阶段:
自己写的动态库使用时除了gcc -L指定路径, 还可以放到环境变量路径下比如/bin, 但需要执行一次ldconfig更新动态库的缓存信息。
也可以临时设定LIBRARY_PATH: export LIBRARY_PATH=${LIBRARY_PATH}:./lib/xxx.so
运行阶段:文章来源:https://www.toymoban.com/news/detail-701555.html
除了把动态库放入环境变量设置的路径下,比如/bin 还可以设置export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:./lib/xxx.so文章来源地址https://www.toymoban.com/news/detail-701555.html
到了这里,关于linux下g++链接动态库和静态库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!