Linux 动静态库

目录

一.静态库

1.理解静态库

a.什么是静态库?

b.创建静态库的理论?

2.打包静态库

3.静态库的使用方法

a.头文件找不着

b.链接报错——库函数文件找不着

4.将静态库文件写到系统目录下

a.直接拷贝

b.建立软链接

二.动态库

1.什么是动态库?

2.打包动态库

3.动态库的使用方法

4.静态链接和动态链接

5.解决方案

环境变量

三.动态库加载(底层原理)

1.前置知识

2.动态库加载(首地址+偏移地址)


一.静态库

1.理解静态库

a.什么是静态库?

简单来说,就是把一些功能接口(函数)打包到一个库里,供他人使用,当第三方使用库内的某一函数时,函数的实现会以拷贝的形式插入代码中,这种函数库,我们将其称为静态库。

b.创建静态库的理论?

我们知道,将一个.c源文件转换成一个可执行程序,需要经过 编译 和 链接 这两个步骤。即,将.c文件编译成.o文件,再将可能用到的所有.o文件链接起来,生成可执行程序。

所以,如果我们想要打包一个静态库,首先要将所有的.c文件编译成.o文件,然后在把所有的.o文件用特定的指令打包成一个库文件!

2.打包静态库

把包含库函数的多个.c文件用 gcc -c file.c 命令编译相应的.o文件,然后用ar -rc libmymath.a file.o 命令将所有.o文件打包成库的形式

如果我们想要将上述的库提供给他人使用,除了需要将 库函数文件(libmymath.a)提供给对方外,还需要将库函数所用到的头文件(Add.h、Del.h、Mul.h、Sub.h)提供给对方。

所以,我们可以将静态库分成两部分:①库函数文件(libmymath.a);②头文件。如果我们将这两部分放在同一个目录下,并将该目录压缩打包,然后就能把这个压缩包发给被人使用啦~~

3.静态库的使用方法

接下来,我们站在对方(使用我们提供的静态库的人)的视角,来看看第三方静态库究竟是如何使用的~~

a.头文件找不着

首先肯定是对压缩包进行解压操作,得到一个目录,该目录下有库函数文件(libmymath.a)和头文件,如下图所示:

接下来,我们创建一个test.c文件,并在该文件中使用静态库所提供的功能接口,试一试~~

那么,编译test.c文件,能否成功呢?

出错啦~~

头文件目录明明就在mymath_lib目录中,系统为什么还说找不到呢??

原因:系统在展开头文件时,只会到两个地方找:①系统的 /user/include/ 目录;②文件所在当前目录。若两个地方都找不到,则报错!!

虽然 mymath_lib 与 test.c 处在同一个目录下,但 Add.h 可不在这里!!

解决方法:

b.链接报错——库函数文件找不着

再次编译 test.c 再试一试~~

报错原因:系统在链接时,会去 /lib64/ 目录下寻找库函数文件,找不着,就报错!!

解决方法:

编译时可以用 -I 指定“头文件”路径、用-L指定“静态库”路径、用 -l 指定所链接的“目标库名”

运行试一试~~

成功啦~~

虽然使用成功了,但是... 每次使用这个库时都要以相对路径的方式包含头文件,而且,编译时还得加上-L 这样的字段,是不是太麻烦了? 嗯~~ 有木有一劳永逸的解决方法嘞? --- 哎,还真有!!

4.将静态库文件写到系统目录下

系统头文件所在的目录: /usr/include/

系统库函数文件所在目录: /usr/local/lib/

由于系统在展开头文件时,会去 /user/include/ 目录下查找;编译时,会去 /lib64/ 目录下查找。所以,我们只需要将头文件和库函数文件分别拷贝到系统头文件目录和系统库函数目录即可~~

a.直接拷贝

