【Linux】—— 详解动态库和静态库

news2024/11/29 16:29:26

前言:

  • 本期我将要给大家讲解的是有关 动态库和静态库 的相关知识!!!

目录

序言

见一见库

为什么要有库 

(一)动态库(.so)

1.基本概念

2.命名规则

3.制作动态库 

(二)静态库(.a)

1.基本概念

2.命名规则

3.制作静态库 

(三)什么叫 fPIC

(四)对比静态库和动态库

总结


序言

见一见库

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)动态库(.so、.dll)

  • 所谓静态、动态是指链接。简单回顾一下将一个程序编译成可执行程序的步骤:

在正式的讲解动态库和静态库之前,我们先带带大家认识我们平时写 C/C++代码时用到的库

  •  " ls /usr/lib64/libc* ” 这个命令用于列出匹配模式 "libc*" 的文件或目录

  •  其次,我们也可以去查看平时我们经常用到的:

【解释说明】

  1. 系统已经预装了C/C++的头文件和库文件,头文件提供方法说明,库提供方法的实现,头和库是有对应关系的,是要组合到一起使用的;
  2. 头文件是在预处理阶段装入的,链接本质其实就是链接库!!!


为什么要有库 

其实这一点大家都能理解(造轮子和用轮子的问题):

  1. 库是一组预先编写好的代码、程序或函数的集合,用于解决特定类型问题或提供特定功能;
  2. 这些代码通常被封装成模块,以便在开发软件时能够重用、共享和简化代码。

在我们学习阶段大家可以更多的尝试去造轮子,熟悉其中的一些思想及其方法等,等到大家上班的就是 “用轮子” 的较多了。


(一)动态库.so

1.基本概念

  • 动态库是一种在运行时加载和链接的库文件;
  • 与静态库相比,动态库在程序执行之前不会被完全链接到可执行文件中,而是在运行时被动态地加载到内存并链接。

2.命名规则

在命名动态库时,通常会遵循一定的命名规则以确保一致性和可读性。以下是一些常见的动态库命名规则:

  1. 前缀:动态库名称通常以lib开头作为前缀,表示这是一个库文件。

  2. 中间部分:中间部分通常是描述库的名称或功能的字母数字组合。可以根据库的用途或模块来命名,以便更好地理解其功能。建议使用小写字母和下划线进行命名,以增加可读性。

  3. 扩展名:动态库的扩展名取决于操作系统和平台。在Linux上,通常是.so(共享对象);在Windows上,通常是.dll(动态链库);在Mac上,通常是.dylib(动态库)。

💨 综合起来,一个典型的动态库命名可能如下所示: 


3.制作动态库 

在Linux系统上创建动态库(也称为共享库或.so文件)涉及编写、编译和链接一组源代码文件,以生成可在多个应用程序之间共享的动态链接库。

以下是创建Linux动态库的一般步骤:

1️⃣编译源代码

使用编译器将源代码编译成位置无关的目标文件,通常使用.o文件扩展名。为了生成动态库,需要使用 -fPIC 选项(位置无关代码)来确保目标文件可以在内存中加载并重定位。

  • 例如,在Linux系统上,可以使用gcc编译器编译一个源文件并生成位置无关的目标文件: 


2️⃣创建动态库

使用共享库工具(gcc也可以用于此)将目标文件链接到一个共享库文件中。通常,Linux动态库的命名约定是以.so结尾,并且通常有版本号。

  • 以下是创建动态库的示例,命名为 libmymath.so


3️⃣运行代码:

我这里是把文件打包拷贝到 【otherPerson】目录下执行:

💨 紧接着执行:gcc -o mytest main.c (发现报错了!!)

 【解释说明】

  • 因为在当前路径下头文件并没有找到,因为并没有进行安装

💨 接下来,再次执行:gcc -o mytest main.c -I include (发现还是报错了!!)

【解释说明】

  • 因为在当前路径下库并没有找到

💨 接下来,再次执行:gcc -o mytest main.c -I include -L lib(发现还是报错了!!)

💨 接下来,再次执行:gcc -o mytest main.c -I include -L lib -lmymath(发现还是报错了!!)

这次,我们发现程序正常运行成功了。紧接着,我们执行相应的文件:

 【解释说明】

  • 此时,有的小伙伴可能就比较疑惑:“我不是已经告诉了系统,我的库在哪里并且告诉叫什么了吗?为什么还是找不到呢?”
  • 其实,gcc时只是告诉了编译器,而没有真正的告诉操作系统!运行的时候因为我的 .so 并不是在默认的路径下,所以os 依旧找不到!!


