Linux(七) 动静态库

目录

一、动静态库的概念

二、静态库的打包与使用

2.1 静态库的打包

2.2 静态库的使用

三、动态库的打包与使用

3.1 动态库的打包

3.2 动态库的使用

3.3 运行动态库的四种方法

四、总makefile


一、动静态库的概念

静态库: Linux下,以.a为后缀的文件。程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。本质是在编译时把静态库中的代码(不是一次性加载,而是分页加载)复制到了进程的的代码区中。
动态库: Linux下,以.so为后缀的文件。程序在运行的时候才去链接动态库的代码,在可执行程序装载或运行时,由操作系统的装载程序加载库,多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
静态链接: 将库中的相关代码复制进可执行程序中的过程。
动态链接: 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中。
链接的本质: 使.o文件可以找到要调用的函数的位置
库文件名称: 比如libc.so,去掉前缀lib和后缀.so,剩下的就是库名。libhello.a的库名就是hello。

头文件gcc的默认搜索路径是 /usr/include
库文件的默认搜索路径是 /usr/lib64

把文件拷贝到系统的默认路径下就叫做库的安装,拷贝之后就不用 -I 和 -L了


实例演示: 分别使用静态链接和动态链接编译生成两个可执行程序,比较两个程序的大小
使用gcc静态链接编译时,命令要带上**-static** 选项,如下:

gcc -o test test.c -static

 

可以看到的是,使用静态库静态链接成的可执行程序比动态链接生成的可执行程序要大很多。
我们还可以通过file命令查看文件的链接属性:
 还可以通过ldd 命令查看可执行程序的依赖库,动态链接生成的可执行程序才有依赖库,静态链接升序的可执行程序不依赖任何库文件,因为库文件的代码已经复制进可执行程序了。

因为这里是动态链接,不仅要让编译器动态库的路径,还要让操作系统知道,所以这里我们需要导入一个环境变量LD_LIBRARY_PATH,如下:

export LD_LIBRARY_PATH=/home/dgz/linux/lesson26/lib/uselib/output/lib

执行完之后

总结动静态库的优缺点
静态库

  • 优点: 程序运行的时候将不再需要静态库,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。
  • 缺点:一是浪费空间,因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,如多个程序中都调用了printf()函数,则这多个程序中都含有printf.o,所以同一个目标文件都在内存存在多个副本;另一方面就是更新比较困难,因为每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。

动态库

  • 优点: 动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间.动态链接的优点显而易见,就是即使需要每个程序都依赖同一个库,但是该库不会像静态链接那样在内存中存在多分,副本,而是这多个程序在执行时共享同一份副本;另一个优点是,更新也比较方便,更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标
  • 缺点: 程序运行的时候依赖动态库,  据估算,动态链接和静态链接相比,性能损失大约在5%以下。经过实践证明,这点性能损失用来换区程序在空间上的节省和程序构建和升级时的灵活性是值得的。

二、静态库的打包与使用

2.1 静态库的打包

静态库打包: 本质其实就是将代码编译成.o的二进制文件,然后进行打包。
为了更好地演示这个过程,我创建了mymath.cmymath.hmyprint.cmyprint.h四个文件,内容分别如下:
mymath.c
 

#include "mymath.h"
int Add_(int a,int b)
{return a+b;
}


mymath.h
 

#pragma once
#include <stdio.h>extern int Add_(int a,int b);


myprint.c
 

#include "myprint.h"
void printf_(const char* str)
{printf("hello %s [%d]\n",str,(int)time(NULL));
}


myprint.h

#pragma once 
#include <stdio.h>
#include <time.h>extern void printf_(const char* str);

如下: 

打包静态库的步骤

  1. 先将myadd.cmysub.c 变成生成对应的二进制文件
  2. 使用ar 归档工具对两个二进制文件进行打包,同时带上选项**-rc**(r和c分别代表replace和creat),这里的库名是hello。
     

    ar -rc libhello.a *.o

  3. 上面这两个步骤其实就把静态库打包好了,下面我们还有做一个工作就是发布静态库,简单地说,就是把头文件和静态库组织起来,头文件放在include 下,如下:

  4. 这样一个库文件就可以给别人使用了。
    上面的所有步骤我们可以写进Makefile里,利用make指令一键打包和make output发布,如下:

    libhello.a:myprint.o mymath.oar -rc libhello.a myprint.o mymath.o
    mymath.o:mymath.cgcc -c mymath.c -o mymath.o
    myprint.o:myprint.cgcc -c myprint.c -o myprint.o.PHONY:output
    output:mkdir -p output/lib mkdir -p output/includecp -rf *.h output/includecp -rf *.a output/lib
    .PHONY:clean
    clean:rm -rf *.o *.a output

