IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux的动态库和静态库 -> 正文阅读

[系统运维]Linux的动态库和静态库

动静态库

动静态库的概念

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统**从磁盘上的该动态库中复制到内存中,**这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
  • 系统默认库命名规则:lib+name.so.version。去掉lib和第一个.后的就是库的名字

动态链接的特点

ldd 文件名

image-20220112091749998

/lib64/libc.so.6是软链接

image-20220112092056943

当顺序执行到printf中程序中没有该函数,跳转到库中执行完再返回后续代码执行。动态库并没有把代码拷贝进来,因此程序体积比较小。

image-20220112092333001

objdump -d test:

image-20220301162558586

  • 动态链接的特点

    • 体积小

      • image-20220112092818698
    • 依赖库

      • 因此删库之后连系统中以C为依赖的命令都用不了了。
    • 运行的时候加载的,可以只有一份。而进程在内存中,没跑到对应函数的时候是不会将处于磁盘上的动态库中的对应代码加载到内存中的

静态链接的特点

gcc -o $@ $^ -static

image-20220112092923450

静态库是将对应的printf函数部分拷贝到自己的程序中。

image-20220112093615253

objdump -d test-s

image-20220301162850628

  • 静态链接的特点
    • 将对应代码拷贝进bin,体积比较大
    • bin可移植性强
    • 链接的时候纳入进来,可能比较占资源(硬盘和内存)
      • 比如每个程序都用了printf,那每份程序里面的printf其实就是冗余的

查看文件的动静态链接属性

file 文件名

image-20220112093338810

动态链接的机理

通过代码区找到映射区的区域,通过页表找到内存中动态库的位置。

image-20220112101315589

当前是一个进程,如果是100个动态链接的进程,代码是只读的,其他进程通过各自页表映射进程地址空间的共享区,因此库我文件只要一份就行。

image-20220117105540492

而静态链接是把拷贝进来的代码放在代码区了,所以代码区变得很大。

生成&&使用静态库

我们要提供两个东西,头文件和库文件。

一批头文件:有什么方法可以使用,接口参数是什么意思

一个、多个库文件:具体的实现,供我们动静态链接。

链接的本质:链接.o文件,lib文件。

而动静态库就是把所有.o文件打包,命令成.a。

#ifndef MY_LIB_H
#define MY_LIB_H
#include<stdio.h>
void myprintf();

#endif

#include"mylib.h"

void myprintf()
{
  printf("hello world!\n");
}

image-20220112102829916

gcc -c xxx.c

image-20220112102956112

单纯不带包给别人用只要把.o和.h给别人即可。不过这样使用注意需要makefile的时候加上其.o为依赖项目,不然找不到对应的符号。

test:test.c mylib.o
	gcc -o $@ $^ 
.PHONY:clean
clean:
	rm -rf *.o test test-static
#include"mylib.h"

int main()
{
  myprintf();
}

image-20220112103527778

但是数量多起来就不方便了,需要打包。

  1. 自己定义库——一批头文件和源文件,只把源文件处理成.o,使用ar -rc(replace and create)打包成一个静态库
  2. 给别人使用的时候提供头文件和静态库。但是gcc的时候面临问题,比如头文件和静态库不在当前目录下(如果在当前目录下-I就不需要了),需要-I指出头文件目录,需要-L指明库的搜索路径,-l指出库搜索路径中的要用的库名(去掉lib和.后的,可以带空格也可以不带),-static指出静态链接。
  • 第一步:将.o文件打包成静态库
ar -rc libxxx.a xxx.o xxx.o

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

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

image-20220112125312073

  • 第二步:使用静态库

image-20220112125409006

path = $(shell pwd) #可以不要这个path使用相对路径

test:test.c
	gcc -o $@ $^ -I $(path)/mylib/include -L $(path)/mylib/lib -l mymath -static
	
.PHONY:clean
clean:
	rm -f test
  • -I选项指定头文件搜索路径
  • -L选项指定库文件搜索路径
  • -l选项指明需要链接库文件路径下的哪一个库

但是这样挺麻烦的,怎么样不用这些选项呢?

有一种粗暴的方式是把自己的头文件和库扔到stdio.hlibc.a的系统默认的搜索路径下。但是这样做会污染其他文件环境。所以还是乖乖地放当前路径下文件夹中把选项带上。

(所谓框架就是这样,下载来之后就是一堆头文件和库)

