【Linux】六、Linux 基础IO(四)

简介: 目录十一、动态库和静态库11.1 动态库和静态库定义11.2 动静态库的基本原理11.3 静态库的打包与使用11.3.1 静态库的打包11.3.2 静态库的使用11.4 动态库的打包与使用11.4.1 动态库的打包11.4.2 动态库的使用11.5 动态库的加载

目录

十一、动态库和静态库

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 就是这个动态库的名字

image.png

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

file 可执行文件名字

image.png

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

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

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

image.png

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

image.png

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

image.png

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

//C语言静态库安装sudoyuminstall-yglibc-static//C++静态库安装sudoyuminstall-ylibstdc++-static

11.2 动静态库的基本原理

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

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

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

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

image.png

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

11.3 静态库的打包与使用

11.3.1 静态库的打包

测试使用代码

image.png

add.h

#pragma onceexternintadd(intx, inty);

add.c

#include "add.h"intadd(intx, inty)
{
returnx+y;
}

sub.h

#pragma onceexternintsub(intx, inty);

sub.c

#include "sub.h"intsub(intx, inty)
{
returnx-y;
}

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

先介绍相关命令

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

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

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

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

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

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

image.png

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

image.png

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

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

libmymath.a:myadd.omysub.oar-rc$@$^myadd.o:add.cgcc-cadd.c-omyadd.omysub.o:sub.cgcc-csub.c-omysub.o.PHONY:cleanclean:    
rm-rf*.olibmymath.amylib.PHONY:outputoutput:     
mkdir-pmylib/includemkdir-pmylib/libcp-f*.amylib/libcp-f*.hmylib/include

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

image.png

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

image.png

11.3.2 静态库的使用

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

测试代码:

image.png

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

image.png

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

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

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

image.png

gcctest.c-omytest-I./mylib/include-L./mylib/lib-lmymath

image.png

注:

  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 查看一下

image.png

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

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

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

image.png

进行拷贝

image.png

编译,运行

image.png

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

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

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

11.4 动态库的打包与使用

11.4.1 动态库的打包

代码依旧是上面的

image.png

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

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

image.png


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

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

image.png

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

image.png

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

image.png

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

image.png

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

image.png

11.4.2 动态库的使用

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

image.png

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

image.png

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

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

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

image.png

ldd 查看

image.png

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

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

image.png

(2)更改添加 LD_LIBRARY_PATH

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

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

image.png

再次运行

image.png

注: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 结尾的文件

image.png

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

image.png

再次运行程序

image.png

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

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

image.png

11.5 动态库的加载

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

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

优点:

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

缺点:

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

动态库

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

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

image.png

优点:

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

缺点:

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

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

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

相关文章
|
1月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
92 0
|
1月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
86 1
Linux C/C++之IO多路复用(aio)
|
3月前
|
缓存 安全 Linux
Linux 五种IO模型
Linux 五种IO模型
|
1月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
25 0
Linux C/C++之IO多路复用(poll,epoll)
|
3月前
|
小程序 Linux 开发者
Linux之缓冲区与C库IO函数简单模拟
通过上述编程实例,可以对Linux系统中缓冲区和C库IO函数如何提高文件读写效率有了一个基本的了解。开发者需要根据应用程序的具体需求来选择合适的IO策略。
34 0
|
3月前
|
存储 IDE Linux
Linux源码阅读笔记14-IO体系结构与访问设备
Linux源码阅读笔记14-IO体系结构与访问设备
|
4月前
|
Linux 数据处理 C语言
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
77 0
|
4月前
|
Linux 编译器 C语言
【Linux】基础IO----理解缓冲区
【Linux】基础IO----理解缓冲区
70 0
【Linux】基础IO----理解缓冲区
|
4月前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
221 2
|
5月前
|
Linux 编译器 C语言
【Linux】基础IO_4
【Linux】基础IO_4
29 3
下一篇
无影云桌面