2.2 静态库的使用

先把静态库放到一个测试目录下:

然后编写一段代码:
 

#include "myprint.h"
#include "mymath.h"int main()
{int ret = Add_(1,2); printf("%d\n",ret);printf_("dgz");return 0;
}

编写Makefile:
使用gcc编译时,采用静态链接编译,所以要带上选项**-static**,此外,因为我们使用了别人给的静态库,所以我们还有告诉编译器库文件所在路径,头文件所在路径以及库名,所以要用到以下三个选项:

  • -L: 指明库文件所在路径
  • -I: 指明头文件所在路径
  • -l: 指明库文件名称,这里库名就是hello(去掉前缀lib和后缀.a)

这里我们可以使用绝对路径,使用下面的shell命令获取当前所在路径:
 

path=$(shell pwd)

Makefile编写后如下:

path=$(shell pwd)mytest:test.c#-l 指定库目录名称 -L 库目录路径 -I 指定头文件路径gcc -o $@ $^ -I $(path)/output/include -L $(path)/output/lib -l hello -static 
.PHONY:clean
clean:rm -f mytest

 

使用file指令查看链接属性:

三、动态库的打包与使用

3.1 动态库的打包

我们同样还是使用上面的那四个文件进行演示。
步骤:

  1. 先将mymath.cmyprint.c 变成生成对应的二进制文件。注意这里生成的二进制文件要带上选项**-fPIC**,产生路径无关码,也就是这里使用相对地址,是动态确定的,不存在绝对地址
    gcc -c -fPIC mymath.c -o mymath_d.o
    gcc -c -fPIC myprint.c -o myprint_d.o
  2. 使用gcc带上选项**-shared** (生成共享的库格式)对二进制文件进行打包
    	gcc -shared myprint_d.o mymath_d.o -o libhello.so
  3. 最后一步就是对动态库进行发布,也就是将库文件和头文件进行组织打包
  4. 编写Makefile:
    libhello.so:myprint_d.o mymath_d.ogcc -shared myprint_d.o mymath_d.o -o libhello.so
    mymath_d.o:mymath.cgcc -c -fPIC mymath.c -o mymath_d.o
    myprint_d.o:myprint.cgcc -c -fPIC myprint.c -o myprint_d.o.PHONY:output
    output:mkdir -p output/lib mkdir -p output/includecp -rf *.h output/includecp -rf *.so output/lib 
    .PHONY:clean
    clean:rm -rf *.o *.so output
    

3.2 动态库的使用

先把动态库放到测试目录下:

然后编写Makefile,和静态库的使用类似:
 

path=$(shell pwd)mytest_d:test.c#-l 指定库目录名称 -L 库目录路径 -I 指定头文件路径gcc -o $@ $^ -I $(path)/output/include -L $(path)/output/lib -l hello 
.PHONY:clean
clean:rm -f mytest_d

 编译程序: 如果此时直接对程序进行编译,不会报错,但是执行的时候会报错,无法打开共享库里面的文件

 因为这里是动态链接,不仅要让编译器动态库的路径,还要让操作系统知道,所以这里我们需要导入一个环境变量LD_LIBRARY_PATH,如下(上面已经说过,这里重复一次)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/dgz/linux/lesson26/lib/uselib/output/lib

 此时再执行程序就不会报错了:

使用file指令查看程序的链接属性:

使用ldd指令查看程序依赖的库: 

3.3 运行动态库的四种方法

  1. 将对应到.so和.h文件拷贝到/usr/lib64和/usr/include
  2. 系统在在搜索头文件时会先在系统默认路径下搜索(上面两个路径),如果没找到,但是环境变量LD_LIBRARY_PATH设置了,也会在该环境变量下搜索,这种方法是内存级的,退出就没有了。
  3. 修改配置文件,配置/etc/ld.so.conf.d/
    路径下原有的文件

    我们想要配置它只需要在该路径下创建一个.conf文件

    然后将我们要配置的路径写进该文件

    最后执行一下
    ldconfig
  4. 建立软连接
     建立成功,然后就可以找到了。

