Linux的库文件

news2024/11/27 18:36:49

概述:

库文件一般就是编译好的二进制文件,用于在链接阶段同目标代码一块生成可执行文件,或者运行可执行文件的时候被加载,以遍调用库文件中的某段代码。

动态链接都是索引的.so文件,静态链接都是压缩打包的.a文件。

库文件和可执行文件相比:

  • 相同点:两者都是编译好的二进制文件
  • 不同点:库文件没法直接执行(直观上看,他的源代码中没有main函数,而只是一些函数模块的定义和实现,没有运行的入口主函数,所以库文件没法直接执行)。

我们的程序开发,无论是运行的时候,还是编译,链接的时候,一般都需要借助一些库来实现他们的功能,而很少直接通过程序的源代码生成完全独立的可执行文件。

静态库:

静态库概述:

        静态库实际上就是一些目标文件的(一般是以.o结尾)的集合,静态库一般是以.a结尾,只用于链接生成可执行文件阶段。

具体来说,以c程序为例子,一般我们编译程序源代码的时候过程大致是:

  • 以.c为后缀的源文件经过编译生成.o文件的目标文件
  • 以.o为后缀的目标文件经过链接生成最终的可执行文件。

我们可以在链接的时候直接链接.o的目标文件,也可以将这些.o文件打包集中起来,统一链接,而生成的打包集成了所有.o文件,也就是静态库。

        静态库只在程序连接的时候时候,连接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中,一旦链接完成生成可执行文件之后,执行程序的时候就不再需要静态库了

        由于每一个静态库的应用程序都是需要拷贝所用到的函数的代码,所以静态库链接生成可执行文件会比较大,多个程序运行的时候占用的内存空间比较大,(每个程序在内存中都有一份复制的静态库代码),但是由于运行的时候不用从外部动态加载额外的库了,速度会比共享库快。

静态库的制作

实例:假设在实际工作中设计了两个算法,但是需要卖给其他公司使用,为了保护公司的知识产权是不能将源代码交给其他公司的,这样我们可以将两个算法封装或者打包到一个静态库中。

假设实现这两个算法的函数为func1()和func()2。

新建一个头文件hello.h,在hello.h中对两个函数进行声明:

编写一个简单的程序“hello.c”

将hello.c编译生成.o文件

gcc -c hello.c -o hello.o

使用ar命令(ar是archive的意思)将hello.o文件打包成一个静态库文件libhello.a

 ar rcs libhello.a hello.o

注意:

  1. 如果需要将多个.o文件打包成文件库,则在命令行后边填写所有.o文件的名字即可
  2. 生成的库的名字必须是libxxx.a格式(注意:这里是尽量最好使用lib开头的格式,因为其他格式的编译方式是不一样的)

编译参数:<rcs>

r:表明将模块加入到静态库中,c表示创建静态库,s表示产生索引

使用nm命令查看库文件中包含的符号:nm libhello.a

使用 ar -t 命令查看静态库是由那些.o文件组成的:ar -t libhello.a

编写一个带有主函数的程序main.c,并且在main.c中调用静态库中的func1和func2函数:

现在所有文件下都在同一个目录下,没法直接体现出来静态库的作用。

在IO_file_test目录下新建一个static_lib_test目录进行测试将文件移动到下边设备树结构。(这里是一个比较常用的目录结构,但是为了方便测试三个文件都放在一个文件目录下即可)

解释:

include目录下是.h文件

lib里边是链接的静态库文件

src里边是.c文件

编译:

gcc main.c -L../lib -lhello -I../include -o main

编译解释:

-L指向的是链接的静态库路径

-l(小L)是静态库的命称(去掉lib之后的)

-I(大i)链接存放.h文件的路径

编译现象:

在静态库的概述中会标红的地方提到了(一旦链接完成生成可执行文件之后,执行程序的时候就不再需要静态库了),所以这时删除掉libhello.a文件后程序仍然可以执行。

共享库(动态库)

共享库概述

共享库也叫做动态库

