【Linux笔记】动静态库的封装和加载

一、静态库的封装

我们在学习C语言阶段其实就已经知道一个可执行程序的形成过程分为预处理、编译、汇编、链接这四个阶段,而且也知道我们程序中使用的各种库其实是在链接的阶段加载的。

可我们那时候并不知道库是怎么被加载的,或者库是怎么形成的,所以今天我们就要好好的来聊一下,库的形成。

1.1、库封装的本质

我们知道链接阶段其实是将形成可执行程序的各种.o目标文件连接起来形成可执行程序,但是对于一个库来说,可是如果一个可执行程序使用的很多函数分散在不同的.o文件中,那么这样一个一个的链接就显得很麻烦。

就例如我们现在有这样的一个场景:

如上图,我们有这样一堆头文件和对应的方法实现,我们想要模拟编译器的行为先形成.o文件,再将它们连接形成可执行程序。我们当然可以一个一个的将它们编译形成.o文件,然后再连接:

但这样实在太麻烦,特别是后面链接形成可执行的操作,如果今天我们的可执行程序依赖了100或200个.o文件,那这样不累死人?

所以为了方便,我们可以将一些有关联的.o文件再次打包,形成一个库文件,那这样我们在连接的时候就只需要找到这个库文件就行了。

所以库的封装其实就是将一批.o文件打包。

1.2、静态库的封装方法

我们打包静态库使用的指令是ar -rc指令,例如我们想要将上面的这些方法打包成一个名为mymath的静态库,对应的指令是这样的:

注意:上面所写的库名称为libmymath.a,但是该库的真实名称并不是libmymath,而是mymath,这是因为库文件必须要一个前缀lib,而.a是静态库文件的后缀名。

但是这样使用起来会有点麻烦,这是因为gcc在编译形成可执行程序的时候默认值知道系统默认的库的名称和路径,我们现在这个是我们自己新建的库,所以gcc不认识。所以我们在编译的时候还需要特别指定库名称和库路径。

指定库名称使用的是-l选项,执行库路径使用的是-L选项:

这样我们才能成功的生成可执行程序:

但我们今天还是想要做得更规范一些,一般我们的库文件和头文件是被放到一个目录结构中的,这样就更像一个整体。

我们编写一个makefile来完成再次打包的工作:

这样执行了makefile之后,我们就得到了一个更规范的库文件了:

然后使用的时候就需要注意了,因为我们上面的演示中头文件是和test.c处在同一个路径下的,所以编译的时候不需要指定头文件的路径编译器也能直接找到,而我们今天已经形成了一个库文件,也就是所我们以后其他的源代码想要用这个库中的方法,就只需要有这个库文件即可,而其他的源代码的路径下就不会有对应的头文件了,所以我们在使用的时候还需要多加一个-I的选项表示指定头文件的路径:

二、动态库的封装

2.1、动态库的封装方法

动态库的封装就和静态库有点不一样了,首先动态库的封装是直接使用gcc的,这说明gcc是可以直接形成动态库的。这个后面我也会聊一些,这是因为动态库比起静态库来说更重要,优先级也更高。

第二个不同的地方也比较特殊了,我们在形成对应的.o文件的时候还需要额外的加上一个“与位置无关码”fPIC的选项,这个后面我们简单的聊一些,其实我也不是很懂,记住就行了。

此外还需要加上一个-shared的指令,表示生成的是“共享库”,这个也是到后面聊:

其他的地方就没什么不同了,因为库的本质动态库和静态库是一样的。

所以我们就只需要修改一下makefile即可,也就是像上面生成静态库一样,将二次打包也做好:

执行makfile之后我们就形成了动态库了:

然后使用动态库生成可执行程序的时候也是个静态库一样:

但当我们直接运行的时候就会出现问题了:

如果直接运行的话,会提示找不到动态库,这时候大家可能就会有疑问了,我在形成可执行程序的时候不是已经告诉了编译器库的路径了吗?怎么还会找不到呢?

这是因为静态库和动态库的加载是不一样的。

严格来说,静态库是不需要加载的,因为静态库是在链接的时候将对应的方法一代码的形式“拷贝”到我们可执行程序的代码部分,所以自然的,运行的时候就不要再找静态库了。

而动态库不同,动态库并不是以代码的形式将拷贝到可执行程序的代码部分,它是在运行的时候才加载到“内存”,并不是加载到可执行程序中,然后由可执行程序在内存中去寻找。

所以我们也就知道了,我们编译形成可执行程序的时候只是将库的路径告诉了编译器,但运行是操作系统的事,操作系统当然不知道我们的库在哪里了。

如果想要解决动态库运行时候找不到库的问题,可以有一下四种解决方案。

