Linux--动静态库制作使用及使用

目录

0.文件系统

1.软硬链接

2.静态库 

2.1先见一见 

 2.2 制作静态库,并使用制作的静态库

3.动态库

3.1制作动态库,并使用制作的动态库

 4.推荐一个第三方库(ncurses)

5.动态库的加载 

6.动态库VS静态库 


0.文件系统

Linux--文件系统-CSDN博客

1.软硬链接

 Linux--软硬链接-CSDN博客


2.静态库 

在Linux中:.so(动态库) .a(静态库)


2.1先见一见 

在这里我们写了一段代码:

        我们在执行这段代码的时候,调用了里面的函数,我们没有该函数的实现,但可以使用它,是因为我们链接了它们的库,有gcc编译器完成链接,ldd可以查看当前可执行程序链接了上面库。而(libc.so.6 => /lib64/libc.so.6 (0x00007fb7ab942000))这个库就是C语言的标准库。

这是它们的软链接关系

这是C语言的库文件


 2.2 制作静态库,并使用制作的静态库

1.我们先将自己提供的目标文件,形成后缀为.o的文件(将源代码为编译对象文件.o 文件通常指的是“对象文件”(Object File)。这些文件是编译器(如GCC)将源代码(如.c.cpp等文件)编译后产生的中间文件,但它们还不是可以直接运行的可执行文件。)

以下是我提供的C语言文件

现在我们要生成对象文件,指令为:

gcc -c  文件名.c -o  文件名.o

2.创建静态库(使用ar命令将对象文件打包为一个静态库文件(.a文件))

命令:ar rc libmyc.a 对象文件

   r选项表示替换现有的目标文件,c选项表示创建一个库。也就是说你要我形成的这个库如果原本没有,我就帮你形成一个新的库,如果有了那我就把你原来旧的库替换掉。

3.将我们创建的静态库安装到系统下:

1.为了达到与C语言库一样的效果,我们要将我们的头文件拷贝到系统级的头文件目录下:

sudo cp mystdio.h mymath.h /usr/include/

2.将对象文件拷贝到C语言标准库的目录下:

sudo cp libmyc.a /lib64

4.写一段C语言代码并调用自己的库:

我写的mymath是实现myAdd函数的,mystdio对几个文件操作函数的实现。

接着我们来编译这段代码,看行不行:发现找不到这些函数,这是因为写到C/C++的库,gcc/g++默认是认识C/C++的库,libmyc.a --.>别人写的(第三方库)->gcc/g++是不认识的

在编译的时候要加 -l(limbmyc.a),表示在编译的时候要链接这个库。结果还是找不到。

这是因为要去掉前缀lib,后缀.a,myc才是库真实的名字。

至此可知:安装库就是将第三方的头文件,库文件拷贝到系统指定的目录下。


如果不想加载到指定目录下的写法:

        gcc main.c - I(大写的i)./(指定用户自定义头文件路径)-L ./(指定用户自定义库文件路径)-l(执行确定的第三方库名称)


        通过使用库,开发者可以避免编写大量重复的代码。库中的函数、类和方法都是经过测试和优化的,因此可以直接在项目中使用,而无需担心潜在的错误或性能问题。


3.动态库


3.1制作动态库,并使用制作的动态库

1. 编译为位置无关代码

这条指令做了两件事情:

  1. -fPIC 选项:它告诉 GCC 生成位置无关的代码(Position Independent Code),这种代码可以在内存中的任何位置运行,这对于动态库(shared libraries)和某些类型的程序(如 PIE - Position Independent Executables)来说是必要的。

  2. -c 选项:它告诉 GCC 只编译源文件,不链接它。这会产生一个目标文件(object file),通常是 .o 扩展名,该文件包含了编译后的机器代码,但还没有和其他目标文件或库链接在一起

2. 链接为目标共享库

直接用gcc就可以 了。命令:

gcc -shared *.o -o libmyc.so(将多个编译过的目标文件(.o 文件)链接成一个动态共享库)

3.使用自己的态库

