[Linux]动静态库

[Linux]动静态库

文章目录

  • [Linux]动静态库
    • 见一见库
    • 存在库的原因
    • 编写库
      • 模拟编写静态库
      • 模拟使用静态库
      • 模拟编写动态库
      • 模拟使用静态库
    • 库的加载原理
      • 静态库的加载原理
      • 动态库的加载原理
    • 库在可执行程序中的编址策略
      • 静态库在可执行程序中的编址策略
      • 动态库在可执行程序中的编址策略

见一见库

在Linux系统中,C语言标准库(C Standard Library)和其他常用库都被称为C库(C library),通常存放在/usr/lib/usr/lib64目录下:

image-20230907132423757

在Linux系统中,/usr/include目录下存放了许多头文件:

image-20230907132557509

  • Linux系统预装了C/C++的头文件和库文件,头文件提供方法的说明,库文件提供方法的实现,头文件和库文件有对应关系,需要组合使用。
  • 在程序编译形成可执行程序的过程中,头文件在预处理时被引入,库文件在链接时被链接 。
  • 在visual studio下安装开发环境时,不仅安装了编译器软件,还安装语言对应的头文件和库文件。
  • 编译器会自动根据用户的输入,查找头文件中的相关内容,实现语法提示的功能。
  • 编译器会自动根据用户的输入,不断地进行编译,实现语法报错的功能。

存在库的原因

编程语言将常用的功能添加到库中,以便于用户可以直接使用这些功能,提高开发的效率。比如printf,用户不需要在每次想打印数据时,编写一个用于打印数据的函数。

编写库

模拟编写静态库

进行库的编写前要说明一下:

  • 库分为动态库和静态库
  • Linux下静态库的命名规则:lib库名.a
  • Linux下动态库的命名规则:lib库名.so
  • 云服务下一般不会内置静态库
  1. 头文件和源文件的编写

编写头文件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; 
}
  1. 将源文件编译成目标文件

使用gcc -c 源文件名将源文件编译成目标文件:

image-20230907162247874

  1. 打包成静态库

使用ar -rc lib库名.a 目标文件 将目标文件打包成静态库:

image-20230907162355901

  1. 模拟库文件目录结构

创建include目录将头文件移动到该目录中,创建lib目录将静态库移动到该目录中:

image-20230907162516768

  1. 将库打包成压缩包

使用tar -czf 目标压缩包名 源文件将库打包成压缩包:

image-20230907162735301

模拟使用静态库

  1. 将前文操作中打包好的静态库压缩包复制到某一目录下并解压来模拟库的下载过程

image-20230907164341754

  1. 在当前目录下创建源文件main.c并编写调用静态库的代码,具体代码实现如下:
#include <stdio.h>
#include "myadd.h"
#include "mysub.h"int 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;
}
  1. 将源文件main.c编译形成可执行程序:

image-20230907165017051

由于第三方头文件不在编译的目录下,需要-I 路径选项指明头文件路径,由于第三方库编译器不会自己查找和使用,需要-L 路径指明库文件路径名,需要-l 库名指明库名。