四、总makefile

.PHONY:all
all:libhello.so libhello.alibhello.so:myprint_d.o mymath_d.ogcc -shared myprint_d.o mymath_d.o -o libhello.so
mymath_d.o:mymath.cgcc -c -fPIC mymath.c -o mymath_d.o
myprint_d.o:myprint.cgcc -c -fPIC myprint.c -o myprint_d.olibhello.a:myprint.o mymath.oar -rc libhello.a myprint.o mymath.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o
myprint.o:myprint.cgcc -c myprint.c -o myprint.o
# 发布
.PHONY:output
output:mkdir -p output/lib mkdir -p output/includecp -rf *.h output/includecp -rf *.a output/libcp -rf *.so output/lib 
.PHONY:clean
clean:rm -rf *.o *.a *.so output

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

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

相关文章

Python专题:十五、JSON数据格式

Python的数据处理&#xff1a;JOSN 计算机的主要工作&#xff1a;处理数据 最容易处理的数据就是结构化数据 非结构化数据&#xff1a;视频&#xff0c;文件等 近些年的大数据、数据挖掘就是对互联网中的各种非结构化的数据的分析和处理 半结构化数据 明确的结构属性&…

陪诊服务运用预约小程序的效果是什么

在中高型城市里&#xff0c;陪诊师近些年也很有热度&#xff0c;已经衍生成为一个新的小众行业&#xff0c;不同医院/不同科目等其它情况针对不同群体往往很难完善&#xff0c;比如部分老年人腿脚不便、不认识字、外地语言难以沟通等&#xff0c;陪诊师的作用就尤为凸显. 对相…

[Bootloader][uboot]code总结

文章目录 1、U_BOOT_DRIVER2、DM框架dm_scan_platdatadm_extended_scan_fdt 1、U_BOOT_DRIVER 使用这个宏可以定义一个驱动实例&#xff0c;宏定义是 其中使用的struct driver结构体 使用的ll_entry_declare宏定义是 归结为 2、DM框架 1、 DM框架 DM模型抽象出了以下四个…

16.投影矩阵,最小二乘

文章目录 1. 投影矩阵1.1 投影矩阵P1.2 投影向量 1. 投影矩阵 1.1 投影矩阵P 根据上节知识&#xff0c;我们知道当我们在解 A X b AXb AXb的时候&#xff0c;发现当向量b不在矩阵A的列空间的时候&#xff0c;我们希望的是通过投影&#xff0c;将向量b投影到矩阵A的列空间中&…

ModuleNotFoundError: No module named ‘sklearn‘

ModuleNotFoundError: No module named sklearn 解决办法&#xff1a; pip install scikit-learn

7B2 PRO主题5.4.2免授权直接安装

B2 PRO 5.4.2 最新免授权版不再需要改hosts&#xff0c;直接在wordpress上传安装即可

网站接入百度云防护CDN后回源率非常高原因

最近&#xff0c;有站长反馈网站接入百度云防护后&#xff0c;网站回源率非常高。 今天百度云来给大家讲解下&#xff0c;CDN回源高的原因&#xff1a; 1.动态请求比较多 网站的动态请求很多&#xff0c;一般是回源率高的主要原因&#xff0c;因为CDN对待动态请求是每个请求…

Vue的学习 —— <网络请求库Axios>

目录 前言 正文 一、Axios基本概念 二、安装Axios 三、Axios使用方法 四、向服务器发送请求 前言 在之前的开发案例中&#xff0c;我们通常直接在组件中定义数据。但在实际的项目开发中&#xff0c;我们需要从服务器获取数据。当其他用户希望访问我们自己编写的网页时&a…

定档 11.2-3,COSCon'24 第九届中国开源年会暨开源社十周年嘉年华正式启动!

中国开源年会 COSCon 是业界最具影响力的开源盛会之一&#xff0c;由开源社在2015年首次发起&#xff0c;今年将举办第九届。 以其独特定位及日益增加的影响力&#xff0c;COSCon 吸引了越来越多的国内外企业、高校、开源组织/社区的大力支持。与一般企业、IT 媒体、行业协会举…

