【Linux】六、Linux 基础IO(四)|动态库和静态库

news2024/11/27 10:30:05

目录

十一、动态库和静态库

11.1 动态库和静态库定义

11.2 动静态库的基本原理

11.3 静态库的打包与使用

11.3.1 静态库的打包

11.3.2 静态库的使用

11.4 动态库的打包与使用

11.4.1 动态库的打包

11.4.2 动态库的使用

11.5 动态库的加载


十一、动态库和静态库

11.1 动态库和静态库定义

静态库定义:

        静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库

        在 Linux 其后缀名一般为 “.a”,在Windows下其后缀一般为 “.lib”

动态库定义: 

        动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码

        在 Linux下动态库一般后缀名为“.so”,在Windows下其后缀一般为 “.dll”

ldd 命令查看可执行程序所依赖的库

ldd 可执行程序名字

        这里可执行程序所依赖的其中一个库是 libc.so.6,它实际上就是 C动态库,当我们去掉一个动静态库的前缀 lib,再去掉后缀 .so 及其后面的版本号,剩下的就是这个库的名字,比如 lib.so.6 去掉前缀和后缀后就剩下 c c 就是这个动态库的名字

file 命令则辨别可执行程序的类型,是静态库还是动态库 

file 可执行文件名字

注:gcc/g++ 在编译时默认使用动态库进行链接

若想进行静态链接,可以携带一个 -static 选项 

gcc -o mytest-s test.c -static //此选项对生成的文件采用静态链接

        静态链接生成的可执行程序并不依赖其他库文件,此时当我们使用 ldd 命令查看该可执行程序所依赖的库文件时就会看到以下信息 

明显发现静态链接生成的可执行程序的文件大小,比动态链接生成的可执行程序的文件大小要大得多

注意:使用 -static 首先要安装静态库,因为Linux下没自带有,输入如下指令进行安装,输入用户密码即可进行安装 

//C语言静态库安装
sudo yum install -y glibc-static
//C++静态库安装
sudo yum install -y libstdc++-static

11.2 动静态库的基本原理

        动静态库的本质是一堆目标文件(xxx.o)的集合

一个源程序经过以下步骤才会变成可执行程序:

  1. 预处理: 完成头文件展开、去注释、宏替换、条件编译等,最终形成 xxx.i 文件
  2. 编译: 完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成 xxx.s 文件
  3. 汇编: 将汇编指令转换成二进制指令,最终形成 xxx.o 文件
  4. 链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序

动静库就是多个源文件经过预处理、编译、汇编,然后形成多个 .o 文件,然后再将这些 .o 文件链接起来,最终形成一个可执行程序

        所有库本质都是一堆目标文件(xxx.o)的集合,库的文件当中并不包含主函数(main函数),而只是包含了大量的方法以供其他程序调用

11.3 静态库的打包与使用

11.3.1 静态库的打包

测试使用代码

add.h

#pragma once

extern int add(int x, int y);

add.c

#include "add.h"

int add(int x, int y)
{
    return x+y;
}

sub.h

#pragma once

extern int sub(int x, int y);

sub.c

#include "sub.h"

int sub(int x, int y)
{
    return x-y;
}

目的:使用 add.c 和 sub.c 生成一个库

先介绍相关命令

gcc –c 源文件 –o 生成目标文件

“-c”选项把代码转换成二进制代码,即汇编完成就停下来,“-o”是指生成的目标文件

ar -rc 生成库的名字 源文件...

ar 命令是 gnu 的归档工具,常用于将目标文件打包为静态库,ar(archive)

  • -r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件
  • -c(create):建立静态库文件

(1)将源文件编译生成 .o 文件

(2)使用 ar 命令生成静态库

(3)将头文件和生成的静态库组织起来,打包到同一个文件,再压缩就可以发给别人,别人就使用了 

        这样一个静态库就打包好了,但是使用一条条命令敲太麻烦了,可以使用 Makefile 

libmymath.a:myadd.o mysub.o    
    ar -rc $@ $^    
myadd.o:add.c    
    gcc -c add.c -o myadd.o    
mysub.o:sub.c    
    gcc -c sub.c -o mysub.o    
    
.PHONY:clean    
clean:    
    rm -rf *.o libmymath.a mylib    
    
.PHONY:output 
output:     
    mkdir -p mylib/include    
    mkdir -p mylib/lib    
    cp -f *.a mylib/lib    
    cp -f *.h mylib/include                

注:output 就是把相关文件打包在一起

再 output 打包,进行压缩就可以发给别人了

11.3.2 静态库的使用

        比如,张三想要使用这个库,你把库打包给了张三,张三解压到了自己的目录下,然后张三尝试使用你提供的库