sudo cp mylib/include/* /usr/include/
sudo cp mylib/lib/libmymath.a /lib64/

需要注意的是,虽然已经将头文件和库文件拷贝到系统路径下,但当我们使用gcc编译main.c生成可执行程序时,还是需要-l指明需要链接库文件路径下的哪一个库。

./test -lmymath

为什么之前使用gcc编译的时候没有指明过库名字?

因为我们使用gcc编译的是C语言,而gcc就是用来编译C程序的,所以gcc编译的时候默认就找的是C库,但此时我们要链接的是哪一个库编译器是不知道的,因此我们还是需要使用-l选项,指明需要链接库文件路径下的哪一个库。

生成&&使用动态库

extern"C"的实例见c++基础的笔记。

windows中的动态库为.dll,静态库是.lib。

  • 第一步:让所有源文件生成对应的目标文件
gcc -fPIC -c add.c
gcc -fPIC -c sub.c

此时用源文件生成目标文件时需要携带-fPIC选项:

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

说明:

  1. -fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
  2. 如果不加-fPIC选项,则加载.so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的拷贝,并且每个拷贝都不一样,取决于这个.so文件代码段和数据段内存映射的位置。
  3. 不加-fPIC编译出来的.so是要在加载时根据加载到的位置再次重定位的,因为它里面的代码BBS位置无关代码。如果该.so文件被多个应用程序共同使用,那么它们必须每个程序维护一份.so的代码副本(因为.so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)。
  4. 我们总是用-fPIC来生成.so,但从来不用-fPIC来生成.a。但是.so一样可以不用-fPIC选项进行编译,只是这样的.so必须要在加载到用户程序的地址空间时重定向所有表目。
  • 第二步:使用-shared选项将所有目标文件打包为动态库
gcc -shared -o libmymath.so add.o sub.o

-shared 代表共享库

  • 第三步:将头文件和生成的动态库组织起来

将add.h和sub.h放到include下,将动态库文件放到lib下,两个文件都放到mylib下。此时就可以给别人使用了。

  • 封装成makefile

生成动态库的makefile

libmymath.so:myadd.o mysub.o
	gcc -shared -o $@ $^
myadd.o:myadd.c
	gcc -fPIC -c $<
mysub.o:mysub.c
	gcc -fPIC -c $<

.PHONY:output
output:		#打包发给别人的
	mkdir -p mylib/include
	mkdir -p mylib/lib
	cp *.h mylib/include
	cp *.so mylib/lib
	
.PHONY:clean
clean:
	rm -rf output *.o libmymath.so

生成.out的makefile

path = $(shell pwd) #可以不要这个path使用相对路径

test:test.c
	gcc -o $@ $^ -I $(path)/mylib/include -L $(path)/mylib/lib -l mymath 
	
.PHONY:clean
clean:
	rm -f test

光是这样生成并不能使用动态库,因为程序要使用的时候操作系统不知道动态库在哪。上述的行为是让gcc知道的-l动态库。

因此让操作系统知道使用的动态库方法有三:

  1. 我们需要将自己的动态库文件拷贝到系统共享库路径下/usr/lib

    sudo cp mlib/lib/libmymath.so /lib64
    
  2. 更改LD_LIBRARY_PATH

    类似PATH帮我们找可执行程序,这个环境变量帮我们找动态库

ldd test

image-20220301192820325

export LD_LIBRARY_PATH=/home/ycb/demo1/mylibso/mylib/lib
ldd test

image-20220301192946244

此时结果正常运行

image-20220301193007357

  1. 配置/etc/ld.so.conf.d/+ldconfig更新

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

image-20220301194049702

使用外部库

系统中其实有很多库,它们通常由一组互相关联的用来完成某项常见工作的函数构成。

gcc -Wall test.c -o test -lm
#include <math.h>
#include <stdio.h>
int main(void)
{
 	double x = pow(4.0, 5.0);
 	printf("%lf\n", x);
 	return 0;
}

对于这份代码,加不加math.h都能跑出来。当然加了C语言的第三方库的libm.so也能跑出来。

ls /usr/lib64/libm.so

image-20220112133831480

但是在老版本中可能会找不到对应的库。(比如上次做yacc的编译原理lab的时候没有-l m导致pow一直没反应。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:53:58  更:2022-03-03 16:57:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 3:36:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码