2.2、解决动态库运行时找不到的三种方法

方法1:直接将动态库安装到系统中默认路径下

我们以前在编译可执行程序的时候,之所以不需要指定库路径和头文件的路径,是因为我们以前使用的都是系统默认支持的库,而这些库的头文件都会存在于系统中的两个默认的路径:/lib64/usr/include中。

所以我们今天就可以直接将我们的头文件和库拷贝到这两个路径中:

这样我们再次运行就可以正常运行了:

并且如果我们今天将可执行程序删掉在重新编译形成,也不再需要指定头文件路径和库路径了,只需要指定库名称即可:

因为我们的头文件和库已经存在于系统的默认路径下了,所以在编译的时候就像我们以前使用系统库一样再默认路径下寻找了,而之所以还需要指定库名称是因为我们实现的mymath本质上还是属于第三方库,而第三方库gcc是不认识的。

而且我们在使用ldd指令来查询可执行程序所依赖的库的时候也是可以查到的,并且显示的路径就是/lib64:

而如果我们将刚才加入的头文件和库都删掉,在用ldd查询的时候就会显示找不到对应的库了:

同时将库直接安装到系统的默认路径下也是我们以后使用第三方库最推荐的一种做法,没有之一。

方法2:在当前路径下创建连接到库的软连接:

其实这也是软连接的一个应用场景,当然啦我们也可以将软连接创建到/lib64目录下,我当前就不做了。

方法3:更改环境变量

在我们的系统中有许许多多的环境变量,而其中有一个是和我们今天动态库加载有关的环境变量——LD_LIBRARY_PATH,这个环境变量就是用来存储我们需要加载的动态库的绝对路径。

但是有的朋友可能这个环境变量是空的或者不存在,这也是很正常的,因为有可能你的系统比较新或者你从来没有设置过这个环境变量。

设置了之后我们就可以,正常的运行我们的可执行程序了:

那我们最后再来做一个实验,就是如果同一套方法,我们机提供了静态库也提供了动态库,编译器会选择哪种库呢?

我们可以先将两个库拷贝到同一个目录下:

然后我们在重新生成可执行程序,再来查看一下它所依赖的库:

从结果中我们可以看到,默认依赖的是动态库,虽然这里找不到,但是也能显示出来我们所依赖的是哪一个库(找不到是因为我们现在库的路径变了,而且我们也把原来的动态库给删除了)。

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

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

相关文章

结构体的大小以及内存对齐问题

结构体的大小怎么计算?什么是结构体的对齐? 首先想要直到结构体的大小需要先了解结构体的内存对齐。那么,什么是结构体的内存对齐: 什么是结构体内存对齐 结构体的对齐 就是 结构体类型数据在内存中按照一定的对齐规律储存。结…

python+django高校活动报名场地管理系统l1ro4

校园活动管理平台程序的开发,在数据库的选择上面,选择功能强大的MySQL数据库进行数据的存放操作。 技术栈 后端:python 前端:vue.jselementui 框架:django Python版本:python3.7 数据库:mysql5…

实现自定义标记

实现自定义标记 问题陈述 New Tech Book的高级管理层决定在其用JSP设计的应用程序的所有页面上显示版权信息。它们还要去如何向应用程序中添加JSP页面,可以重用显示版本信息的代码。公司的软件开发人员Jerry Smith决定用自定义标记来创建应用程序的这一部分。 解决方案 要解…

kali最新最简单安装

之前都是用iso镜像文件的 今年好多东西都删库了,所有还是要主要资源的保存 去官网找下载 一般来说都是用虚拟机的 下载完会是一个压缩文件, 解压,然后操作之前需要先下载虚拟机 打开方式用虚拟机打开 kali就按装好了

腾讯云4核8G服务器可以用来干嘛?怎么收费?

腾讯云4核8G服务器适合做什么?搭建网站博客、企业官网、小程序、小游戏后端服务器、电商应用、云盘和图床等均可以,腾讯云4核8G服务器可以选择轻量应用服务器4核8G12M或云服务器CVM,轻量服务器和标准型CVM服务器性能是差不多的,轻…

Minecraft的红石教程之电梯

一.前言 我记得是上初中的时候,就看到了这类电梯。现在我在看现在这类电梯的相关视频,大多是盗用创意未能领会其中的红石运作规律,于是我就删繁就简写了这篇。 二.步骤 1.材料 粘性活塞,黏液块,红石,红…

考研数据结构笔记(6)

单链表的建立 单链表的建立尾插法头插法 双链表初始化插入删除遍历小结 单链表的建立 尾插法 首先对单链表进行定义,然后初始化 法1:定义遍历链表的插入函数 法2:利用指针移动建立函数 头插法 带头结点 双链表 初始化 插入 p节点不是最后…

