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.xdnf.cn/news/1425348.html

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

相关文章

Sam Blackshear谈Move如何赋能开发者

Move编程语言提供了直观的编码体验&#xff0c;让开发者能够快速上手。Mysten Labs的联合创始人兼CTO Sam Blackshear创建了Move&#xff0c;这是一种用于编写智能合约的语言&#xff0c;更像传统编程语言&#xff0c;如JavaScript或Rust。 https://youtu.be/iYe_hG8Mzx8 视频…

Spring MVC(响应 + 状态码)

文章目录 一、RestController VS Controller VS ResponseBody1.1 关于元注解1.2 Controller1.3 ResponseBody1.4 RestController 二、响应2.1 Spring 对于响应的设置2.2 返回静态页面2.3 返回HTML代码片段2.4 返回JSON2.5 设置HTTP状态码2.6 设置响应部分的Header 二、状态码2.…

小红书孕妇宝妈暴力拉新玩法,每日两小时,单日收益500+

哎呀&#xff0c;你好呀&#xff0c;亲爱的小伙伴们&#xff01;我今天心血来潮&#xff0c;想和你们分享一个超级棒的方法&#xff0c;这个方法我亲自试过&#xff0c;超级有效&#xff01;就是在小红书上针对孕妇和宝妈们进行引流的方法。听起来是不是很有趣呀&#xff1f;&a…

Excel表格内容误删未保存怎么找回?5种XLS文件恢复有效方法

在繁忙的工作中Excel表格作为数据处理的重要工具&#xff0c;承载了众多关键信息。然而误删未保存的Excel内容往往让人措手不及。今天我将为大家分析Excel表格内容误删未保存的可能原因&#xff0c;并提供五个免费实用的解决方案&#xff0c;助你轻松找回误删的XLS文件数据。 一…

贝努利贝叶斯算法

基本用法 完整代码&#xff1a; from sklearn.naive_bayes import BernoulliNB from sklearn.datasets import make_blobs from sklearn.model_selection import train_test_split# 生成数据 X, y make_blobs(n_samples500, centers5, random_state8) X_train, X_test, y_tr…

什么是蜜罐,在当前网络安全形势下,蜜罐能提供哪些帮助

在当前的互联网时代&#xff0c;网络安全威胁日益严峻&#xff0c;攻击手段层出不穷。为了应对这些威胁&#xff0c;网络安全专家们不断探索新的防御手段&#xff0c;在过去的几年里&#xff0c;一种更加积极主动的网络安全方法正在兴起。蜜罐技术便是这样一种备受瞩目的主动防…

打包conda环境的两种方法:conda env export和Conda-Pack

打包conda环境的两种方法&#xff1a;conda env export和Conda-Pack 搭建项目环境可能是整个开发过程中最让人头疼的部分了。如何把我们辛辛苦苦搭建的环境打包起来&#xff0c;万一环境崩了还能迅速恢复&#xff0c;或者让别人能轻松地复制同样的设置呢&#xff1f; 今天&am…

数仓架构之为什么要进行数仓分层

数仓分层这个概念想必大家都很熟悉&#xff0c;不管是在实际的开发工作当中会用的&#xff0c;还是在面试官面试你的时候会问到&#xff1a;你之前的项目是按照什么分层的&#xff0c;分哪几层&#xff0c;数仓分层有什么好处&#xff0c;举个栗子说说。 简而言之&#xff0c;…

[Cocos Creator 3.5赛车游戏]第3节 新建项目

环境已经配置好&#xff0c;现在您将真正的开始开发您的项目&#xff0c;开发项目的第一步是新建项目。所以现在请关闭上一个步骤打开的Cocos Creator窗口&#xff0c;回到CocosDashboard&#xff0c;点击“新建”按钮&#xff1a; 选择“模板”选项卡&#xff0c;因为您即将开…

视频监控平台智能边缘分析一体机视频存储平台打手机检测算法