gcc test.c - I(大写的i)./(指定用户自定义头文件路径)-L ./(指定用户自定义库文件路径)-l(执行确定的第三方库名称)

执行下面程序:

此时使用gcc编译main.c生成可执行程序时,需要用-I选项指定头文件搜索路径,用-L选项指定库文件搜索路径,最后用-l选项指明需要链接库文件路径下的哪一个库。

gcc test.c -I mylib/include -L mylib/lib -lmyc

与静态库的使用不同的是,此时我们生成的可执行程序并不能直接运行。

        需要注意的是,我们使用-I-L-l这三个选项都是在编译期间告诉编译器我们使用的头文件和库文件在哪里以及是谁,但是当生成的可执行程序生成后就与编译器没有关系了,此后该可执行程序运行起来后,操作系统找不到该可执行程序所依赖的动态库,我们可以使用ldd命令进行查看。

可以看到,此时可执行程序所依赖的动态库是没有被找到的。而静态库在编译期间,已经将库中的代码拷贝到我们的可执行程序内部了!加载和库就没有关系了!

4.让操作系统找到运行程序所依赖的动态库的四个方法

方法一:拷贝.so文件到系统共享库路径下(不建议)

        既然系统找不到我们的库文件,那么我们直接将库文件拷贝到系统共享的库路径下,这样一来系统就能够找到对应的库文件了。

sudo cp mylib/lib/libmyc.so /lib64

方法二:软链接

ln -s /home/light/mystdio/mylib/lib/libmyc.so /lib64/libmyc.so

        这条命令在/lib64/目录下创建了一个名为libmyc.so的符号链接,/lib64/libmyc.so: 这是链接文件的路径。这不会复制libmyc.so/lib64/目录下,而只是在该目录下创建一个指向/home/light/mystdio/mylib/lib/libmyc.so的链接。在运行就成功了

方法三:环境变量法(更改LD_LIBRARY_PATH)

  LD_LIBRARY_PATH是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH环境变量当中即可。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/light/mystdio/mylib/lib

  LD_LIBRARY_PATH 是一个由冒号分隔的目录列表,动态链接器会在这些目录中查找动态链接库。

  • LD_LIBRARY_PATH: 这是一个环境变量,用于指定动态链接器搜索共享库的额外目录。

  • $LD_LIBRARY_PATH: 通过 $ 符号引用现有的 LD_LIBRARY_PATH 环境变量的值。

  • :/home/light/mystdio/mylib/lib: 这里,: 是目录分隔符,后面跟的是你想要添加到

        一旦你关闭终端或者重启机器,所有的环境变量设置都会丢失,因为它们只存在于当前 shell 进程的上下文中。

        如果你希望在每次登录或重启后都能保持这个环境变量的设置,你需要将这个命令添加到某个在登录时自动执行的脚本中。对于 bash shell,通常这样的脚本是用户的 .bashrc.bash_profile 或 .profile 文件(具体哪个文件取决于你的系统配置和个人偏好)。

        只要使用vim打开,将之前设置的环境变量添加进来,登录或重启后都能保持这个环境变量的设置

方法四:配置/etc/ld.so.conf.d/(三步走)

  我们可以通过配置/etc/ld.so.conf.d/的方式解决该问题,/etc/ld.so.conf.d/路径下存放的全部都是以.conf为后缀的配置文件,而这些配置文件当中存放的都是路径,系统会自动在/etc/ld.so.conf.d/路径下找所有配置文件里面的路径,之后就会在每个路径下查找你所需要的库。我们若是将自己库文件的路径也放到该路径下,那么当可执行程序运行时,系统就能够找到我们的库文件了。

1.首先将库文件所在目录的路径存入一个以.conf为后缀的文件当中。

2.然后将该.conf文件拷贝到/etc/ld.so.conf.d/目录下。

        但此时我们用ldd命令查看可执行程序时,发现系统还是没有找到该可执行程序所依赖的动态库。

3.这时我们需要使用ldconfig命令将配置文件更新一下,更新之后系统就可以找到该可执行程序所依赖的动态库了。