静态库缺点:

  1. 内存消耗大;(假设一个静态库的大小为1M,当两千个程序都用到这库将消耗掉2G内存)
  2. 当静态库中的代码优化的时候,所有调用该静态库的程序需要重新编译,这样太过与麻烦。

动态库特点:

  1. 动态库在程序编译的时候并不会被链接到目标代码当中,而是在程序运行的时候才被载入。
  2. 不同的应用程序如果调用相同的库,那么在内存中里只需要有一份共享库的实例,规避了空间浪费问题。
  3. 动态库在程序运行的时候才能被载入,也解决了静态库对程序的更新,部署和发布页带来的麻烦。用户只需要更新动态库即可,增量更新。

动态库制作

参照静态库目录下创建三个文件如下:内容和静态库的也相同

编译链接生成.o文件

将编译好生成好的hello.o编译编译生成动态库:gcc -shared -fPIC -o libhello.so hello.o

注意:

  1. -shared:表明是使用的共享库
  2. -fPIC:表明生成与位置无关的代码、
  3. 动态库后缀为.so
  4. 动态库格式libxxx.so
  5. 如果还有其他链接的.o文件,直接在hello.o后边加上,用空格隔开

使用nm命令查看一个库文件中包含的符号: nm libhello.so

对照静态库测试目录制作动态库目录格式:

将上边共享库目录的文件对应拷贝到共享库测试目录里边如下:

进行编译:gcc main.c -L../lib -lhello -I../include -o main

但是如果直接执行的话,编译器会爆出一个错误。

错误的主要意思是在加载的时候打不开动态库文件,但是注意:动态库在在程序执行的时候会被加载。

这是因为在Linux中启动一个ELF格式的二进制可执行文件会自动启动和运行一个program loader(程序加载器:用来加载一些库)。对于Linux系统,这个loader的名字是ld-linux.so.X(X是版本号)。这个loader启动后会load所有的其他本程序的要使用的共享函数库。动态库与静态库不同,在执行文件的阶段需要加载动态库文件,而加载的动态库文件需要在指定位置或者添加在环境变量中,才能正确的加载动态库文件。

动态链接库的查找先后顺序:

  • LD_LIBRARY_PATH环境变量中的路径
  • /etc/ld.so.cache缓存文件
  • /usr/lib和/lib

动态库临时生效

可以临时将libhello.so所在的路径追加到环境变量LD_LIBRARY_PATH中

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/IO_file_test/shared_lib_test/lib

冒号后边跟是自己的动态库路径。

修改完成之后我们可以使用echo $LD_LIBRARY_PATH查看环境变量被修改的值

注意: 在终端使用expert命令来修改当前环境变量的值,只是对当前会话临时生效,如果切换到一个新的会话窗口或者新的终端,关闭当前会话窗口都会失效。

动态库长期生效

  • 修改系统启动配置文件,将export命令添加到启动文件当中

设置环境变量:
      1.打开 vim ~/.bashrc 文件
       2.在文件末尾添加一行
            export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径(如果需要删除环境变量,需要在~/.bashrc中删除环境变量后,关掉终端,重新启动终端才能生效)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/Desktop/IO_file_test/shared_lib_test/lib
       3.重新加载配置文件 source ~/.bashrc

  • 将动态库文件拷贝到/usr/lib或者/lib目录下(一般不采用这个种方式,因为这样会污染系统,并且不方便项目迁移)
  • 修改/etc/ld.so.conf文件

动态库的升级

引入:

在实际工作当中,我们可能经常需要对动态库的板本进行升级,假如原来的库为libhello.so,那么升级完以后还需要保留每一个旧的板本,动态库的名字就不能重复,但是程序在加载的时候只加载libhello.so文件,解决:所以我们可以对每一个板本的动态库文件进行不同的命名,然后在新建立软链接,链接需要使用的实体库即可。

根据动态的命名规则,我们可以将动态库的第一个板本命名为:libhello.so.1.0.0,然后创建软连接

ln -s libhello.so.1.0.0 libhello.so