总结一下Linux系统下第三方库的使用:

  • 需要指定头文件路径和库文件的路径和名称
  • 如果没有将头文件和库文件安装到编译器搜素的默认路径下,用户必须指明对应选项:
    • 头文件路径 (-I 路径
    • 库文件路径(-L 路径
    • 库名(-l 库名
  • 安装头文件和库文件的本质是将文件拷贝至系统默认路径下。
  • 头文件和库文件安装后,编译时需要指明库名选项

模拟编写动态库

在模拟编写动态库时,沿用了前文中打包静态库使用的头文件myadd.h和其对应的源文件myadd.c和头文件mysub.h和其对应的源文件mysub.c。

  1. 将源文件进行编译

打包动态库时需要使用gcc -fPIC -c 源文件名将源文件编译成目标文件:

image-20230907173438259

  1. 将目标文件打包成动态库

使用gcc -shared -o lib库名.so 目标文件将目标文件打包成动态库:

image-20230907173847412

  1. 模拟库文件目录结构

创建include目录将头文件移动到该目录中,创建lib目录将静态库移动到该目录中:

image-20230907174146799

  1. 将库打包成压缩包

使用tar -czf 目标压缩包名 源文件将库打包成压缩包:

image-20230907174229960

模拟使用静态库

  1. 将前文操作中打包好的动态库压缩包复制到某一目录下并解压来模拟库的下载过程

image-20230907184457085

  1. 在当前目录下创建源文件main.c并编写调用静态库的代码,具体代码实现如下:
#include <stdio.h>
#include "myadd.h"
#include "mysub.h"int 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;
}
  1. 将源文件main.c编译形成可执行程序:

指定动态库头文件的路径、库文件的路径和库名后,编译器能够成功编译,由于是动态库,程序运行时需要OS根据程序内的动态库地址链接到动态库才能成功运行,但是OS无法找到该动态库,就造成了下图的情况:

image-20230907184623458

  1. 采用导入环境变量的方式使得程序运行(临时方案)

使用export LD_LIBRARY_PATH=LD_LIBRARAY_PATH:动态库所在目录路径将动态库路径导入环境变量,OS在运行程序时会从环境变量中的路径找到动态库并成功运行:

image-20230907185214813

解决第三方动态库OS查找不到的方法:

  1. 导入环境变量:使用export LD_LIBRARY_PATH=LD_LIBRARAY_PATH:动态库所在目录路径将动态库路径导入环境变量,环境变量会在重新打开shell时重新加载,因此是临时方案
  2. 在系统路径下建立动态库的软链接:使用sudo ln -s 动态库路径 /lib64/lib库名.so将动态库的软链接添加到系统路径下
  3. 修改配置文件:在/etc/ld.so.conf.d/路径下创建后缀为.conf文件,将静态库的路径写入该文件,然后使用sudo ldconfig使配置文件生效。

库的加载原理

静态库的加载原理

动态库的加载过程就是在形成可执行程序的链接过程中直接将静态库中的实现拷贝至可执行程序中。因此静态库十分占用资源(磁盘、内存、网络资源)。

动态库的加载原理

首先,使用动态库生成可执行程序时,在链接过程中,可执行程序中只会将代表库中方法的外部符号替换成对应地址,由于形成可执行程序中没有具体的实现,因此要想运行起来,操作系统做了一系列的工作,在程序被加载到内存中形成进程后,操作系统会为其维护进程控制块和进程地址空间和页表等:

image-20230908133542761

在进程运行到动态库中的方法后,操作系统会在页表中寻找映射,发现映射到内存中的只是一个对应地址而不是具体方法实现,因此操作系统寻找这个动态库,按照一定策略将动态库加载到内存中,然后操作系统会将加载到内存中的动态库映射给进程地址空间中在栈区和堆区之间的共享区:

image-20230908133642887

而后,每次该进程执行该库中方法时,只需要跳转到进程地址空间中的共享区,就可以完成程序的执行:

image-20230908133705099

另外,当该库被加载到内存中后,后续运行的进程需要执行该库方法时,不需要再在内存中加载库,而是直接创建共享区映射,然后使用库中方法。

库在可执行程序中的编址策略

静态库在可执行程序中的编址策略

形成可执行程序时,可执行程序中会存在逻辑地址,如果采用的是静态库,可执行程序中静态库的方法也会被编址,获得一个逻辑地址,在程序变成进程运行时,只需要根据逻辑地址进行跳转即可。

动态库在可执行程序中的编址策略

形成可执行程序时,可执行程序中会存在逻辑地址,如果采用的是动态库,可执行程序中动态库的方法也会被编址,但该地址是库中方法在库中从起始地址开始的偏移量,在制作动态库的获取目标文件的操作时,使用gcc添加-fPIC就是获取这个被称为与地址无关码的地址偏移量,在实际进程运行时,进程只需要等待库中方法被加载到内存中并被映射到共享区,然后利用共享区映射加上偏移地址完成运行。

说明一下:

  • gcc/g++编译器编译形成可执行程序时,默认使用动态库。
  • gcc/g++编译器编译形成可执行程序时,使用-static选项,将使用静态库。
  • gcc/g++编译器编译形成可执行程序时,部分动态库不存在,会采用动态库混合使用的方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/103277.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TinTin Web3 动态精选:以太坊基金会推出 EELS、Arbitrum Stylus 上线

TinTin 快讯由 TinTinLand 开发者技术社区打造&#xff0c;旨在为开发者提供最新的 Web3 新闻、市场时讯和技术更新。TinTin 快讯将以周为单位&#xff0c; 汇集当周内的行业热点并以快讯的形式排列成文。掌握一手的技术资讯和市场动态&#xff0c;将有助于 TinTinLand 社区的开…

YOLO目标检测——红火蚂蚁识别数据集+已标注yolo格式标签下载分享

实际项目应用&#xff1a;目标检测红火蚂蚁识别数据集在农业、生态学、环境保护、城市管理和学术研究等领域都有着广泛的应用。通过准确识别和定位红火蚂蚁&#xff0c;可以帮助我们更好地了解和管理这一入侵物种&#xff0c;从而减少其对环境和经济的负面影响。数据集说明&…

基于Docker从零到一实操MySql的主从复制

文章目录 一、在Docker上安装&#xff0c;启动MySQL查看docker是否安装成功安装mysql查看mysql镜像进入mysql后台操作docker Volume&#xff08;卷&#xff09;入门 MySql的主从复制1. 创建MySQL主从复制的网络2. 创建MySQL主服务器3. 创建MySQL从服务器4. 配置主从同步5.测试主…

Activiti7工作流引擎:在线流程编辑器Activiti Modoler5.x

一&#xff1a;简介 有的时候我们的流程图需要业务人员自己绘制&#xff0c;然后使用自己绘制的流程图&#xff0c;此时就需要一个在线流程图编辑器需要集成到我们的web系统中。Activiti Modoler是Activiti官方推出的在线流程编辑器。 二&#xff1a;pom.xml <dependency…

Python - 队列【queue】task_done()和join()基本使用

一. 前言 task_done()是Python中queue模块提供的方法&#xff0c;用于通知队列管理器&#xff0c;已经处理完了队列中的一个项目。 queue.task_done()是Queue对象的一个方法&#xff0c;它用于通知Queue对象&#xff0c;队列中的某一项已经被处理完毕。通常在使用Queue对象时…

电脑磁盘分区形式是什么?如何更改?

磁盘分区形式介绍 在了解为什么以及如何更改分区形式之前&#xff0c;让我们对磁盘分区形式有一个基本的了解。一般来说&#xff0c;分区形式是指主引导记录&#xff08;MBR&#xff09;和 GUID 分区表&#xff08;GPT&#xff09;。 MBR和GPT是Windows系统中常用…

洛谷 LGR SCP-J 2023 c++语言模拟试题 10. 以下程序片段的时间复杂度为( )

之前在牛客的一个群中看到有位哥们发的题 好像是洛谷哪次的模拟题&#xff0c;还写着什么 LGR SCP-J 2023 c语言模拟试题 题目 就是给段代码询问时间复杂度 for (int i1; i<n; i){for (int j1; j<n; ji){for (int k1; k<n; k j){}} } 跑代码 一开始想不出怎么解就…

【CMake工具】工具CMake编译轻度使用(C/C++)

目录 CMake编译工具 一、CMake概述 二、CMake的使用 2.1 注释 2.1.1 注释行 2.1.2 注释块 2.2 源文件 2.1.1 共处一室 2.1.2 VIP包房 2.3 私人定制 2.2.1 定义变量 2.2.2 指定使用的C标准 2.2.3 指定输出的路径 2.4 搜索文件 2.3.1 方式1 2.3.2 方式2 2.5 包含…

岩土工程安全监测利器:振弦采集仪的发展

岩土工程安全监测利器&#xff1a;振弦采集仪的发展 岩土工程安全监测是保障建筑物、地下工程和地质环境安全稳定运行的重要手段。传统上&#xff0c;监测手段主要依靠人工巡视以及基础设施安装的传感器&#xff0c;但是这些方法都存在着缺陷。人工巡视存在的问题是数据采集精…

云原生Kubernetes:pod基础

目录 一、理论 1.pod 2.pod容器分类 3.镜像拉取策略&#xff08;image PullPolicy&#xff09; 二、实验 1.Pod容器的分类 2.镜像拉取策略 三、问题 1.apiVersion 报错 2.pod v1版本资源未注册 3.取行显示指定pod信息 四、总结 一、理论 1.pod (1) 概念 Pod是ku…

CASAIM与南京航空航天大学在自动化叶片曲面分析系统开展合作,推动航空航天发动机零部件自动化3D检测进程

近期&#xff0c;CASAIM与南京航空航天大学在自动化叶片曲面分析系统展开深入合作&#xff0c;充分发挥双方在航空航天和智能检测领域优势&#xff0c;共同推动航空航天发动机零部件自动化3D检测进程。 南京航空航天大学创建于1952年10月&#xff0c;是新中国自己创办的第一批…

软考高级架构师下篇-14面向服务架构设计理论

目录 1. 引言2. SOA的相关概念3. SOA的发展历史4. SOA的参考架构5. SOA 主要协议和规范6. SOA设计的标准要求7. SOA的作用与设计原则8. SOA的设计模式9. SOA构建与实施10. 前文回顾1. 引言 在面向服务的体系结构(Service-Oriented Architecture,SOA)中,服务的概念有了延伸…