网络安全快速入门(十三)linux及vmware软件的网络配置

13.1 前言 在通过我们前面的了解&#xff0c;我们现在已经对Linux的基础知识有了大致的了解&#xff0c;今天我们来大概讲一下关于linux系统及vmware的网络配置问题&#xff0c;在这之前&#xff0c;我们需要对网络有一个大概的认识和了解&#xff0c;话不多说&#xff0c;我们…

01记-“计算机基础知识”

感觉媒体: 直接作用于人的感觉器官&#xff0c;使人产生直接感觉的媒体&#xff1a;声音、图形、图像、动画等。 表示媒体: 为了加工、处理和传输感觉媒体而人为研究、构造出来的一种媒体&#xff0c;常见的有各种编码方式&#xff0c;如文本编码、图像编码和声音编码等。 …

Java中静态方法为什么不能调用非静态成员?

在Java面试中&#xff0c;这个问题经常被问到&#xff0c;因为它不仅涉及到Java的基本语法规则&#xff0c;还深入到了JVM的工作机制。理解这个问题可以帮助面试者更好地掌握Java的静态和非静态成员的区别以及它们在内存中的分配和使用。 静态成员 vs 非静态成员 首先&#x…

AtCoder Beginner Contest 318 A题 Full Moon

A题&#xff1a;Full Moon 标签&#xff1a;模拟、数学题意&#xff1a;给定一个起始 m m m和上限 n n n&#xff0c;每次增量 p p p&#xff0c;求能加几次。题解&#xff1a;数据比较小&#xff0c;可以直接暴力&#xff1b;数学方法算的话&#xff0c;注意边界。代码&#…

HNU-算法设计与分析-作业5

第五次作业【回溯算法】 文章目录 第五次作业【回溯算法】<1> 算法分析题5-3 回溯法重写0-1背包<2> 算法分析题5-5 旅行商问题&#xff08;剪枝&#xff09;<3> 算法实现题5-2 最小长度电路板排列问题<4> 算法实现题5-7 n色方柱问题<5> 算法实现…

时间格式数据向前或向后归于整时

假设你有一个“时:分:秒”的时间格式数据&#xff0c;例如"12:34:56"&#xff0c;你想要将它向前归整于整时或者向后归整于整时&#xff0c;可以按照以下方法进行处理&#xff1a; 1、向前归整于整时&#xff1a;将分钟和秒数设置为0 import datetime# 原始时间 ti…

公共字段填充(AOP的使用)

Thread是线程池,ThreadLocal是线程变量,每个线程变量是封闭的,与其它线程变量分隔开来,在sky-common下的com.sky.context包下有一个Basecontext类 public class BaseContext {//每一个上下文创建了一个线程变量,用来存储long类型的id//创建三个方法,用来设置,取用,删除idpubli…

绝地求生:PGS3参赛队伍跳点一览,17压力有点大,4AM与PeRo大概率不roll点

在PCL春季赛结束后&#xff0c;PGS3的参赛队伍名单以及分组就正式确定了&#xff0c;最后确定名额的DDT和NH被安排在了A组和B组&#xff0c;感觉这次PGS3的分组比较均衡&#xff0c;没有“死亡之组”一说。这段时间已经有网友汇总了PGS3队伍在各个地图的跳点&#xff0c;并且把…

「AIGC算法」近邻算法原理详解

本文主要介绍近邻算法原理及实践demo。 一、原理 K近邻算法&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;是一种基于距离的分类算法&#xff0c;其核心思想是距离越近的样本点&#xff0c;其类别越有可能相似。以下是KNN算法的原理详解&#xff1a; 1. 算…

python安装ESPHome

1. powershell输入python 或者 python3 可以查看python版本&#xff0c;没安装则会自动跳出微软商店&#xff0c;安装即可(注意这里会自动安装在C盘默认路径) 2. pip3 install esphome -i https://mirrors.aliyun.com/pypi/simple 3. 根据报错信息找到esphome的安装目录&…

python脚本编辑oss文件

1、安装oss2库 rootubuntu:~# pip3 install oss2 Collecting oss2Downloading oss2-2.18.5.tar.gz (283 kB)|████████████████████████████████| 283 kB 6.9 MB/s Collecting aliyun-python-sdk-core>2.13.12Downloading aliyun-python-s…