物流网站模板,友链网站,wordpress做图集,东莞做网站公司首选![Linux]动静态库 文章目录 [Linux]动静态库见一见库存在库的原因编写库模拟编写静态库模拟使用静态库模拟编写动态库模拟使用静态库 库的加载原理静态库的加载原理动态库的加载原理 库在可执行程序中的编址策略静态库在可执行程序中的编址策略动态库在可执行程序中的编址策略 见…[Linux]动静态库 文章目录 [Linux]动静态库见一见库存在库的原因编写库模拟编写静态库模拟使用静态库模拟编写动态库模拟使用静态库 库的加载原理静态库的加载原理动态库的加载原理 库在可执行程序中的编址策略静态库在可执行程序中的编址策略动态库在可执行程序中的编址策略 见一见库
在Linux系统中C语言标准库C Standard Library和其他常用库都被称为C库C library通常存放在/usr/lib或/usr/lib64目录下 在Linux系统中/usr/include目录下存放了许多头文件 Linux系统预装了C/C的头文件和库文件头文件提供方法的说明库文件提供方法的实现头文件和库文件有对应关系需要组合使用。在程序编译形成可执行程序的过程中头文件在预处理时被引入库文件在链接时被链接 。在visual studio下安装开发环境时不仅安装了编译器软件还安装语言对应的头文件和库文件。编译器会自动根据用户的输入查找头文件中的相关内容实现语法提示的功能。编译器会自动根据用户的输入不断地进行编译实现语法报错的功能。
存在库的原因
编程语言将常用的功能添加到库中以便于用户可以直接使用这些功能提高开发的效率。比如printf,用户不需要在每次想打印数据时编写一个用于打印数据的函数。
编写库
模拟编写静态库
进行库的编写前要说明一下
库分为动态库和静态库Linux下静态库的命名规则lib库名.aLinux下动态库的命名规则lib库名.so云服务下一般不会内置静态库
头文件和源文件的编写
编写头文件myadd.h和其对应的源文件myadd.c和头文件mysub.h和其对应的源文件mysub.c,各文件中的具体代码如下
//myadd.h
#pragma once int my_add(int x, int y);//myadd.c
#include myadd.h int my_add(int x, int y)//一个简单的加法函数
{return x y;
}//mysub.h
#pragma once int my_sub(int x, int y);//mysub.c
#include mysub.h int my_sub(int x, int y)//一个简单的减法函数
{return x - y;
}将源文件编译成目标文件
使用gcc -c 源文件名将源文件编译成目标文件 打包成静态库
使用ar -rc lib库名.a 目标文件 将目标文件打包成静态库 模拟库文件目录结构
创建include目录将头文件移动到该目录中创建lib目录将静态库移动到该目录中 将库打包成压缩包
使用tar -czf 目标压缩包名 源文件将库打包成压缩包 模拟使用静态库
将前文操作中打包好的静态库压缩包复制到某一目录下并解压来模拟库的下载过程 在当前目录下创建源文件main.c并编写调用静态库的代码具体代码实现如下
#include stdio.h
#include myadd.h
#include mysub.hint main()
{int x 20;int y 10;printf(%d %d %d\n, x, y, my_add(x, y));printf(%d - %d %d\n, x, y, my_sub(x, y));return 0;
}将源文件main.c编译形成可执行程序 由于第三方头文件不在编译的目录下需要-I 路径选项指明头文件路径由于第三方库编译器不会自己查找和使用需要-L 路径指明库文件路径名需要-l 库名指明库名。
总结一下Linux系统下第三方库的使用
需要指定头文件路径和库文件的路径和名称如果没有将头文件和库文件安装到编译器搜素的默认路径下用户必须指明对应选项 头文件路径 -I 路径库文件路径-L 路径库名-l 库名 安装头文件和库文件的本质是将文件拷贝至系统默认路径下。头文件和库文件安装后编译时需要指明库名选项
模拟编写动态库
在模拟编写动态库时沿用了前文中打包静态库使用的头文件myadd.h和其对应的源文件myadd.c和头文件mysub.h和其对应的源文件mysub.c。
将源文件进行编译
打包动态库时需要使用gcc -fPIC -c 源文件名将源文件编译成目标文件 将目标文件打包成动态库
使用gcc -shared -o lib库名.so 目标文件将目标文件打包成动态库 模拟库文件目录结构
创建include目录将头文件移动到该目录中创建lib目录将静态库移动到该目录中 将库打包成压缩包
使用tar -czf 目标压缩包名 源文件将库打包成压缩包 模拟使用静态库
将前文操作中打包好的动态库压缩包复制到某一目录下并解压来模拟库的下载过程 在当前目录下创建源文件main.c并编写调用静态库的代码具体代码实现如下
#include stdio.h
#include myadd.h
#include mysub.hint main()
{int x 20;int y 10;printf(%d %d %d\n, x, y, my_add(x, y));printf(%d - %d %d\n, x, y, my_sub(x, y));return 0;
}将源文件main.c编译形成可执行程序
指定动态库头文件的路径、库文件的路径和库名后编译器能够成功编译由于是动态库程序运行时需要OS根据程序内的动态库地址链接到动态库才能成功运行但是OS无法找到该动态库就造成了下图的情况 采用导入环境变量的方式使得程序运行临时方案
使用export LD_LIBRARY_PATHLD_LIBRARAY_PATH:动态库所在目录路径将动态库路径导入环境变量OS在运行程序时会从环境变量中的路径找到动态库并成功运行 解决第三方动态库OS查找不到的方法
导入环境变量使用export LD_LIBRARY_PATHLD_LIBRARAY_PATH:动态库所在目录路径将动态库路径导入环境变量环境变量会在重新打开shell时重新加载因此是临时方案在系统路径下建立动态库的软链接使用sudo ln -s 动态库路径 /lib64/lib库名.so将动态库的软链接添加到系统路径下修改配置文件在/etc/ld.so.conf.d/路径下创建后缀为.conf文件将静态库的路径写入该文件,然后使用sudo ldconfig使配置文件生效。
库的加载原理
静态库的加载原理
动态库的加载过程就是在形成可执行程序的链接过程中直接将静态库中的实现拷贝至可执行程序中。因此静态库十分占用资源磁盘、内存、网络资源。 动态库的加载原理
首先使用动态库生成可执行程序时在链接过程中可执行程序中只会将代表库中方法的外部符号替换成对应地址由于形成可执行程序中没有具体的实现因此要想运行起来操作系统做了一系列的工作在程序被加载到内存中形成进程后操作系统会为其维护进程控制块和进程地址空间和页表等 在进程运行到动态库中的方法后操作系统会在页表中寻找映射发现映射到内存中的只是一个对应地址而不是具体方法实现因此操作系统寻找这个动态库按照一定策略将动态库加载到内存中然后操作系统会将加载到内存中的动态库映射给进程地址空间中在栈区和堆区之间的共享区 而后每次该进程执行该库中方法时只需要跳转到进程地址空间中的共享区就可以完成程序的执行 另外当该库被加载到内存中后后续运行的进程需要执行该库方法时不需要再在内存中加载库而是直接创建共享区映射然后使用库中方法。
库在可执行程序中的编址策略
静态库在可执行程序中的编址策略
形成可执行程序时可执行程序中会存在逻辑地址如果采用的是静态库可执行程序中静态库的方法也会被编址获得一个逻辑地址在程序变成进程运行时只需要根据逻辑地址进行跳转即可。
动态库在可执行程序中的编址策略
形成可执行程序时可执行程序中会存在逻辑地址如果采用的是动态库可执行程序中动态库的方法也会被编址但该地址是库中方法在库中从起始地址开始的偏移量在制作动态库的获取目标文件的操作时使用gcc添加-fPIC就是获取这个被称为与地址无关码的地址偏移量在实际进程运行时进程只需要等待库中方法被加载到内存中并被映射到共享区然后利用共享区映射加上偏移地址完成运行。
说明一下
gcc/g编译器编译形成可执行程序时默认使用动态库。gcc/g编译器编译形成可执行程序时使用-static选项将使用静态库。gcc/g编译器编译形成可执行程序时部分动态库不存在会采用动态库混合使用的方式。