测试代码:

该目录下只有一个测试的源文件和你提供的库

使用gcc编译main.c生成可执行程序时需要携带三个选项

  • -I:指定头文件搜索路径(大写的i)
  • -L:指定库文件搜索路径
  • -l:指明需要链接库文件路径下的哪一个库(L的小写)

不指明这三个选项是编译不了的

gcc test.c -o mytest -I./mylib/include -L./mylib/lib -lmymath

注:

  1. 因为编译器不知道你所包含的头文件add.h,sub.h在哪里,所以需要指定头文件的搜索路径
  2. 头文件 add.h,sub.h 当中只有 add(),sub() 函数的声明,并没有该函数的定义,所以还需要指定所要链接库文件的搜索路径
  3. 我们需要指明需要链接库文件路径下的哪一个库,因为 lib 目录下可能会有大量的库文件,编译器不知道使用哪一个库
  4. 库文件名去掉前缀 lib,再去掉后缀 .so 或 .a 及其后面的版本号,剩下的就是库的名字
  5. -I,-L,-l 选项后面可带空格也可以不带
  6. 我们平时使用 C/C++ 的头文件不用加这么繁琐的选项可以直接编译,这是因为我们所写的库不在系统的默认路径下
  7. 还要 -l(L的小写)指定库名字是因为要链接的是哪一个库编译器是不知道的,而我们使用的 C/C++ 头文件编译器默找的就是 C/C++ 的库,所以我们自己或他人写的库要指定库的名字

file 查看一下

怎么这么奇怪,我提供的不是静态库码,怎么还是动态链接?

  1.  gcc 默认是动态链接的(建议行为),对于特定的一个库,究竟是动态链接还是静态链接,取决于你提供的是动态库还是静态库
  2. 一个可执行性程序不可能只依赖一个库函数,也就是说必须依赖多个库函数
  3. 但是,假设动静态库同时给你,编译器只能把静态库拷贝到可执行程序里面,然后只能进行动态链接,哪怕只有一个动态库剩下的全是静态库,链接依旧是动态链接
  4. 全部提供的是动态库,链接也是动态链接;提供有指定的静态库,再以静态的方式编译,这样链接就是静态链接

我们可以试着把库拷贝到系统路径下

进行拷贝

编译,运行

注:需要指明需要链接库文件路径下的哪一个库,因为编译的时候默认就找的是C库(使用的是 C语言)

        实际上我们拷贝头文件和库文件到系统路径下的过程,就是安装的过程

记得把自己拷贝到系统路径下文件删去 !!

11.4 动态库的打包与使用

11.4.1 动态库的打包

代码依旧是上面的

(1)将源文件编译生成 .o 文件,这里要给 gcc 加多一个选项

        -fPIC(position independent code):产生位置无关码

(2)生成动态库时我们不必使用ar命令,使用 gcc 生成动态库即可,这里也是多加了一个选项 -shared

gcc -shared -o libmymath.so sub.o add.o 

(3)将头文件和生成的动态库组织起来,打包到同一个文件,再压缩就可以发给别人,别人就使用了

这样一个动态库就打包好了,但是使用一条条命令敲太麻烦了,可以使用 Makefile 

直接 make 就可以生成一个动态库了  

再 make output 打包,进行压缩就可以发给别人进行使用了 

11.4.2 动态库的使用

        比如,张三想要使用这个库,你把库打包给了张三,张三解压到了自己的目录下,然后张三尝试使用你提供的库,测试代码依旧是上面的

该目录下只有一个测试的源文件和你提供的库

  

        使用该动态库的方法与刚才我们使用静态库的方法一样,我们既可以使用  -I-L-l 这三个选项来生成可执行程序,也可以先将头文件和库文件拷贝到系统目录下,然后仅使用 -l(L的小写)选项指明需要链接的库名字来生成可执行程序

  • -I:指定头文件搜索路径(大写的i)
  • -L:指定库文件搜索路径
  • -l:指明需要链接库文件路径下的哪一个库(L的小写)
gcc test.c -o mytest  -I./mylib/include -L./mylib/lib -lmymath

 但是这次程序运行不了,可执行程序运行起来后,操作系统找不到该可执行程序所依赖的动态库

ldd 查看

解决该问题的方法有以下三个:

(1)第一个是将库函数和相关的头文件拷贝到系统路径下,一般拷贝到这两个目录下,这个就不测试了

(2)更改添加 LD_LIBRARY_PATH

        动态库加载会在系统路径下查找,也会在 LD_LIBRARY_PATH 这个环境变量下查找,添加这个动态库的路径到这个环境变量里面

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/fy/code/code_linux/code_202301_12/d7/mylib/lib