此时我们就可以正常的运行程序了


 4.推荐一个第三方库(ncurses)

        ncurses是一个功能强大且广泛使用的库,它使得开发者能够在字符终端上创建出丰富、交互式的用户界面。通过其提供的API和核心概念如屏幕缓冲区、颜色系统和窗口管理等,开发者可以轻松地构建出各种复杂且吸引人的终端应用程序。

先安装这个库

使用到这个库sh,编译时记得指定


5.动态库的加载 

        静态库在编译期间,就把库中的方法拷贝到了程序当中,未来加载就只谈论程序加载,与库没有关系,所以我们再谈库的加载时,不考虑 静态库,只考虑动态库。

动态库加载的整体轮廓:

        每个进程都有其独立的虚拟地址空间,由操作系统管理。地址空间包括代码段、数据段、堆和共享区等区域。当可执行程序启动时,操作系统会检查其依赖的动态库。动态链接器(如Linux中的ld.so或ld-linux.so)负责将动态库加载到进程的地址空间中的共享区。库中的代码和数据会被映射到相应的虚拟地址上,使得程序能够通过指针或函数调用访问它们。多个进程是可以同时使用一个动态库的,因为都在一个内存里,其它进程同样只需要将动态库加载到自己地址空间的共享区中,就能使用这个动态库。

