[Linux]动静态库

news2025/1/21 6:01:59

[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.coloradmin.cn/o/991271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

本地启动 Falcon-180B

本地启动 Falcon-180B 通过 Gradio 的 load 函数&#xff0c;我们可以在本地加载 HuggingFace 的 Spaces 上面的 demo。 那就运行 Falcon-180B 来试试吧。 创建 falcon_demo.py 文件&#xff0c; cat << EOF > falcon_demo.py import gradio as grdemo gr.load(&q…

小节3:数据类型

Python的数据类型包括&#xff1a;字符串&#xff08;str&#xff09;、整数&#xff08;int&#xff09;、浮点数&#xff08;float&#xff09;、布尔类型&#xff08;bool&#xff09;、空值类型&#xff08;NoneType&#xff09;、列表&#xff08;list&#xff09;、字典&…

Spring Cloud zuul与CloseableHttpClient连接池,TLS证书认证

前言 最近做项目&#xff0c;需要一个代理逻辑&#xff0c;实际上这种代理NGINX最好&#xff0c;但是有些额外功能的开发&#xff0c;NGINX就需要额外能力支持&#xff0c;比如lua脚本&#xff0c;常见的做法有kong&#xff0c;apisix等&#xff0c;据说apisix的性能较强&…

Python 03(循环语句)

Python03&#xff08;循环语句&#xff09; 文章目录 Python03&#xff08;循环语句&#xff09;一、while语句二、while实现猜数字三、while循环的嵌套while循环嵌套实例需求&#xff1a; 四、for循环1、什么 是for循环2、语法3、执行流程4、for循环的基本使用5、range()函数6…

光刻机的原理和技术路线概览

一、简介 集成电路产业被誉为现代“工业粮食”&#xff0c;引领未来科学技术产业革命的发展&#xff0c;带动世界前沿技术创新发展。 集成电路产业是社会发展的先导产业&#xff0c;主要包括半导体材料、装备、芯片制造、封装测试、电路设计等重要环节。 随着工业智能制造和电子…

OpenCV(三十):图像膨胀

1.图像膨胀原理 图像膨胀的原理是将一个结构元素&#xff08;也称为核或模板&#xff09;在图像上滑动&#xff0c;并将其与图像中对应位置的像素进行比较。如果结构元素的所有像素与图像中对应位置的像素都匹配&#xff0c;那么该位置的像素值保持不变。如果结构元素的任何一个…

Telnet

远程登录/管理 目录 1、什么是Telnet 2、Telnet工作原理 3、常见的Telnet使用场景 4、Telnet协议结构 5、Telnet工作流程 6、Telnet常见命令 6.1、[Huawei]user-interface ? 用户界面 6.2、[Huawei]user-interface vty ? 6.3、[Huawei-ui-vty0-4]? 6.4、[Huawei-…

软件测试技术题目大全【含答案】

请看下面 你的测试职业发展是什么?  测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&#x…

buuctf crypto 【[AFCTF2018]Morse】解题记录

1.打开文件 2.摩斯密码解密 3.这个结果验证之后发现不对&#xff0c;猜测是16进制转字符 4.验证发现是对的

直方图均衡化原理

import numpy as np import cv2 hist, bins np.histogram(img, bins256, range(0, 256))# 计算累积分布函数&#xff08;CDF&#xff09; cdf np.cumsum(hist)# 归一化CDF&#xff1a; 归一化CDF以确保其范围在0到255之间 cdf_norm 255 * (cdf - cdf.min()) / (cdf.max()…

提词软件有哪些?了解一下这几个

提词软件有哪些&#xff1f;提词软件可以广泛应用于各种场景。除了在学习和工作中提高效率外&#xff0c;在日常生活中也有很多用处。例如&#xff0c;在进行演讲的时候&#xff0c;如果担心会因为紧张而忘词的话&#xff0c;就可以使用一些提词软件&#xff0c;将演讲词编辑进…

使用P5.js来制作一个快乐的小风车动画

p5.js简介 前一段时间偶然了解到一个觉得很好玩儿的东西p5.js,于是就去了解了一下&#xff0c;发现可以自己设计一些有趣的动画效果&#xff0c;设计出来的动画可以放置到页面当中&#xff0c;而且也是简单易学的。 下面是一段官方的介绍&#xff1a; p5.js是一个以 Processi…

0016Java程序设计-springboot幼儿园管理系统

摘 要目 录系统设计开发环境 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于幼儿园管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了幼儿园管理系统&a…

从JVM角度看继承

从JVM角度看继承 最近重读了周志明老师的《深入理解JAVA虚拟机》一书&#xff0c;看完大有收获&#xff0c;但仍对继承情况下对象内存布局有所疑惑&#xff0c;所以查阅资料&#xff0c;结合本书进行分析 参考文档&#xff1a; 【深入理解JVM】&#xff1a;Java类继承关系中…

算法训练营day45|动态规划 part07:完全背包 (LeetCode 70. 爬楼梯(进阶)、322. 零钱兑换、279.完全平方数)

文章目录 70. 爬楼梯(进阶)(求排列方法数)思路分析代码实现 322. 零钱兑换(求等于背包重量的最小物品数)思路分析代码实现思考总结 279.完全平方数 (求等于背包重量的最小物品数)思路分析代码实现 70. 爬楼梯(进阶)(求排列方法数) 题目链接&#x1f525; 假设你正在爬楼梯。需…

jquery jstree的懒加载

效果如下 使用jquery的jstree组件 1.前端准备工作 1.1引入jstree样式和js <link rel"stylesheet" href"/public/vendor/jstree/jstree.css"> <div id"departmentJstree"></div> <script src"/public/vendor/jstree…

Dominosa/数邻(2) | C++ | BFS

目录 一、Dominosa简介二、题目描述三、编程思路四、完整代码 一、Dominosa简介 Dominosa&#xff0c;中文名称为数邻&#xff0c;是一种棋盘游戏&#xff0c;基于骨牌的排列和匹配来进行。它是从骨牌游戏中发展而来的&#xff0c;在骨牌的基础上添加了一些规则和难度。具体的游…

canape中快速配置需要录制参数的技巧

以前在车里录制数据时&#xff0c;大量融合数据一个一个拖拽 &#xff0c;不仅慢&#xff0c;有时心不细的话&#xff0c;还会漏选、挑错。 用正则表达式的挑选方法&#xff0c;可以既快速又准确的挑出所需数据。 以下蓝色字体是操作方法&#xff1a; 正则表达式 示例&#xff…

QTableView通过setColumnWidth设置了列宽无效的问题

在用到QT的QTableView时&#xff0c;为了显示效果&#xff0c;向手动的设置每一列的宽度&#xff0c;但是如下的代码是无效的。 ui->tableView->setColumnWidth(0,150);ui->tableView->setColumnWidth(1,150);ui->tableView->setColumnWidth(2,150);ui->t…

docker-compose安装nginx

基于docker-compose安装nginx 目录 一、目录结构 1、docker-compose.yml 2、nginx.conf 3、default.conf 4、index.html 二、访问测试 一、目录结构 1、docker-compose.yml version: 3 services:nginx:image: registry.cn-hangzhou.aliyuncs.com/zhengqing/nginx:1.21.1…