再次运行

注:export  添加这个动态库的路径到这个环境变量里面,只会在当前登录的 shell 有效,下次登录无效,程序依旧无法运行

(3)配置 /ect/ld.so.conf.d/ 文件

        可以通过配置 /etc/ld.so.conf.d/ 的方式解决该问题,/etc/ld.so.conf.d/ 路径下存放的全部都是以 .conf 为后缀的配置文件,而这些配置文件当中存放的都是路径,系统会自动在 /etc/ld.so.conf.d/ 路径下找所有配置文件里面的路径,之后就会在每个路径下查找你所需要的库

        若是将自己库文件的路径也放到该路径下,那么当可执行程序运行时,系统就能够找到这个库文件了

在这个路径下新建一个以 .conf 结尾的文件 

将动态库所在的目录拷贝到这个文件里面

再次运行程序

        原因是我们没有更新配置文件,使用 ldconfig 命令将配置文件更新一下,更新之后系统就可以找到该可执行程序所依赖的动态库 

[fy@VM-4-14-centos d7]$ sudo ldconfig

11.5 动态库的加载

静态库不需要加载,所以不考虑静态库的加载

        静态库是程序在编译的时候把库的代码复制到可执行程序的地址空间的代码区中,生成的可执行程序在运行的时候将不再需要静态库,因此使用静态库生成的可执行程序的大小比较大

优点:

        使用静态库生成可执行程序后,该可执行程序就可以独自运行,不再需要库了

缺点:

        使用静态库生成可执行程序会占用大量磁盘空间,特别是当有多个静态链接的程序同时运行时,这些静态链接的程序使用的都是很多相同的库,这时在内存当中就会存在大量的重复代码,造成内存浪费

动态库

        动态库是程序在运行的时候才去链接相应的动态库代码的,多个程序共享使用库的代码

         在可执行文件加载到内存时,所需要的动态库会从磁盘上加载到内存中,函数地址再由内存通过页表映射到这个可执行程序的共享区中,这个过程称为动态链接。动态库在多个程序间共享,节省了大量的磁盘空间和内存

优点:

        节省磁盘空间,且多个用到相同动态库的程序同时运行时,库文件会通过进程地址空间进行共享,内存当中不会存在重复代码。

缺点:

        必须依赖动态库,否则无法运行

----------------我是分割线---------------

文章到这里就结束了,基础IO篇章结束,下一篇即将更新

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

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

相关文章

CB2-2CARD的openSUSE安装NAS环境配置

CB2-2CARD的openSUSE安装&NAS环境配置1. 简介2. 规格3. 系统安装3.1 Linux/Unix稳定镜像3.2 基础功能更新&安装3.2.1 更新源3.2.2 升级系统3.2.3 基础功能安装3.3 OpenSUSE系统情况3.3.1 源操作命令3.3.2 源镜像4. 需求 & 配置4.1 MiniDLNAStep 1:安装M…

Day870.全局锁和表锁 -MySQL实战

全局锁和表锁 Hi,我是阿昌,今天学习记录的是关于全局锁和表锁的内容。 数据库锁设计的初衷是处理并发问题。 作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。锁就是用来实现这些访问规则的重…

数据结构 | C++ | 并查集原理讲解与模拟实现 | 并查集的相关习题

文章目录前言并查集原理并查集的模拟实现leetcode练习省份数量等式方程的可满足性前言 并查集通常会作为高阶数据结构的一个子结构使用,虽然原理不是很难,但其思想值得我们好好学习 并查集原理 并查集是一种树形结构,其保存了多个集合&…

【Maven】多环境配置与应用

目录 1. 多环境配置作用 问题导入 2. 多环境配置步骤 2.1 定义多环境 2.2 使用多环境(构建过程) 3. 跳过测试(了解) 问题导入 3.1 应用场景 3.2 跳过测试命令 3.3 细粒度控制跳过测试 1. 多环境配置作用 问题导入 多…

LeetCode 2331. 计算布尔二叉树的值

给你一棵 完整二叉树 的根,这棵树有以下特征: 叶子节点 要么值为 0 要么值为 1 ,其中 0 表示 False ,1 表示 True 。 非叶子节点 要么值为 2 要么值为 3 ,其中 2 表示逻辑或 OR ,3 表示逻辑与 AND 。 计算…

【推荐系统】User-Item CF:NGCF