⭐️ 如何让系统能够找到动态库:

  • 1、通过环境变量(临时方案)

环境变量中确实没有我们当前的路径,因此第一种解决方法就是把我们当前的路径加入到系统的环境变量中。具体如下:

但是,这个方法是临时性的,当我们重新打开去运行时就失效了:


  • 2、指定路径下建立软链接(永久版本)


  • 3、配置文件方案

在配置之前,需要先把上述使用软链接创建的删除掉:

💨如果安装在其他目录,需要将其添加到/etc/ld.so.conf.d/文件中,步骤如下:

1.前期准备

2.编辑/etc/ld.so.conf文件,加入库文件所在目录的路径

 3.运行ldconfig ,该命令会重建/etc/ld.so.conf.d/文件


(二)静态库.a

1.基本概念

  1. 静态库是一种在编译时链接到可执行程序的库文件形式;
  2. 它是由一组预编译的目标文件(Object File)组成,其中包含了函数、变量和其他可重用的代码和数据。

💨 需要注意一点:库云服务器默认没有静态!!!


2.命名规则

在 Linux 上,静态库的命名规则通常是:

lib<library_name>.a

其中:

  • lib 是固定的前缀,表示这是一个库文件。
  • library_name 表示该库的名称或功能,建议使用小写字母和下划线进行命名,以增加可读性。
  • .a 是静态库的扩展名,表示这是一个归档文件 (archive file)。静态库通常以 .a 作为扩展名。

💨 综合起来,一个典型的动态库命名可能如下所示: 


3.制作静态库 

创建静态库涉及编写、编译和打包一组代码文件,以便它们可以在其他程序中静态链接和重用。

以下是创建静态库的一般步骤:

  • 1、编写使用创建的静态库的测试代码:
/myadd.h/
     #ifndef __ADD_H__
     #define __ADD_H__ 
     int add(int a, int b); 
     #endif // __ADD_H__

 /myadd.c/
 #include "myadd.h"
 int add(int a, int b)
 {
     return a + b;
 }

 /mysub.h/
     #ifndef __SUB_H__
     #define __SUB_H__ 
     int mysub(int a, int b); 
     #endif // __SUB_H__

 /mysub.c/
 #include "mysub.h"
 int sub(int a, int b)
 {
     return a - b;
 }

 ///main.c
 #include <stdio.h>
 #include "myadd.h"
 #include "mysub.h"
 
 int main()
 {
     int a = 10;
     int b = 3;
     printf("add(10, 3)=%d\n", a, b, add(a, b));
     printf("add(10, 3)=%d\n", a, b, sub(a, b));
     
     return 0;
 }
  • 2、使用编译器将源代码编译成目标文件(通常是中间代码文件),编译时,使用适当的编译选项以确保生成的目标文件是可链接的(注意带参数-c,否则直接编译为可执行文件

  • 3、然后,通过ar工具将目标文件打包成.a静态库文件

【注意】 

  •  大一点的项目会编写makefile文件(CMake等等工程管理工具)来生成静态库,输入多个命令太麻烦了

  • 4、Linux下使用静态库,只需要在编译的时候,指定静态库的搜索路径(-L选项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)

【注意】

  •  -L:表示要连接的库所在目录
  •  -l:指定链接时需要的动态库,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a或.so来确定库的名称。

【小结】

  1. 创建静态库涉及编写、编译、打包目标文件,然后将静态库链接到其他程序中;
  2. 这种方法适用于小型项目,或者当需要确保可执行文件与特定版本的库一起分发时;
  3. 但需要注意的是,静态库会增加可执行文件的大小,并且不支持动态更新。如果需要更大的灵活性和共享性,可以考虑使用动态库。 

(三)什么叫 fPIC

fPIC 是 GCC编译器的一个选项,用于生成位置无关代码(Position Independent Code,PIC)。位置无关代码是一种可以在内存中加载并且不受加载地址限制的代码,因此适合用于创建共享库(动态链接库,也称为.so文件)以及在多个进程之间共享的代码。 

  • 我们以下图进行分析: 

【解释说明】

  1. 当一个库真正的映射到地址空间的时候,它的起始地址才能真正的被确定下来!而它的库在形成的时候并不是使用的绝对地址,而是使用的相对于起始地址的偏移量;
  2. 有了上述这样的方法,使得动态库在进程的地址空间中能够随便的进行加载,而与我们加载到地址空间的什么位置毫无关系。因为OS是知道起始地址的,因此在我们链接时只需把对应的偏移量加载进来,OS根据起始地址 + 偏移量的操作即可完成相应的地址映射;
  3. 上述这样的库就称为动态库,这种库中的地址就称为 fPIC。

(四)对比静态库和动态库

动态库和静态库是两种不同的库文件类型,它们在编程和软件开发中有着重要的区别。以下是它们之间的主要区别:

  1. 加载时机:

    • 静态库:在编译时将库的代码和数据链接到可执行文件中,形成一个单独的可执行文件。这意味着库的代码在程序运行之前已经完全被包含在可执行文件中。
    • 动态库:库的代码和数据在程序运行时才被加载到内存中。可执行文件包含了对库的引用,但实际的库代码在程序启动时或首次使用时才会被加载。
  2. 文件大小:

    • 静态库:由于库的代码被完全复制到每个可执行文件中,因此可执行文件通常比较大。
    • 动态库:多个可执行文件可以共享相同的库,因此动态库可以减小可执行文件的大小。
  3. 内存占用:

    • 静态库:每个运行的程序实例都包含库的一个拷贝,因此可能会占用更多的内存。
    • 动态库:多个程序实例可以共享同一个库的实例,节省内存。
  4. 可扩展性:

    • 静态库:每次引入新的库版本都需要重新编译和链接,不够灵活。
    • 动态库:可以在不修改可执行文件的情况下,替换或升级库的版本,提供更好的可扩展性。
  5. 加载速度:

    • 静态库:由于库的代码已经包含在可执行文件中,因此加载速度较快。
    • 动态库:需要在运行时加载,可能会略微减慢程序启动速度。

总结

以上便是本文关于动静态的全部内容了。接下来,简单的回顾总结一下!!

  1. 动态库和静态库各自有其优势和劣势,具体选择取决于项目的需求和设计考虑;
  2. 通常,动态库在节省内存、库的更新和维护方面更有优势,而静态库在加载速度和跨平台兼容性方面更有优势

 

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

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

相关文章

No155.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【KingbaseES】银河麒麟V10 ARM64架构_安装人大金仓数据库KingbaseES_V8R6(CentOS8)

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

C# 类型、变量与对象

变量一共7种&#xff1a; 静态变量&#xff08;静态字段&#xff09;、实例变量&#xff08;成员变量、字段&#xff09;、数组元素、值参数、引用参数、输出形参、局部变量 狭义的变量就是局部变量 内存的最小单位是比特&#xff08;byte&#xff09;&#xff0c;8个比特为…

【数据结构】【C++】封装哈希表模拟实现unordered_map和unordered_set容器

【数据结构】&&【C】封装哈希表模拟实现unordered_map和unordered_set容器 一.哈希表的完成二.改造哈希表(泛型适配)三.封装unordered_map和unordered_set的接口四.实现哈希表迭代器(泛型适配)五.封装unordered_map和unordered_set的迭代器六.解决key不能修改问题七.实…

Stm32_标准库_5_呼吸灯_按键控制

Stm32按键和输出差不多 PA1为LED供给正电&#xff0c;PB5放置按键&#xff0c;按键一端接PB5,另一端接负极 void Key_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //APB2总线连接着GPIOBGPIO_InitStructur.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructur.…

Java下对象的序列化和反序列化(写出和读入)

代码如下&#xff1a; public class MyWork {public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化File f new File("testFile/testObject.txt");ObjectOutputStream oos new ObjectOutputStream(new FileOutputStream(…

数据结构:堆的实现和堆排序及TopK问题

文章目录 1. 堆的概念和性质1.1 堆的概念1.2 堆的性质1.3 堆的作用 2. 堆的声明3. 堆的实现3.1 堆的插入3.2 删除堆顶元素3.3 利用数组建堆3.4 完整代码 4. 堆的应用4.1 堆排序4.2 TopK问题代码实现 物理结构有顺序结构存储和链式结构存储两种,二叉树理所应当也是可以顺序结构存…

实时通信协议

本文旨在简要解释如何在Web上实现客户端/服务器和客户端/客户端之间的实时通信&#xff0c;以及它们的内部工作原理和最常见的用例。 TCP vs UDP TCP和UDP都位于OSI模型的传输层&#xff0c;负责在网络上传输数据包。它们之间的主要区别在于&#xff0c;TCP在传输数据之前会打开…

26960-2011 半自动捆扎机 学习笔记

声明 本文是学习GB-T 26960-2011 半自动捆扎机. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了半自动捆扎机(以下简称"捆扎机")的术语和定义、型号、型式与基本参数、技术要求、 试验方法、检验规则及标志、包装、运…

Python变量的三个特征

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 我们来看这些代码 x 10 print(x) # 获取变量的变量值 print(id(x)) # 获取变量的id&#xff0c;可以理解成变量在内存中的地址python的内置功能id()&#xff0c;内存地址不一样&#xff0c;则id()后打印的结果不一样&…

【HTML】表格行和列的合并

概述 当我们需要在 HTML 表格中展示复杂的数据时&#xff0c;行和列的合并可以帮助我们实现更灵活的布局和结构。通过合并行和列&#xff0c;我们可以创建具有更多层次和结构的表格&#xff0c;使数据更易于理解和分析。 在 HTML 表格中&#xff0c;我们可以使用 rowspan 和 …

【Spring Cloud】深入探索 Nacos 注册中心的原理,服务的注册与发现,服务分层模型,负载均衡策略,微服务的权重设置,环境隔离

文章目录 前言一、初识 Nacos 注册中心1.1 什么是 Nacos1.2 Nacos 的安装&#xff0c;配置&#xff0c;启动 二、服务的注册与发现三、Nacos 服务分层模型3.1 Nacos 的服务分级存储模型3.2 服务跨集群调用问题3.3 服务集群属性设置3.4 修改负载均衡策略为集群策略 四、根据服务…

【JUC】一文弄懂@Async的使用与原理

文章目录 1. Async异步任务概述2. 深入Async的底层2.1 Async注解2.2 EnableAsync注解2.3 默认线程池 1. Async异步任务概述 在Spring3.X的版本之后&#xff0c;内置了Async解决了多个任务同步进行导致接口响应迟缓的情况。 使用Async注解可以异步执行一个任务&#xff0c;这个…

棱镜七彩受邀参加“数字政府建设暨数字安全技术研讨会”

近日&#xff0c;为深入学习贯彻党的二十大精神&#xff0c;落实《数字中国建设整体布局规划》中关于“发展高效协同的数字政务”的要求&#xff0c;由国家信息中心主办、复旦大学义乌研究院承办、苏州棱镜七彩信息科技有限公司等单位协办的“数字政府建设暨数字安全技术研讨会…

zemax埃尔弗目镜

可以认为是一种对称设计&#xff0c;在两个双胶合透镜之间增加一个双凹单透镜 将半视场增大到30&#xff0c;所有的轴外像差维持在可以接受的水平。 入瞳直径4mm波长0.51、0.56、0.61半视场30焦距27.9mm 镜头参数&#xff1a; 成像效果&#xff1a;

Win11配置多个CUDA环境

概述 由于跑项目发现需要配置不同版本的Pytorch&#xff0c;而不同版本的Pytorch又对应不同版本的CUDA&#xff0c;于是有了在Win上装多个CUDA的打算 默认已经在电脑上装了一个CUDA 现在开始下载第二个CUDA版本&#xff0c;前面下载的操作和普通安装的几乎一样 安装CUDA CU…

CFS内网穿透靶场实战

一、简介 不久前做过的靶场。 通过复现CFS三层穿透靶场&#xff0c;让我对漏洞的利用&#xff0c;各种工具的使用以及横向穿透技术有了更深的理解。 一开始nmap探测ip端口,直接用thinkphpv5版本漏洞工具反弹shell&#xff0c;接着利用蚁剑对服务器直接进行控制&#xff0c;留下…

识别消费陷阱,反消费主义书单推荐

在消费主义无所不在的今天&#xff0c;商家是如何设置消费陷阱的&#xff1f;人们在做出消费决策时又是如何“犯错”的&#xff1f;如何才能做出更加理性的选择&#xff1f; 本书单适合对经济学、市场营销感兴趣的朋友阅读。 《小狗钱钱》 “你的自信程度决定了你是否相信自已…

kaggle_competition1_CIFAR10_Reg

一、查漏补缺、熟能生巧&#xff1a; 1.关于shutil.copy或者这个copyfile的作用和用法&#xff1a; 将对应的文件复制到对应的文件目录下 2.关于python中dict的键值对的获取方式&#xff1a; #终于明白了&#xff0c;原来python中的键_值 对的用法就是通过调用dict.keys()和…

Windows/Linux下进程信息获取

Windows/Linux下进程信息获取 前言一、windows部分二、Linux部分三、完整代码四、结果 前言 Windows/Linux下进程信息获取&#xff0c;目前可获取进程名称、进程ID、进程状态 理论分析&#xff1a; Windows版本获取进程列表的API: CreateToolhelp32Snapshot() 创建进程快照,…