sudo cp  ./mymath_lib/include/*  /usr/include/    (拷贝头文件)

sudo cp  ./mymath_lib/lib/*  /usr/local/lib/  (拷贝库函数文件)

b.建立软链接

在 /user/include/ 和 /lib64/ 目录下建立软链接(注:软链接指向的路径必须是绝对路径!!)

给头文件建立软链接(在 /user/include/ 目录下操作):

sudo ln -s /home/common_whb/lesson29/static_warehouse/mymath_lib/include/Add.h  Add.h

给库函数文件建立软链接(在 /usr/local/lib/  目录下操作):

sudo ln -s /home/common_whb/lesson29/static_warehouse/mymath_lib/libmymath.a  libmymath.a

值得一提的是,上述两种方法虽然可以让我们在编译源文件时,无需使用指令(-I 和 -L)的方式指明路径,但在编译时,我们仍需使用 -l(小写L,前面那个是大写i)来指明第三方库名。

二.动态库

1.什么是动态库?

--- 本质就是将可能用到的.c文件直接翻译称为.o二进制文件,然后打包成的库,供第三方使用,当第三方使用库内的某一函数时,函数代码会以动态链接的形式被他人使用。

2.打包动态库

把所有的.c文件编译成.o文件的命令:gcc -fPIC -c  *.c

把所有的.o文件打包成动态库的命令:gcc -shared -o libmymath.so *.o

把包含库函数的多个.c文件用 gcc -fPIC -c file.c 命令编译相应的.o文件,然后用 gcc -shared -o libmymath.so *.o 命令将所有.o文件打包成 libmymath.so 库

3.动态库的使用方法

接下来,我们依旧站在对方(使用我们提供的静态库的人)的视角,来看看第三方动态库究竟是如何使用的~~

我们会遇到与静态库的使用相似的问题,即:①头文件找不到;②链接报错(库函数文件)

这两个问题的解决方法与静态库一摸一样的,咱们在这里就不再赘述了,直接一行代码搞定~~

gcc test.c -o test -I(大写的i) dynamic_warehouse/mymath_lib/include -L dynamic_warehouse/mymath_lib/lib -l(小写的L) mymath

执行试一试~~

源文件明明已经成功编译成了可执行程序,但运行可执行程序时,为什么还要去找动态库?

哎~~这就要说说静态链接和动态链接的区别了~~

4.静态链接和动态链接

静态链接:链接静态库时,系统会将相关代码和数据直接拷贝到己方源文件中,而后生成可执行程序,这样一来,可执行程序的运行便与静态库再无任何联系。

动态链接:链接动态库时,己方源文件内只会记录调用函数在动态库内的偏移地址,大大减少己方文件代码量的同时,却也提高了可执行程序对动态库的依赖性,即,当我们运行可执行程序时,仍需知道动态库的路径,并将动态库也一并加载到内存!!

gcc默认是动态链接的,但个别库,如果只提供.a(静态库),gcc也没办法,只能局部的把你指定的.a进行静态链接,其他库正常动态链接,而如果命令行有 -static, 无论有无动态库,都会执行静态链接。

所以,当使用静态库的源文件编译形成可执行程序后,可执行程序的运行就和静态库没关系了;而使用动态库编译形成可执行程序后,可执行程序的运行仍需要知道动态库的路径!!

故,由于动态链接生成的可执行程序的运行,仍需知道动态库的路径,所以,用指令(-I 和 -L)的方式编译源文件便不再可行(没法运行程序)了。

5.解决方案

解决方法:①直接拷贝(方法如静态库);②建立软链接(方法如静态库)。这两种方法既能编译源文件形成可执行程序,又能直接运行可执行程序。

而除了上述两种解决方法外,我们还可以用环境变量的方式来添加链接器默认搜索路径上的文件,注意:是链接器(针对的是库函数文件,不包括头文件),不是系统,头文件依旧需要指定路径。

环境变量

使用环境变量LD_LIBRARY_PATH,让系统找到自己的动态库。

虽然LD_LIBRARY_PATH这个环境变量主要用于动态链接器在运行时搜索动态库(.so文件),但在某些情况下,它也可能间接影响链接器在编译时的行为

操作如下:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/common_whb/lesson29/dynamic_warehouse/mymath_lib/lib

即,将包含 .so 文件的目录添加到 LD_LIBRARY_PATH,而不是将 .so 文件本身添加到该环境变量中。

注意:若使用该方法,待xshell外壳程序退出重新登陆时,环境变量会被清除。

小知识:ldd  a.out  查看一个可执行程序所链接的动态库 

三.动态库加载(底层原理)

1.前置知识

源文件编译成可执行程序的时候,代码被翻译成二进制文件后,原先代码中的变量名和函数名等都变成了一个个逻辑地址,链接动态库时,这些逻辑地址会记录动态库名和库函数的偏移地址,最终形成ELF格式的可执行程序!!

什么是库函数的偏移地址?--- 就是动态库中某一函数相对于该库首地址的偏移量,-fPIC (与位置无关码)的作用,就是让系统用偏移量的方式对库中的函数进行编址。

Linux下,可执行程序是ELF格式的,动态链接的可执行程序,不光程序本身要加载到内存,链接的库也要加载,并且,动态库在加载到内存后,会被所有进程共享!!

ELF格式的可执行文件(二进制文件格式):文件内包含了程序的机器码、数据、符号表、重定位信息以及程序运行所需的其他元数据。

2.动态库加载(首地址+偏移地址)

---源文件能够链接动态库的原因是源文件在翻译的过程中与动态库形成了某种关联(其实就是在可执行程序内记录下了的动态库名和方法偏移量),

由于调用了动态库的源文件形成的可执行程序运行时,仍需要使用动态库,那么,可执行程序是如何使用动态库的呢??

首先,可执行程序在加载到内存后,会在页表中填充虚拟地址和物理地址的映射关系,CPU会读取其表头中的entry代码入口地址,拿到虚拟地址块空间中代码段的入口地址,随后CPU上的指令寄存器便可读取地址空间上的代码,当读取到调用库函数的代码时,OS会查看该动态库是否已经加载到内存(其它进程可能在使用),若其尚未被加载到内存,则加载。

加载动态库的具体细节?

当动态库加载到物理内存后,物理地址与程序地址空间上的虚拟地址通过页表映射,在程序地址空间上的库的首地址会替换库名,通过库首地址,可以在程序地址空间上找到这个库,再通过方法偏移量,可以找到动态库内的某一具体函数

动态库在被映射到的共享区上的位置不是固定的!!

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

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

相关文章

通过标签实现有序:优化你的 FastAPI 生成的 TypeScript 客户端

在软件开发的世界里,API 客户端代码的质量直接影响着应用程序的性能和可维护性。随着项目规模的扩大,自动化生成的代码往往变得臃肿且难以管理。但幸运的是,通过一系列的优化策略,我们可以显著提升这些代码的优雅与效能。在本文中…

C#如何把写好的类编译成dll文件

1 新建一个类库项目 2 直接改写这个Class1.cs文件 3 记得要添加Windows.Forms引用 4 我直接把在别的项目中做好的cs文件搞到这里来,连文件名也改了(FilesDirectory.cs),这里using System.Windows.Forms不会报错,因为前…

用Qt 对接‌百度AI平台

很多同学想利用几大模型AI弄点东西,但又不知道如何去介入??最近帮同学弄点东西,刚好要接入到AI平台,就顺便研究了一下,并记录下来。 首先我们选择的 AI模型是百度的,然后注册,申请密…

8. 尝试微调LLM大型语言模型,让它会写唐诗

这篇文章与03. 进阶指南:自定义 Prompt 提升大模型解题能力一样,本质上是专注于“用”而非“写”,你可以像之前一样,对整体的流程有了一个了解,尝试调整超参数部分来查看对微调的影响。 这里同样是生成式人工智能导论&…

13年计算机考研408-数据结构

解析: 这个降序链表不影响时间复杂度,因为是链表,所以你想要升序就使用头插法,你想要降序就使用尾插法。 然后我们来分析一下最坏的情况是什么样的。 因为m和n都是两个有序的升序序列。 如果刚好m的最大值小于n的最小值&#xff0…

消息中间件---Kafka

一、什么是Kafka? Kafka是一个分布式流处理平台,类似于消息队列或企业消息传递系统; 流处理事什么呢? 流处理就是数据处理工作流,本质上是一种计算机编程范例。流处理是对接收到的新数据事件的连续处理。‌它涉及对从生产者到消…

10年408考研真题-数据结构

23.[2010统考真题]若元素 a,b,c,d,e,f 依次进栈,允许进栈、退栈操作交替进行,但不允许连续3次进行退栈操作,不可能得到的出栈序列是(D)。 A.dcebfa B.cbdaef C.bcaefd D.afedcb 解析: 直接看D选项&#xff0…

Python | Leetcode Python题解之第420题强密码检验器

题目: 题解: class Solution:def strongPasswordChecker(self, password: str) -> int:n len(password)has_lower has_upper has_digit Falsefor ch in password:if ch.islower():has_lower Trueelif ch.isupper():has_upper Trueelif ch.isdi…

微服务保护之熔断降级

在微服务架构中,服务之间的调用是通过网络进行的,网络的不确定性和依赖服务的不可控性,可能导致某个服务出现异常或性能问题,进而引发整个系统的故障,这被称为 微服务雪崩。为了防止这种情况发生,常用的一些…

pytorch实现RNN网络

目录 1.导包 2. 加载本地文本数据 3.构建循环神经网络层 4.初始化隐藏状态state 5.创建随机的数据,检测一下代码是否能正常运行 6. 构建一个完整的循环神经网络 7.模型训练 8.个人知识点理解 1.导包 import torch from torch import nn from torch.nn imp…

Python画笔案例-057 绘制蜘蛛网

1、绘制蜘蛛网 通过 python 的turtle 库绘制 蜘蛛网,如下图: 2、实现代码 绘制蜘蛛网,以下为实现代码: """蜘蛛网.py """ import turtledef draw_circle(pos,r):"""p

实时数据的处理一致性

实时数据一致性的定义以及面临的挑战‍‍‍‍‍ 数据一致性通常指的是数据在整个系统或多个系统中保持准确、可靠和同步的状态。在实时数据处理中,一致性包括但不限于数据的准确性、完整性、时效性和顺序性。 下图是典型的实时/流式数据处理的流程: 1、…

Infineon——TC397 Multicore简介

文章目录 前言一、TC397简介二、命名规则三、多核开发建议 前言 AURIX™ TC3xx微控制器架构具有多达6个独立的处理器内核CPU0…CPU5, 可在一个统一平台上无缝托管多个应用程序和操作系统. 由于实现了具有独立读取接口的多个程序Flash模块, 该架构支持进一步的实时处理. AURIX™…

毕业设计选题:基于ssm+vue+uniapp的驾校预约管理系统小程序

开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…

iPhone16,超先进摄像头系统?丝滑的相机控制

iPhone 16将于9月20号正式开售,这篇文章我们来看下iPhone 16 在影像方面,有哪些升级和新feature。 芯片:采用第二代 3纳米芯片,A18。 摄像头配置: iPhone 16 前置:索尼 IMX714 ,1200 万像素&am…

Red Hat 和 Debian Linux 对比

原图的作者(https://bbs.deepin.org/post/209759) Red Hat Enterprise Linux https://www.redhat.com/ CentOS Linux https://www.centos.org/ Fedora Linux https://fedoraproject.org/ Debian https://www.debian.org/ Ubuntu https://cn.ubuntu.com/ https://ubuntu.c…

harbor私有镜像仓库,搭建及管理

私有镜像仓库 docker-distribution docker的镜像仓库,默认端口号5000 做个仓库,把镜像放里头,用什么服务,起什么容器 vmware公司在docker私有仓库的基础上做了一个web页面,是harbor docker可以把仓库的镜像下载到本地&…

Matlab 的.m 文件批量转成py文件

在工作中碰到了一个问题,需要将原来用matlab gui做出来的程序改为python程序,因为涉及到很多文件,所以在网上搜了搜有没有直接能转化的库。参考了【Matlab】一键Matlab代码转python代码详细教程_matlab2python-CSDN博客 这位博主提到的matla…

Lanterns (dp 紫 线段树 二分 维护dp)

Lanterns - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 让所有点被覆盖,那么状态可以设计成覆盖一段前缀,并且中间不允许出现断点 由于CF崩了,所以暂时没提交代码。 记f(i) 为前 i 个灯笼点亮的最长前缀。 由于答案具有保留性&#xff…

自闭症孩子送寄宿学校,给他们成长的机会

在自闭症儿童的教育与康复之路上,选择一种合适的寄宿方式对于孩子的成长至关重要。这不仅关乎到孩子能否获得专业的训练与关怀,还直接影响到他们未来的社交能力、独立生活能力以及心理健康。今天,我们将以广州的星贝育园自闭症儿童寄宿制学校…