假设我们在原来的库上增加了某些接口我们可以将新库的版本名命名为libhello.so.1.1.0,删除原来的软连接文件,并重新创建软链接文件到该文件。

位置无关代码

        位置无关代码(PIC:position-independent code),也被称为地址无关代码,是指源代码被编译成二进制文件(可以是执行文件也可以是某个库文件),编码方式也和位置(地址)无关。

        程序在运行的时候是需要被加载到物理内存上运行的,但是操作系统为了方便每个进程进行内存管理,使用虚拟内存技术,每一个进程运行时都会得到4G的虚拟内存。这个虚拟内存可以认为每个进程任务自己认为自己有4G的空间,着只是每个进程认为的,但是实际上,在虚拟内存对应的物理内存上,可能只对应一点点的物理内存,实际用了多少内存,就会对应多少物理内存。

使用静态库和动态库编译生成的可执行文件在运行时候在内存上的加载方式:

如果使用了静态库编译可执行程序,每个函数在内存中的位置(地址)在编译完成以后就已经决定了。

但是共享库(动态库)是在可执行程序执行的时候加载进去的,动态编译后的函数的调用地址是自动计算出来的,这就是与位置无关的代码。

下边是找到的一个资料对位置无关代码的验证:

在64为机器上可以运行32位的指令。

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

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

相关文章

配置visualsvn提交后自动邮件通知

参考&#xff1a; https://blog.csdn.net/wiker_yong/article/details/10334967 # -*- coding: utf-8 -*- import sys import os import smtplib from email.mime.text import MIMEText from email.header import Headermail_host smtp.163.com #发送邮件的smtp地址 mail_us…

【RPA】什么是RPA

一、什么是RPA? RPA&#xff0c;全称机器人流程自动化&#xff0c;是一种利用机器人技术实现工作信息与业务交互自动化的过程。它能够按照预先设计的流程&#xff0c;高效地处理大量的工作信息与业务交互&#xff0c;极大地节约了人工成本。如今&#xff0c;RPA已成为智能化软…

26.云原生ArgoCD高级之ApplicationSet

云原生专栏大纲 文章目录 ApplicationSet介绍ApplicationSet 特性ApplicationSet 安装ApplicationSet 工作原理ApplicationSet 生成器列表类型生成器集群生成器基础使用方法Label Selector 指定集群Values 字段传递额外的参数 git生成器git目录生成参数排除目录git文件生成器矩…

zabbix server/agent源码编译成rpm包(通用版-小白教程)

前言 工作环境需要用到很多信创的操作系统&#xff0c;zabbix agent2的官方没有现成的包可用&#xff0c;网上巴拉了一下找到zabbix agent2通用版编译成rpm包的方法 思路&#xff1a;假如当你有一批ky10_x86的机器需要配套的zabbix agent的rpm包&#xff0c;那就找一台ky10_x…

6个国内可用的chat大模型

文心一言 - 一款适合中国人使用的AI智能助理&#xff0c;能够帮助用户进行对话、生成内容等工作&#xff0c;提高工作效率和创作水平 文心一言 文心一言 App 是一款适合中国人的 AI 智能助理&#xff0c;它的功能点主要包括&#xff1a; 工作生活助理&#xff1a;该应用通过简…

鉴权失败原因

在技术领域&#xff0c;鉴权失败是指一个系统或应用程序中的身份验证或权限验证过程失败。当用户试图访问受限资源或执行受限操作时&#xff0c;系统会进行鉴权过程来确认用户是否具有足够的权限。如果鉴权过程失败&#xff0c;则表示用户无法获得所需的访问权限。 鉴权失败可…

Java代码实现基数排序算法(附带源码)

基数排序是一种非比较型整数排序算法&#xff0c;其原理是将整数按位数切割成不同的数字&#xff0c;然后按每个位数分别比较。由于整数也可以表达字符串&#xff08;比如名字或日期&#xff09;和特定格式的浮点数&#xff0c;所以基数排序也不是只能使用于整数。 1. 基数排序…