我们的可执行程序,编译成功,没有加载运行,二进制代码中有“地址”吗?

        当然包含了地址。源代码会首先被转换为汇编代码,然后汇编器将这些汇编指令转换为机器代码。在这个过程中,汇编器会为程序中的各个部分(如函数、变量等)分配相对地址或偏移量。这些地址用于在程序内部进行跳转、调用或数据访问(每条汇编语句都有它的地址)。

        编译后的二进制代码中确实包含地址信息,但这些地址通常是相对地址或偏移量,用于在程序内部进行定位。这些地址在程序被加载到内存并执行时,才会被转换为实际的物理或虚拟内存地址。(cup的pc指针拿到虚拟地址,通过查页表找到物理地址,然后执行代码

以上都是程序的加载

再理解动态库的加载

  • 当程序开始运行时,如果它依赖于动态库,那么这些库的代码和数据并不会立即被加载到物理内存中。相反,当程序首次调用库中的函数或访问库中的数据时,动态链接器会负责加载所需的库。
  • 动态链接器首先检查所需的库是否已经在内存中加载。如果是,则通过共享区的映射直接使用该库;如果不是,则从磁盘中加载库文件到物理内存,并更新页表以建立虚拟地址和物理地址之间的映射关系。
  • 动态库被加载到内存中后,会被映射到进程的地址空间中。这意味着库中的代码和数据现在可以通过进程的虚拟地址空间进行访问。
  • 由于多个进程可能共享同一个动态库,因此操作系统会确保这些进程在各自的地址空间中都能正确地映射到库的实际物理地址。这是通过共享内存技术实现的,其中多个进程可以访问同一块物理内存区域。

6.动态库VS静态库 

        在上面制作的库中,动静态库同名,运行程序时,系统时默认优先使用动态库的。

        在编译和链接程序时,通常会明确指定使用静态库还是动态库。例如,在GCC编译器中,可以通过-static选项来强制使用静态链接,或者使用-l选项后跟库名来指定要链接的库。如果同时指定了同名的静态库和动态库,编译器和链接器的具体行为可能因系统和工具链的不同而有所差异。

动静态库的差异:

1. 链接时间和方式

  • 静态库:在编译时被链接到可执行文件中。静态库的代码会被完整地复制到最终的可执行文件里。
  • 动态库:在运行时被加载到内存中。动态库在编译时不会被合并到可执行文件中,而是在程序运行时由系统动态加载。

2. 对可执行文件大小的影响

  • 静态库:由于静态库的代码被完整地复制到每个使用该库的可执行文件中,因此会导致可执行文件体积增大。
  • 动态库:多个程序可以共享同一个动态库,因此不会显著增加每个可执行文件的大小。

3. 更新和维护

  • 静态库:如果静态库发生更新,所有使用该库的可执行文件都需要重新编译和链接。
  • 动态库:当动态库更新时,只要库中的函数定义和接口没有变化,使用该库的可执行文件通常不需要重新编译或链接。这大大简化了软件的更新和维护过程。

4. 依赖性和移植性

  • 静态库:由于代码在编译时已被嵌入到可执行文件中,因此静态库对可执行文件的依赖性较低,移植相对方便。
  • 动态库:程序在运行时需要动态库的支持,如果目标系统上没有相应的动态库,程序将无法运行。这增加了对运行环境的依赖性,但在多个程序共享相同库的情况下,可以节省内存和系统资源。

5. 文件扩展名

  • 静态库:在Unix/Linux系统上通常以.a为文件扩展名,在Windows系统上通常以.lib为文件扩展名。
  • 动态库:在Unix/Linux系统上通常以.so(Shared Object)为文件扩展名,在Windows系统上则以.dll(Dynamic Link Library)为文件扩展名。

        综上所述,动态库和静态库各有优缺点,适用于不同的场景和需求。静态库更适合于需要独立运行、对体积不敏感且更新频率较低的应用;而动态库则更适合于需要频繁更新、多个程序共享代码以及对可执行文件大小有严格要求的应用场景。

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

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

相关文章

北理工提出 LTrack 双摄像头系统 | 专注于暗场景多目标跟踪,自动驾驶和夜间监控的福音!

低光照场景在现实世界应用中很普遍(例如自动驾驶和夜间监控)。最近,在各种实际用例中的多目标跟踪受到了很多关注,但在暗场景中的多目标跟踪却鲜少被考虑。 在本文中,作者专注于暗场景中的多目标跟踪。为了解决数据集…

9.5 Go语言入门(条件语句和循环语句)

Go语言入门(条件语句和循环语句) 目录四、条件语句和循环语句1. 条件语句1.1 if 语句1.2 if-else 语句1.3 if-else if-else 语句1.4 带初始化语句的 if1.5 switch 语句1.6 带条件的 switch1.7 多个条件的 case 2. 循环语句2.1 基本 for 循环2.2 省略初始…

转行3年涨薪300%,我总结了一套产品经理快速入门指南!

想转行的产品小白,初期一定会遇到这个问题——我要如何 0 基础转行产品经理? 要想 0 基础快速转行产品经理,我通过个人实践总结了 5 个关键点,可以参考。 一、熟悉产品经理的工作全流程 转行的产品小白,首先要建立产…

Amesim应用篇-制冷剂压焓图软件Coolpack简介与冷媒流量评估

前言 空调系统仿真不可避免的会涉及到冷媒的物性参数、压焓图等信息。冷媒的物性可以在Amesim中自带的模型中查看。而压焓图可以通过Coolpack软件绘制。 一 软件介绍 Coolpack是个独立的小程序,集成了各种冷媒的性能参数,可以直观查看冷媒工作工况曲线…

c语言:摆脱对指针的恐惧【4】

在上一期指针我们讲到了二级指针是的作用是存放一级指针的地址,还讲了指针数组是一个可以存放若干个指针变量的数组,这里我们再复习一下,下面指针数组是什么意思? int* arr1[10]; //整形指针的数组 char *arr2[4]; //一级字符指针…

Python中动态调用C#的dll动态链接库中方法

在Python中调用C#的dll库_哔哩哔哩_bilibili 环境准备: 安装 pythonnet pip install pythonnet在Python中调用C#动态链接库(DLL),可以使用pythonnet库,它允许直接使用 .NET 的程序集。以下是一个示例,…

C++ 写的_string类,兼容std::string, MFC CString和 C# 的string

代码例子: using namespace lf; int main() { CString s1 _t("http://www.csdn.net"); _string s2 s1; CString s3 s2; _pcn(s1); _pcn(s2); _pcn(s3); return 0; } 输出: _Str.h /***************************************…

在使用LabVIEW控制多个串口设备进行数据读取时,读取时间过长

在使用LabVIEW控制多个串口设备进行数据读取时,如果发现数据更新时间超过5秒,可以从以下几个方面进行分析和解决: 1. 串口配置与通信参数 确保每个串口的通信参数(波特率、数据位、停止位、校验位等)配置正确&#x…

【数据结构】二叉树的功能实现

文章目录 关于二叉树的创建如何创建二叉树实现二叉树的前、中、后序遍历层序遍历 关于二叉树的创建 在笔者的上一篇文章中堆进行了一个详细介绍,而二叉树是以堆为基础进行创建,它与堆的显著不同是 堆像是一个线性结构,堆的结构往往是一个数…

springboot项目,@Test写法 @Before @After

某文件示例 package cn.xxx.crm.boss;import cn.xxxx.crm.manager.mq.rabbit.AliyunCredentialsProvider; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; im…

2024电工杯数学建模B题Python代码+结果表数据教学

2024电工杯B题保姆级分析完整思路代码数据教学 B题题目:大学生平衡膳食食谱的优化设计及评价 以下仅展示部分,完整版看文末的文章 import pandas as pd df1 pd.read_excel(附件1:1名男大学生的一日食谱.xlsx) df1# 获取所有工作表名称 e…

XSS漏洞:pikachu靶场中的XSS通关

目录 1、反射型XSS(get) 2、反射性XSS(POST) 3、存储型XSS 4、DOM型XSS 5、DOM型XSS-X 6、XSS之盲打 7、XSS之过滤 8、XSS之htmlspecialchars 9、XSS之href输出 10、XSS之js输出 最近在学习XSS漏洞,这里使用…

与WAF的“相爱相杀”的RASP

用什么来保护Web应用的安全? 猜想大部分安全从业者都会回答:“WAF(Web Application Firewall,应用程序防火墙)。”不过RASP(Runtime Application Self-Protection,应用运行时自我保护)横空出世…

LeetCode198:打家劫舍

题目描述 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存…

【LeetCode】【5】最长回文子串

文章目录 [toc]题目描述样例输入输出与解释样例1样例2 提示Python实现动态规划 个人主页:丷从心 系列专栏:LeetCode 刷题指南:LeetCode刷题指南 题目描述 给一个字符串s,找到s中最长的回文子串 样例输入输出与解释 样例1 输入…

打造专业级网页排版:全方位解析专业字体家族font-family实践与全球知名字体库导览

CSS中的字体家族(font-family)属性用于指定文本所使用的字体系列。它允许开发者选择一种或多种字体作为备选,确保在浏览器中以最佳可用字体显示文本。本文将深度解析专业级网页排版中字体家族(font-family)设置的实践技…

嵌入式实时操作系统笔记2:UCOS基础知识_UC/OS-III移植(STM32F4)_编写简单的UC/OS-III任务例程(失败.....)

今日学习嵌入式实时操作系统RTOS:UC/OS-III实时操作系统 本文只是个人学习笔记备忘用,附图、描述等 部分都是对网上资料的整合...... 文章主要研究如何将UC/OS-III 移植到 STM32 F407VET6上,提供测试工程下载 (2024.5.21 文章未…

明天(周六)下午!武汉Linux爱好者线下沙龙,我们在华中科技大学等你!

2024 年 5月 25 日(周六)下午,我们将在「武汉市洪山区」 珞喻路 1037 号华中科技大学南五楼 613 室举办武汉 Linux 爱好者线下沙龙(WHLUG),欢迎广大 Linux 爱好者来到现场,与我们一同交流技术&a…

【Spring】SSM介绍_SSM整合

1、SSM介绍 1.1简介 SSM(Spring SpringMVC MyBatis)整合是一种流行的Java Web应用程序框架组合,它将Spring框架的核心特性、SpringMVC作为Web层框架和MyBatis作为数据访问层框架结合在一起。这种整合方式提供了从数据访问到业务逻辑处理再…

构建智能化的语言培训教育技术架构:挑战与机遇

随着全球化的发展和人们对语言学习需求的增长,语言培训教育行业正面临着越来越多的挑战和机遇。在这个背景下,构建智能化的语言培训教育技术架构成为提升服务质量和效率的重要手段。本文将探讨语言培训教育行业的技术架构设计与实践。 一、智能化教学平台…