[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.rhkb.cn/news/126250.html

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

相关文章

储能直流侧计量表DJSF1352

安科瑞 华楠 具有CE/UL/CPA/TUV认证 DJSF1352-RN导轨式直流电能表带有双路直流输入&#xff0c;主要针对电信基站、直流充电桩、太阳能光伏等应用场合而设计&#xff0c;该系列仪表可测量直流系统中的电压、电流、功率以及正反向电能等。在实际使用现场&#xff0c;即可计量总…

LT8711HE 是一款高性能的Type-C/DP1.2到HDMI2.0转换器

概述&#xff1a; LT8711HE是一种高性能的Type-C/DP1.2到HDMI2.0转换器&#xff0c;设计用于连接USB Type-C源或DP1.2源到HDMI2.0接收器。LT8711HE集成了一个DP1.2兼容的接收器&#xff0c;和一个HDMI2.0兼容的发射机。此外&#xff0c;还包括两个CC控制器&#xff0c;用于CC通…

自然语言处理——数据清洗

一、什么是数据清洗 数据清洗是指发现并纠正数据文件中可识别的错误的最后一道程序&#xff0c;包括检查数据一致性&#xff0c;处理无效值和缺失值等。与问卷审核不同&#xff0c;录入后的数据清理一般是由计算机而不是人工完成。 ——百度百科 二、为什么要数据清洗 现实生…

bboss 流批一体化框架 与 数据采集 ETL

数据采集 ETL 与 流批一体化框架 特性&#xff1a; 高效、稳定、快速、安全 bboss 是一个基于开源协议 Apache License 发布的开源项目&#xff0c;主要由以下三部分构成&#xff1a; Elasticsearch Highlevel Java Restclient &#xff0c; 一个高性能高兼容性的Elasticsea…

java开发之个人微信的二次开发

简要描述&#xff1a; 修改我在某群的昵称 请求URL&#xff1a; http://域名/updateIInChatRoomNickName 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参…

Python标准数据类型-List(列表)

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;零基础入门篇 &#x1f4ac;个人格言&#xff1a;不断的翻越一座…

备份StarRocks数据到对象存储minio中/外表查minio中的数据

1.部署minio环境 docker pull minio/minio宿主机与容器挂在映射 宿主机位置容器位置/data/minio/config/data/data/minio/data/root/.minio 拉起环境&#xff1a; docker run -p 9000:9000 -p 9090:9090 --name minio \ -d --restartalways \ -e "MINIO_ACCESS_KEYadm…

基于Dubbo实现服务的远程调用

目录 前言 RPC思想 为什么使用Dubbo Dubbo技术框架 ​编辑 调用关系流程 基础实现 A.提供统一业务Api B.编辑服务提供者Product B.a 添加依赖 B.b 添加Dubbo 配置(基于yaml配置文件) B.c 编写并暴露服务 C.编辑服务消费者 C.a 添加依赖 C.b 添加Dubbo配置 C.c 引用…

使用正则表达式总结

多行匹配 使用Pattern.DOTALL | Pattern.MULTILINE参数 Pattern.CASE_INSENSITIVE&#xff1a;不区分大小写 public static void main(String[] args) {String teststr "AA aa AASSF \n\r */ DDET AA";String regStr "(?AA)\\w\\b";extracted(testst…

网络威胁防御+资产测绘系统-Golang开发

NIPS-Plus 网络威胁防御资产测绘系统-Golang开发 项目地址&#xff1a;https://github.com/jumppppp/NIPS-Plus NIPS-Plus 是一款使用golang语言开发的网络威胁防御系统&#xff08;内置资产测绘系统&#xff09; 网络威胁流量视图网络威胁详细信息浏览列表网络威胁反制探测攻…

C++ std::pair and std::list \ std::array

std::pair<第一个数据类型, 第二个数据类型> 变量名 例如&#xff1a; std::pair<int, string> myPair; myPair.first;拿到第一个int变量 myPair.second拿到第二个string变量 std::pair需要引入库#include "utility" std::make_pair() 功能制作一个…

数控程序传输DNC服务、数控刀补服务(发那科fanuc、西门子、三菱、广数、新代、华中、宝元、马扎克、大畏Okuma)等数据采集服务

行业现状&#xff1a; 最近听到很多做MES、ERP这一行的叫苦&#xff0c; 客户对项目的要求越来越严格&#xff0c;做到数字化工厂都伴随着ERP、MES的项目要求必须一起做下去 然而很对MES、ERP对设备协议不懂&#xff0c;买了协议自己还要开发&#xff0c;考虑线程的问题、断…

syn洪流原理

TCP三次握手 建立连接发送或回应第一次握手客户端发送报文&#xff0c;标志位为SYN&#xff08;seqa&#xff09;第二次握手服务器发送报文&#xff0c;标志位为SYN&#xff0c;ACK&#xff08;seqb,acka1&#xff09;第三次握手客户端回应服务器报文&#xff0c;标志位为ACK&…

Unity 之 Invoke 与InvokeRepeting 函数控制定时调用

文章目录 InvokeInvokeRepeating Invoke 在Unity游戏开发中&#xff0c;Invoke是一种用于延迟调用方法的方法。它允许你在一定的时间之后执行特定的函数或方法&#xff0c;通常用于执行定时任务&#xff0c;例如在一段时间后触发一个事件或在一定间隔内重复执行某个方法。Invo…

图的应用(最小生成树,最短路径,有向无环图)

目录 一.最小生成树 1.生成树 2.无向图的生成树 3.最小生成树算法 二.最短路径 1.单源最短路径---Dijkstra&#xff08;迪杰斯特拉&#xff09;算法 2.所有顶点间的最短路径---Floyd&#xff08;弗洛伊德&#xff09;算法 三.有向无环图的应用 1.AOV网&#xff08;拓扑…

Opencv手工选择图片区域去水印

QT 插件化图像算法研究平台的功能在持续完善&#xff0c;补充了一个人工选择图片区域的功能。 其中&#xff0c;图片选择功能主要代码如下&#xff1a; QRect GLImageWidget::getSeleted() {QRect ajust(0,0,0,0);if(image.isNull() || !hasSelection)return ajust;double w1…

智能小车之测速小车原理和开发

目录 1. 测速模块介绍 2. 测试原理和单位换算 3. 定时器和中断实现测速开发和调试代码 4. 小车速度显示在OLED屏 1. 测速模块介绍 用途&#xff1a;广泛用于电机转速检测&#xff0c;脉冲计数,位置限位等。有遮挡&#xff0c;输出高电平&#xff1b;无遮挡&#xff0c;输出…

算法通过村第六关-树青铜笔记|中序后序

文章目录 前言1. 树的常见概念2. 树的性质3. 树的定义与存储方式4. 树的遍历方式5. 通过序列构建二叉树5.1 前中序列恢复二叉树5.2 中后序列恢复二叉树 总结 前言 提示&#xff1a;瑞秋是个小甜心&#xff0c;她只喜欢被爱&#xff0c;不懂的去爱人。 --几米《你们 我们 他们》…

基础算法--理解递归

理解递归 递归的两个特点 调用自身结束条件 举个从小就听过的例子&#xff1a; 1. 从前有座山&#xff0c;山中有座庙&#xff0c;庙里有个老和尚&#xff0c;老和尚在给小和尚讲故事&#xff1a;2. 从前有座山&#xff0c;山中有座庙&#xff0c;庙里有个老和尚&#xff0c;…

JAVA实现SAP接口

JAVA实现SAP接口 环境spring-bootmaven 1.maven依赖 <dependency><groupId>com.github.virtualcry</groupId><artifactId>sapjco-spring-boot-starter</artifactId><version>3.1.4</version></dependency>2.配置文件 applic…