💡 本次解读的文章是 2019 年发表于 SIGIR 的一篇基于图卷积神经网络的用户物品协同过滤推荐算法论文, 论文将用户-物品交互信息建模为二分图,提出了一个基于二分图的推荐框架 Neural Graph Collaborative Filtering(NGCF&#xf…

基于nodejs+vue的社区问答网站与设计

目 录 摘要 I Abstract II 1 绪论 1 1.1 选题背景 1 1.2 选题意义 1 1.3 研究内容 2 2 相关技术介绍 3 3 系统分析 5 3.1可行性分析 5 3.2 需求分析 5 3.2.1非功能性需求 5 3.2.2功能需求 6 3.3 系统用例 6 3.3.1 会员功能需求 6 …

【C++修炼之路】13. priority_queue及仿函数

每一个不曾起舞的日子都是对生命的辜负 stack&&queue一 . priority_queue介绍二. priority_queue的使用三. 仿函数3.1 仿函数的介绍3.2 仿函数的好处四.priority_queue模拟实现五.仿函数之日期比较一 . priority_queue介绍 priority_queue文档介绍 优先队列是一种容器…

机器学习实战(第二版)读书笔记(2)—— LSTMGRU

刚接触深度学习半年的时间,这期间有专门去学习LSTM ,这几天读机器学习实战这本书的时候又遇到了,感觉写的挺好的,所以准备结合本书写一下总结方便日后回顾。如有错误,欢迎批评指正。 一、LSTM 优势:可在一…

ApiSix 开启SkyWalking插件,实现链路信息追踪

ApiSix 开启SkyWalking插件,实现链路信息追踪1 ApiSix开启SkyWalking插件1.1 修改config.yml配置文件1.2 在路由中开启SkyWalking插件2 创建两个SpringBoot服务,接入SkyWalking2.1 下载skywalking agent2.2 创建服务2.3 测试SkyWalking1 ApiSix开启SkyWa…

【链表】反转链表

BM1反转链表 描述 给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。 数据范围: 0\leq n\leq10000≤n≤1000 要求:空间复杂度…

飞行员兄弟( 二进制枚举) --《算法竞赛进阶指南》

题目如下: 输入样例: --- ---- ---- ---输出样例: 6 1 1 1 3 1 4 4 1 4 3 4 4思路 or 题解: 数据量很小可以直接进行 搜索 在这里我使用 二进制枚举 的方法去寻找答案 时间复杂度:O(2n)O(2^n)O(2n) 我们二进制枚举…

计算机相关专业混体制的解决方案(事业编之学校与医院)

文章目录1、教师行业1.1 中小学教师资格1.2 高校教师资格证1.3 应聘中小学教师1.4 待遇2、医疗行业2.1 如何进入医院信息科2.2 医院信息科工作内容2.3 医院信息科待遇主要介绍三个方面: 1、招聘条件,要求是什么。 2、工作内容,需要我做什么工…

【哈希表】leetcode242.有效的字母异位词(C/C++/Java/Python/Js)

leetcode242.有效的字母异位词1 题目2 思路 (字典解法)3 代码3.1 C版本3.2 C版本3.3 Java版本3.4 Python版本3.5 JavaScript版本4 总结1 题目 题源链接 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xf…

【JavaScript】多态(Symbol),迭代器接口,getter/setter,继承,instanceof

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录多态symbol迭代器接口实现数组的迭代器方法练习Getter/Setterstatic继承instanceof多态 我拿到一…

虽迟但到,我的2022年终总结

“子在川上曰,逝者如斯夫”。经历一年的居家办公、解封,终于在年底回归正常生活。时隔三年回老家过年,一切如故,好像疫情从没有来过。2022年对我来说是值得记忆的一年,在这一年里完成了买房这件人生大事,终…

SpringCloud学习笔记【part1】Spring Cloud Gateway网关的搭建、处理跨域问题

一、Spring Cloud Gateway 介绍 API网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先…

macos nginx 安装/卸载,启动/重启/关闭

1.安装/卸载 在macos中使用homebrew安装 brew install nginx,卸载brew uninstall nginx。homebrew安装 brew install xx,卸载brew uninstall xx 可以直接安装nginx-full,来安装echo模块 brew install nginx-full # 如果上面安装报错,需要按…

C 程序设计教程(18)—— 数组和指针(一):数组

C 程序设计教程(18)—— 数组和指针(一):数组 该专栏主要介绍 C 语言的基本语法,作为《程序设计语言》课程的课件与参考资料,用于《程序设计语言》课程的教学,供入门级用户阅读。 目…

【SpringCloud复习巩固】微服务+Eureka+Ribbon

文章中需要用到的代码和sql 链接:https://pan.baidu.com/s/1_1Qqro7wR5zi7Ds8Bgmf-g 提取码:vxzg 目录 一.微服务 1.1单体架构 1.2分布式架构 1.3微服务 1.4各自特点总结 1.5微服务技术对比 二.服务拆分及远程调用 三.Eureka注册中心 3.1服务调用…