基于Springboot的兼职网(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的兼职网&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0…

ubuntu离线安装k8s

目录 一、前期准备 二、安装前配置 三、安装docker 四、安装cri-dockerd 五、部署k8s master节点 六、整合kubectl与cri-dockerd 七、网络等插件安装 八、常见问题及解决方法 一、前期准备 ①ubuntu系统 本地已安装ubuntu系统&#xff0c;lsb_release -a命令查看版本信…

HarmonyOS应用/服务发布:打造多设备生态的关键一步

目前 前言HarmonyOS 应用/服务发布的重要性使用HarmonyOS 构建跨设备的应用生态前期准备工作简述发布流程生成签名文件配置签名信息编译构建.app文件上架.app文件到AGC结束语 前言 随着智能设备的快速普及和多样化&#xff0c;以及编程语言的迅猛发展&#xff0c;构建一个无缝…

打印文件pdf怎么转换成word文档?pdf转换工具推荐

有时候我们可能需要重用PDF文件中的文本内容&#xff0c;比如引用某些段落、复制粘贴特定文字或提取数据&#xff0c;通过将pdf文件转换成word&#xff0c;可以轻松地提取和重用其中的文本&#xff0c;节省时间和努力&#xff0c;那么pdf怎么转word呢&#xff1f;可以试试本文推…

读论文:DiffBIR: Towards Blind Image Restoration with Generative Diffusion Prior

DiffBIR 发表于2023年的ICCV&#xff0c;是一种基于生成扩散先验的盲图像恢复模型。它通过两个阶段的处理来去除图像的退化&#xff0c;并细化图像的细节。DiffBIR 的优势在于提供高质量的图像恢复结果&#xff0c;并且具有灵活的参数设置&#xff0c;可以在保真度和质量之间进…

SpringBoot实战第二天

今日战报 继续完善用户相关接口开发&#xff1a; 1.完成获取用户信息功能 2.完成更新用户信息功能 3.完成更新用户头像功能 4.完成更新用户密码功能 获取用户信息 接口文档 如接口文档所示&#xff0c;我们需要做的就是从header中的Authorization中读取token&#xff0c;解码…

CSS 闪电按钮效果

<template><view class="const"><div class="voltage-button"><button>闪电按钮</button><svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox=&q…

PyTorch 2.2 中文官方教程(十七)

&#xff08;Beta&#xff09;使用缩放点积注意力&#xff08;SDPA&#xff09;实现高性能 Transformer 原文&#xff1a;pytorch.org/tutorials/intermediate/scaled_dot_product_attention_tutorial.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 注意 点击这…

Flutter开发iOS问题记录

一、版本适配问题 warning: The iOS deployment target ‘IPHONEOS_DEPLOYMENT_TARGET’ is set to 10.0, but the range of supported deployment target versions is 12.0 to 17.2.99. (in target ‘Protobuf’ from project ‘Pods’) 可以通过在podfile中配置解决。 pos…

小埋的解密游戏的题解

题目描述 小埋最近在玩一个解密游戏&#xff0c;这个游戏的解密方法是这样的&#xff0c;这个游戏会给你提供 个数,让我们求出这 个数里面&#xff0c;有多少个连续的数的平均数大于某个给定的数 。这个数可能会很大&#xff0c;所以我们要输出这个数对 的取模结果。现在小…

Java并发之synchronized详解

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

使用Java实现基于HTTP的分布式系统:让你的应用“四处开花”

在数字世界里&#xff0c;分布式系统就像是一个大家庭&#xff0c;每个成员&#xff08;即节点&#xff09;都有自己的任务和职责&#xff0c;共同维护整个家庭的运转。如果你想使用Java来实现这样一个大家庭&#xff0c;让应用在各个节点上“四处开花”&#xff0c;那就需要借…

ensp实验合集(二)

实验6 VLAN划分....................................................................... - 30 - 实验7 路由器调试及常用命令使用........................................ - 42 - 实验8 配置静态路由器............................................................…