智能边缘分析一体机的打手机检测算法是一种集成了先进图像处理、计算机视觉和人工智能技术的解决方案&#xff0c;专门用于实时监测和识别监控场景中的打手机行为。 在提到“打手机检测算法”时&#xff0c;可能是指一种能够识别和检测使用手机行为的算法。这种算法可以应用于多…

29.IO流(了解)

1. C语言的输入与输出 ​ C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键 盘)读取数据&#xff0c;并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的…

在面对各种问题时,我们应该如何进行数据分析

python数据分析汇总 前言一、对比分析概念特征类型案例Matplotlib的颜色字母对照表解决遇到未知函数 二、相关性分析概念类型案例一案例二 三、时间序列分析概念类型案例 四、回归分析概念类型案例一案例二案例三 五、决策树概念计算过程案例 六、主成分分析概念计算过程案例 七…

武汉星起航推出亚马逊一站式孵化服务,助力卖家轻松拓展全球市场

亚马逊作为全球最大的电商平台之一&#xff0c;以其全球化的销售平台和完善的物流体系&#xff0c;吸引了众多卖家的目光。通过亚马逊平台&#xff0c;卖家可以轻松地将产品销往世界各地&#xff0c;无需担心复杂的国际贸易流程。而在这个充满机遇的市场中&#xff0c;武汉星起…

IDEA中开发并部署运行WEB项目

IDEA中开发并部署运行WEB项目 1 WEB项目的标准结构2 WEB项目部署的方式3 IDEA中开发并部署运行WEB项目3.1 部署步骤3.2 IDEA关联本地Tomcat 4 IDEA创建web工程5 IDEA部署-运行web项目6 IDEA部署并运行项目的原理 1 WEB项目的标准结构 一个标准的可以用于发布的WEB项目标准结构如…

安防监控视频平台智能边缘分析一体机视频存储系统客流统计检测算法

智能边缘分析一体机的客流统计检测算法是一种基于人工智能与边缘计算技术的解决方案&#xff0c;专门设计用来实时、准确地统计通过特定区域的人流量。这项技术广泛应用于零售、交通、场馆管理、智慧城市等领域&#xff0c;以帮助管理者更好地理解顾客行为、优化资源配置、提升…

RS232/RS485信号转12路模拟信号 YL34隔离D/A转换器 4-20mA/0-5V/0-10V/0-20mA/0-25mA

特点&#xff1a; ● RS-485/232接口&#xff0c;隔离转换成12路标准模拟信号输出 ● 可选型输出4-20mA或0-10V控制其他设备 ● 模拟信号输出精度优于 0.2% ● 可以程控校准模块输出精度 ● 信号输出 / 通讯接口之间隔离耐压3000VDC ● 宽电源供电范围&#xff1a;10 ~ …

什么是控制,什么是控制系统?复杂的动态系统怎么被控制的?

在汽车研发中或者购买新能源汽车中&#xff0c;通常能提到什么EPS控制、ABS控制、智能域控等等各种说法&#xff0c;听起来让人觉得非常不一般&#xff0c;但是&#xff0c;这控制究竟是什么&#xff1f;控制的又是什么&#xff1f;其实很好理解&#xff01; 关注我&#xff0c…

Unity Mirror 从入门到入神(一)

Mirror从入门到成神 文章目录 Mirror从入门到成神简介NetworkClientRegisterPrefabConnect (string address)Disconnect ()activeactiveHost NetworkServerSpawn 简介 Mirror是一个unity网络同步框架&#xff0c;基于MonoBehaviour生命周期的回调的基础上进行数值的同步&#…

HTML+CSS练习小项目——百叶窗

前言&#xff1a;在学习完HTML和CSS之后&#xff0c;我们就可以开始做一些小项目了&#xff0c;本篇文章所讲的是新手可以练习的小项目——百叶窗 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 先让我们看一下效果&#xff1a…

python怎么安装matplotlib

1、登陆官方网址“https://pypi.org/project/matplotlib/#description”&#xff0c;下载安装包。 2、选择合适的安装包&#xff0c;下载下来。 3、将安装包放置到python交互命令窗口的当前目录下。 4、打开windows的命令行窗口&#xff0c;通过"pip install"这个命令…