【Linux】学习-基础IO—下

Linux基础IO—上 重定向 通过上篇的学习,我们了解了文件描述符的分配规则是遍历指针数组,用没有被使用的最小下标作为新的文件描述符,也就是我们可以通过关闭三个标准流文件并使用他们原先所占用的0,1,2描述符。 那…

【蓝桥杯Python】试题 算法训练 藏匿的刺客

资源限制 内存限制:256.0MB C/C时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 问题描述 强大的kAc建立了强大的帝国,但人民深受其学霸及23文化的压迫,于是勇敢的鹏决心反抗。   kAc帝国防守…

元素显示模式

1.块级元素 显示特点: 1.独占一行(一行只能显示一个) 宽度默认是父元素的宽度可以设置宽高 代表标签:div、p、h系列、ul、li、dl、dd、from、header、nav、footer...... 2.行内元素 显示特点: 一行可以显示多个宽…

中国判决生效,诺基亚全面与中国手机签署授权协议,降低专利费

日前媒体报道指诺基亚与中国两家手机企业都签署了专利授权协议,全面结束诉讼,而这一切正是在OPPO于去年底在重庆法院就OPPO与诺基亚的专利费诉讼问题,做出裁决之后,要求诺基亚按公平、公正等合理收费原则收取专利费。 这几年诺基亚…

HiveSQL——连续增长问题

注:参考文章: SQL连续增长问题--HQL面试题35_sql判断一个列是否连续增长-CSDN博客文章浏览阅读2.6k次,点赞6次,收藏30次。目录0 需求分析1 数据准备3 小结0 需求分析假设我们有一张订单表shop_order shop_id,order_id,order_time…

动态水印怎么加 怎么去除动态水印 视频剪辑软件 会声会影安激活序列号 会声会影怎么剪辑视频

为了防止白嫖或者增加美观效果,视频制作者可能会采用动态水印的方式,让其他人难以盗取视频使用。动态水印的添加,需要应用到运动路径功能。接下来,本文会教大家动态水印怎么加,怎么去除动态水印的相关内容。感兴趣的小…

第67讲自定义icon实现

element-plus内置有一些常用的icon供我们使用&#xff0c;但是我们假如需要用自己的icon时候&#xff0c;我们可以搞一个icon自定义组件&#xff1b; 先把icons文件放到src下&#xff1b; 再新建一个SvgIcon组件&#xff1b; index.vue <template><svg class"…

【Linux】指令提权-sudo

Hello everybody&#xff0c;新年快乐&#xff01;哈哈&#xff01;今天打算给大家讲讲指令提权的相关知识&#xff0c;虽然内容不多&#xff0c;但有时却很有用。在我们学习过权限&#xff0c;vim后就可以学习指令提权啦&#xff0c;没看过的宝子们建议先去看一看我之前的文章…

【数据存储+多任务爬虫】

数据存储 peewee模块 第三方模块&#xff0c;也需要在cmd中安装。 from peewee import *db MySQLDatabase("spider",host"127.0.0.1",port3306,userroot,password123456 )# 类》表 class Person(Model):name CharField(max_length20) # 类型/约束bi…

C# WinForm开发系列 - DataGridView

原文地址&#xff1a;https://www.cnblogs.com/peterzb/archive/2009/05/29/1491891.html 1.DataGridView实现课程表 testcontrol.rar 2.DataGridView二维表头及单元格合并 DataGridView单元格合并和二维表头.rar myMultiColHeaderDgv.rar 3.DataGridView单元格显示GIF图片 …

第70讲axios后端请求工具类封装

axios工具类封装&#xff1a; // 引入axios import axios from axios;// 创建axios实例 const httpService axios.create({// url前缀-http:xxx.xxx// baseURL: process.env.BASE_API, // 需自定义baseURL:http://localhost:80/,// 请求超时时间timeout: 3000 // 需自定义 })…

Linux中常用的工具

软件安装 yum 软件包 在Linux中&#xff0c;软件包是一种预编译的程序集合&#xff0c;通常包含了用户需要的应用程序、库、文档和其他依赖项。 软件包管理工具是用于安装、更新和删除这些软件包的软件。常见的Linux软件包管理工具包括APT&#xff08;Advanced Packaging To…

Linux第45步_通过搭建“DNS服务器”学习图形化配置工具

学习的意义&#xff1a;通过搭建“DNS服务器”&#xff0c;来学习“图形化配置工具”。“DNS服务器”&#xff0c;我们用不到&#xff0c;但为后期移植linux系统服务&#xff0c;因为在移植系统时&#xff0c;需要用到这个“图形化配置工具”。 1、“menuconfig图形化配置工具…