Linux下动静态库的打包与使用C C++

news2024/9/21 11:00:09

目录

  • 前言
    • 为什么用动静态库
    • 动态链接与静态链接
      • 底层优缺点
  • Linux下的动静态库
    • 动静态库的对比
  • 打包静态库
    • 使用静态库
  • 打包动态库
    • 使用动态库
  • 小结
  • win下打包动静态库

前言

为什么用动静态库

我们在实际开发中,经常要使用别人已经实现好的功能,这是为了开发效率和鲁棒性(健壮性);因为那些功能都是顶尖的工程师已经写好的,并且已经践行多年的代码。

那么如何使用他人开发的功能呢?

1.库: 包括静态库与动态库。

2.开源代码。

3.基本的网络功能调用,比如各种网络接口、语音识别等等。

这其中,我们将详细介绍静态库和动态库:

为什么在实际工作中一般将源码打包成动态静态库来给不同的人使用

  1. 知识就是财富,你只是给某些人用一下你写的业务功能,并不想暴露源码的逻辑,那就打包成.obj目标文件甩给他用;
  2. 你也可以自己给自己封装库,因为你自己编译生成了.obj目标文件,是已经编译完成了的,只需要把这个库对应的头文件引入新的程序中,.obj文件放入库路径,这样新的程序链接器就可以直接把功能链接起来,方便部署使用,省去了反复编译的麻烦

动态链接与静态链接

一般情况下,为了更好的支持开发,第三方库或者是语言库都必须提供静态库和动态库(eg:C C++等官方库),这是方便程序员根据需求功能进行可执行文件的生成;

动态链接使用动态库,而静态链接使用静态库。

一般来说,我们gcc编译默认是动态链接的而如果加上-static选项,那么生成的可执行文件将为静态生成;

底层优缺点

动态链接文件信息:

在这里插入图片描述

静态链接文件信息:

在这里插入图片描述

可以明显发现动态链接的文件大小明显要比静态链接的文件大小要小多了

这是因为动态链接是当程序执行到调用接口时编译器再去特定路径查找目标接口的可执行文件,直接进行计算;

静态链接比较暴力,链接时候直接将目标接口的二进制代码全部链接到原文件中去,这也就是静态链接生成的文件这么大的原因了;(毕竟把二进制代码copy过来了)

但是这些都是相对的,有优点就有缺点:

万一动态库路径中的库丢失损坏 ,动态链接的程序到目标位置了,过来用的时候肯定出错了;

静态链接因为编译的时候吧二进制代码考过去了,不依赖原生库,即便原库代码丢失也没事;

小结

在这里插入图片描述

Linux下的动静态库

linux下库的命名格式一般为:

静态库: lib+库的名字+.a eg:c标准库为 libc.a

动态库: lib+库的名字+.so

静态库是指程序在编译链接的时候把库的二进制可执行代码链接到可执行文件中。程序运行的时候将不再需要静态库。

而动态库则是指程序在运行的时候才去启动指定位置的动态库的代码,使其加载到内存共享区中,多个程序共享使用库的二进制代码, 不用拉到本文件中来。

  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表(头文件),而不是外部函数所在目标文件(.o)的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking),也就是说,动态链接是在需要调用接口时才会去将所用接口的二进制代码拷贝到内存中
  • 当一个库多文件使用时,动态库只有一份,所以可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。–>操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
  • 这里需要提一下的是,我们之前所提过的进程地址空间中有一个共享区,而一般动态库的代码就映射在共享区所有进程都共享着动态库的代码

在这里插入图片描述

动静态库的对比

动态库被加载在内存中,可以供多个使用库的程序共享映射到自己的虚拟地址空间使用,因此可以减少页面交换以及降低内存中代码冗余,并且因为与源程序模块分离,因此开发模式比较好。

而加载动态库的程序运行速度相对较慢,因为动态库运行时加载,映射到虚拟地址空间后需要重新根据映射起始地址计算函数/变量地址。

静态库直接把二进制代码链接过来,与动态库的使用恰好相反,其运行速度相对较快,但消耗资源较多。

打包静态库

库函数源文件:

//file1: Add.c
#include<stdio.h>

int Add(int a,int b)
{
    return a+b;
}

//file2: Sub.c
#include<stdio.h>
int Sub(int a,int b)
{
    return a-b;
}

生成静态库需要先生成目标文件(.o)再进行打包,故先编写相应的源文件再将其编译成目标文件:

//生成两个二进制目标文件
[root@VM-8-15-centos fighting]# gcc -c Sub.c -o Sub.o 
[root@VM-8-15-centos fighting]# gcc -c Add.c -o Add.o

此时的add.o和sub.o文件是已经编译好但还没有链接的两个文件;

此时再用 ar命令,归档工具将其打包成静态库

//将这俩二进制目标文件打包成静态库
[lyl@VM-4-3-centos 2022-3-14]$ ar -rc libmycal.a Add.o Sub.o //`rc`表示(replace and create)

查看静态库

 //查看静态库的目录列表
[root@VM-8-15-centos fighting]#  ar -tv libmycal.a `tv`表示(列出静态库中文件 and verbose详细信息)
rw-r--r-- 0/0    936 Jan 24 16:57 2023 Add.o
rw-r--r-- 0/0   1240 Jan 24 16:57 2023 Sub.o

使用静态库

将库的头文件和静态库都放到指定lib目录下:

在这里插入图片描述

调用我们的库接口代码:

#include <stdio.h>
#include "add.h"
#include "sub.h"

int main()
{
  	int a = 10;
  	int b = 20;
  	printf("a+b:%d\n", Add(a, b));
  	printf("a-b:%d\n", Sub(a, b));
 	return 0;
}

编译:

在这里插入图片描述

发现报错: 这是因为gcc编译时去链接库和头文件,是去默认路径以及当前源文件路径下寻找;

//gcc 寻找的默认头文件路径:不建议污染原生库
/usr/include
//gcc 寻找的默认库文件路径:   
/lib , lib64 ......

在这里插入图片描述

而我们将静态库打包到lib目录下,gcc编译时就找不到我们的库了,因此我们编译的时候,需要指定一些选项,并且带上路径./lib;

因此,正确链接的指令为:

gcc -o test test.c -I ./lib -L ./lib  -lmycal -static
  • -I(大写i) + 指定路径:告知gcc除了默认路径之外,还要去寻找这个指定路径的头文件
  • -L + 指定路径:除默认库路径以外,需要寻找这个指定路径的
  • -l(小写L)+ 库名称:表示要具体链接的是哪一个库;(因为路径下库可能不止一个)
  • -static 选择使用静态库的静态链接

由此,我们就静态链接生成了一个可执行文件test,运行test程序结果如下:

在这里插入图片描述

此时我们删除静态库,发现照样可以运行,因为静态库中Add和Sub的二进制代码已经被链接入test程序中了,不怕原生库没了!

可见,有时候编译选项多而杂,难记,特别是文件一多,写的很麻烦,介绍一个camke构建项目的工具,C/C++开发人员必会技能;博客链接

打包动态库

类似与打包静态库使用的ar归档工具,动态库也有自己的语法,我们将生成动态库的依赖关系及方法写进自动化构建工具(Makefile)中::

在这里插入图片描述

显然手动写Makefile和上面手动打包静态库一样,麻烦很多,我的评价是,直接cmake起飞;

注意:

  • 由于动态库在内存中是可加载的,它可能在内存中的任意位置,也可能被映射到进程地址空间的每个区域,所以为了保证库当中的代码执行不会出错,也就是要保证库中的代码是与位置无关的,因此生成.o文件时需要带上-fPIC选项表示生成与位置无关码
  • 这里由于在依赖关系中已经点明了要生成的目标文件,故不带上$@也可以
  • 打包动态库不是像静态库一样先gcc -o再使用ar(归档工具);
  • 而是用gcc 带上-shared选项表示生成共享动态库格式,这也体现了动态库代码映射在共享区的特点

在这里插入图片描述

编写好Makefile之后 make指令构建动态库 libmycal.so:

在这里插入图片描述

使用动态库

和静态库一样,我们把头文件和.so库文件放入lib目录,gcc的时候带上选项;

在这里插入图片描述

 gcc -o test test.c -I ./lib -L ./lib -l mycal //因为是动态链接 所以不用带-static了

然后编译过了,运行程序时发现有问题,打不开动态库?:

在这里插入图片描述

既然编译都声称可执行程序了,此时的可执行程序是没问题的,因此已经与编译过程无关了;

那么这属于运行问题,其实运行时系统也会去默认路径下找到我们所使用的动态库但在默认路径下没有我们的库

这里解决方法有多种,但我倾向于推荐下面这一种:

修改环境变量LD_LIBRARY_PATH,将动态库所在路径.lib添加到该环境变量中,这样程序在运行时系统就能够找到动态库,从而运行成功。

在这里插入图片描述

当然,还可以拷贝我们的.so文件到系统共享库路径下, 一般指/usr/lib;

但是这可能会污染系统原生的库,一般不推荐这样做。

还有一种方法,在我们的系统下有**/etc/ld.so.conf.d/**这个路径:

在这里插入图片描述

我们可以在这个路径下制造自己的.conf,然后再将自己的库路径写进这个conf中;

但是还是有点污染了原生库,不建议;

小结

linux打包使用静态库:

接口的.c源文件–>.o目标二进制文件–>ar rc(归档工具)进行打包成.a静态库,编译程序使用时带上-static;(注意带上头文件寻找路径选项)

linux打包使用动态库:

接口的.c源文件–>.o目标二进制文件(需带上-fPIC 与位置无关)–>-shard 打包动态库;(注意带上头文件寻找路径选项)+(注意添加动态库寻找路径)

win下打包动静态库

比如通过VS2019打包,由于是可视化界面方便操作,不再赘述,参考下方文章;

参考文章

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

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

相关文章

移动窗口下的LiDAR点云区域生长滤波算法教程

一、前言LiDAR 滤波的现有方法包括&#xff1a;数学形态学滤波法、基于地形坡度滤波、最小二乘内插法滤波等滤波方法。最小二乘内插法能够较好的获取地形趋势面&#xff0c;但是算法中无法根据地形自适应设置参数&#xff1b;在地形起伏较大的地区提取结果精度低&#xff1b;无…

Linux进程的后台运行

文章目录一. 什么是进程?二. 进程后台运行在了解三种进程后台运行的方式前&#xff0c;小编觉得有必要先简单讲解一下什么是进程。 PS: 本篇博客技术参考价值不大&#xff0c;只是类似随笔比较水&#xff0c;详细的知识点可以关注一下nohup命令的使用。 一. 什么是进程? 什…

00开篇词:带你玩转gRPC框架

前言 大家好&#xff0c;先做一下自我介绍 我叫Barry Yan&#xff0c;目前是一名互联网公司的研发工程师&#xff0c;同时也是后端技术领域的狂热爱好者和技术博主&#xff0c;在GitHub、CSDN社区、51CTO博客社区、阿里云技术社区、掘金技术社区和InfoQ写作社区等都有自己的博…

详解1242:网线主管(二分答案经典习题)

题目1242&#xff1a;网线主管时间限制: 1000 ms 内存限制: 65536 KB提交数: 23180 通过数: 5566【题目描述】仙境的居民们决定举办一场程序设计区域赛。裁判委员会完全由自愿组成&#xff0c;他们承诺要组织一次史上最公正的比赛。他们决定将选手的电脑用星形拓扑结构连接在一…

【SVM原理推导】核SVM为什么能分类非线性问题?

核SVM为什么能分类非线性问题?要解决这个问题,首先应该先深入理解SVM的原理与本质。(涉及SVM的问题是很常见的,因为SVM可以算是传统机器学习领域非常成功的算法之一了,现在仍有许多research运用SVM解决问题。) 一、支持向量机(SVM) 1. 基本介绍与提出背景 支持向量机…

【C++】lambda 表达式 | 包装器

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;lambda表…

解决宏碁非凡S3 安装Win11时无法找到驱动器问题

1 问题描述 机型&#xff1a;宏碁非凡S3 2022款CPU&#xff1a;i5 1240P安装系统&#xff1a;Win11 专业版问题描述&#xff1a;安装系统时&#xff0c;在选择驱动器界面无法找到驱动器&#xff0c;如下图所示 2 解决流程 查了一下网上的解决办法&#xff0c;进入BIOS把VMD C…

非极大值抑制(Non-Maximum Suppression)

文章目录一、什么是非极大值抑制二、为什么要用非极大值抑制三、 如何使用非极大值抑制四、代码段一、什么是非极大值抑制 非极大值抑制&#xff0c;简称为NMS算法&#xff0c;英文为Non-Maximum Suppression。其思想是搜素局部最大值&#xff0c;抑制非极大值。NMS算法在不同…

JavaEE7-Bean的作用域

目录 1.作用域定义 2.Bean的6种作用域 2.1.singleton&#xff1a;单例作用域&#xff08;默认作用域&#xff09; 2.2.prototype&#xff1a;原型作用域&#xff08;多例作用域&#xff09; 2.3.request&#xff1a;请求作用域 2.4.session&#xff1a;会话作用域 2.5.a…

C++基础回顾

吼吼吼CC基础回顾C基础入门一、标识符1.1标识符命名规则二、数据类型2.1整形&#xff08;格式&#xff1a;int 关键字&#xff09;2.2 sizeof关键字2.3 float关键字2.4字符型2.5转义字符2.6字符串型2.7布尔类型2.8数据的输入三、运算符3.1算数运算符前置递增与后置递增区别3.2 …

MS Access数据库多数据源JDBC查询

Druid, C3P0都不支持微软的Access&#xff0c;如何实现多数据源JDBC查询&#xff1f;&#xff1f; 2023-01-23T23:54:52.4760800 WARNING com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask544a5904 -- Acquisition Attempt Failed!!! Clearing pending a…

Linux内核驱动初探(二) TI声卡

目录 0. 前言 1. menuconfig 2. 超时问题 3. 稳定性问题 0. 前言 通过查询该设备原理图可知&#xff0c;该声卡的Codec芯片型号为德州仪器 TLV320DAC3101。 1. menuconfig 我们在 linux-menuconfig 里面如下设置&#xff1a;进入 Device Drivers ---> Sound card supp…

准确率、精确率、召回率、F1-measure

文章目录准确率(Accuracy)精确率(precision)召回率(recall)F1-measure值学习理解网站-p’(Predicted)n’(Predicted)p(Actual)True PositiveFalse Negtiven(Actual)False PositiveTrue Negtive 准确率(Accuracy) ANo.Samples Predicted CorrectlyTotal No.of SamplesTPTNPN(1)A…

适配splashscreen步骤以及遇到的坑

Android 12 启动画面 从 Android 12 开始&#xff0c;在所有应用的冷启动和温启动期间&#xff0c;系统一律会应用 Android 系统的默认启动画面。默认情况下&#xff0c;此系统默认启动画面由应用的启动器图标元素和主题的 windowBackground&#xff08;如果是单色&#xff09…

虚函数的静态解析

目录 一.基类的constructor和destructor内 二.使用的是基类的对象而不是基类对象的pointer或reference 存在两种情况&#xff0c;虚函数机制不会出现预期行为&#xff1a; 即不根据虚函数的机制来调用类中对应的虚函数 示例中使用的基类和派生类&#xff1a; class base_cl…

vue事件车的原理与标准写法实现兄弟组件的传值

目录前言一&#xff0c;全局事件总线介绍1.1 原理介绍1.2 x需要满足的条件二&#xff0c;知识点的复习2.1 vc是什么2.2 vm管理vc如何体现2.3 原型2.4 上述知识的串联三&#xff0c;实现需求3.1 x的编写及讲解3.2 使用x四&#xff0c;标准写法4.1 写法改动4.2 销毁五 关键代码后…

有关BMP位图的分析

1、BMP是什么&#xff1f; BMP是 Bitmap&#xff08;位图&#xff09;的简称&#xff0c;是windows显示图片的基本格式。 在windows下&#xff0c;任何格式的图片文件&#xff08;包括视频播放&#xff09;都要转化为位图才能显示出来&#xff0c;各种各样格式的图片文件也都…

9.Java数组知识大全

文章目录前言一、数组介绍二、数组的定义域静态初始化三、数组元素访问数组地址中的小拓展:四、数组遍历1.获取数组里面的元素2.把数据存储到数组中3.遍历数组的最快方式4.遍历数组并求和5.统计个数6.变化数据五、数组动态初始化1.数组默认初始化值的规律2.数组动态初始化和静态…

单绞机控制算法模型(Simulink仿真)

线缆行业单绞机PLC控制算法详细解读可以参看下面的文章链接: 线缆行业单绞机控制算法(详细图解+代码)_RXXW_Dor的博客-CSDN博客在了解单绞机之前需要大家对收放卷以及排线控制有一定的了解,不清楚的可以参看下面几篇博客,这里不再赘述,受水平和能力所限,文中难免出现错…

【JavaEE】认识线程Thread类及常用方法线程状态

目录 一&#xff1a;认识线程&#xff1a; 二、线程的优点&#xff1a; 三、进程和线程的区别&#xff08;面试题&#xff09;&#xff1a; 四、第一个多线程程序&#xff1a; 五、创建线程的方式&#xff1a; 六、Thread类及常用方法 Thread类常见构造方法&#xff1…