Linux笔记--静态库和动态库

        库是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为"库"文件;在链接步骤中,链接器将从库文件取得所需的代码,复制到生成的可执行文件中。

Linux中常见的库文件有两种,一种.a为后缀,为静态库,另一种以.so为后缀,为动态库

一、静态库

        可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝"它自己需要的内容到最终的可执行文件中。这个单独的文件,称为静态库。Linux中这类库的名字一般是libxxx.a。

1.创建步骤

将add.c sub.c创建成静态库文件:

  • 创建add.c sub.c
#add.cint add (int a, int b) 
{return a + b;
}#sub.cint sub (int a, int b) 
{return a - b;
}
  • 对add.c sub.c编译成可重定位目标文件
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
  • 利用ar工具创建静态库: ar rcs lib 库名.a所有可重定位目标文件
#生成静态库
ar rcs libmath.a add.o sub.o 

2.静态库的使用

制作使用libmath.a静态库的程序

  • 创建main.c
#include<stdio.h>int add(int a,int b);
int sub(int a,int b);int main(int argc, char* argv[])
{int a=5,int b=3;printf("a+b=%d\n",add(a,b));printf("a-b=%d\n",sub(a,b));    return 0;
}
  • 编译main.c

编译时要将静态库libmath.a加上gcc选项:

  • l:指定库名(库的文件名为libxxx.a,库名为xxx)
  • L:指定库路径
  • static:使用静态链接
gcc -static main.c -l math -L ./
#注意:要先运行main.c后运行静态库文件./a.out

特别注意,必须把-l math 放在后面。放在最后时它是这样的一个解析过程:

  • 链接器从左往右扫描可重定位目标文件和静态库
  • 扫描main.c时,发现两个未解析的符号add和sub,记住这两个未解析的符号
  • 扫描libmath.a,找到了前面未解析的符号,因此提取相关代码
  • 最终没有任何未解析的符号,编译链接完成

那如果将-l math放在前面,又是怎样的情况呢?

  • 链接器从左往右扫描可重定位目标文件和静态库
  • 扫描libmath.a,由于前面没有任何未解析的符号,因此不会提取任何代码
  • 扫描main.c,发现未解析的符号add和sub
  • 扫描结束,还有两个个未解析的符号,因此编译链接报错

生成可执行文件大小:

        生成的可执行文件大小为826k

        由于最终生成的可执行文件中已经包含了add和sub相关的二进制代码,因此这个可执行文件在一个没有libmath.a的Linux系统中也能正常运行。

二、动态库

        动态库和静态库类似,但是它并不在链接时将需要的二进制代码都“拷贝"到可执行文件中,而是仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程。Linux中这类库的名字一般是libxxx.so。(shared object)

1.创建步骤

//先编译成可重定位目标文件(生成与位置无关的代码-fPIC)
gcc -c add.c -o add.o -fPIC
gcc -c sub.c -o sub.o -fPIC
//使用gcc -shared 制作动态库
gcc -shared -o libmath.so add.o sub.o

-fPC作用:生成与位置无关的代码

2.动态库的使用

        通常我们编译的程序默认就是使用动态链接

gcc main.c -o main -l math -L ./

        通过动态库链接的程序只有8.5k.

        通过 ldd命令来观察可执行文件链接了哪些动态库:

        因为没有把 libmath.so 中的二进制代码“拷贝"可执行文件中,程序在其他没有上面的动态库时,将无法正常运行。

3.找不到动态库

        运行可以执行程序./main出错!!! ldd main --> "not found"

        链接器:工作于链接阶段,工作时需要-l和L

        动态链接器:工作于程序运行阶段,工作时需要提供动态库所在目录位置。

        原因:没有提供动态库的位置

解决方式:

  • 通过环境变量(临时生效): export LD_LIBRARY_PATH=动态库路径
  • 环境变量写入配置文件~/.bashrc(使用绝对路径),生效方法: .~/.bashrc或source ~/.bashrc 或 重启终端
  • 拷贝自定义动态库到lib(标准C库所在目录位置)(不推荐)

        【注】只是临时生效。关闭终端再重启时使用./main还会报错。如果想要一直生效需要写在配置文件中。

动态库绝对路径写到/etc/ld.so.conf配置文件中,生效方法: sudo ldconfig

三、静态库和动态库的区别

        静态库被使用目标代码最终和可执行文件在一起(它只会有自己用到的),而动态库与它相反,它的目标代码在运行加载时链接。正是由于这个区别,会导致下面所介绍的这些区别。

1.可执行文件大小

        静态链接的可执行文件要比动态链接的可执行文件要大得多,因为它将需要用到的代码从二进制文件中“拷贝”了一份,而动态库仅仅是复制了一些重定位和符号表信息。

2.扩展性与兼容性

        如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。

3.依赖原库文件

        静态链接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。

即便如此,系统中一般存在一些大量公用的库,所以使用动态库并不会有什么问题。

4.加载速度

        由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性时值得的。

5.库的制作复杂度

        相对来讲,动态库的处理要比静态库要复杂,例如,如何在运行时确定地址?多个进程如何共享一个动态库?当然,这些我们不需要关注。另外动态库版本的管理也是一项技术活。

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

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

相关文章

这回就好好聊聊Kotlin的泛型

公众号「稀有猿诉」 原文链接 这回就好好聊聊Kotlin的泛型 泛型(Generics)是静态强类型编程语言中非常强大的特性&#xff0c;可以极大的加强代码的复用&#xff0c;并增强类型安全&#xff0c;减少运行时的类型转换错误。在这篇文章就来详细的学习一下Kotlin中对泛型的…

EasyX的学习2

消息处理——漂亮的按钮(鼠标) 用到的函数 1.消息结构体变量类型&#xff1a;使用ExMessage ExMessage msg{ 0 }; 定义一个变量名为msg的ExMessage结构体变量并初始化为0 2.获取消息函数&#xff1a;peekmessage函数 //获取消息 peekmessage(&msg, EX_MOUSE); 两个参…

Batch Normalization和Layer Normalization和Group normalization

文章目录 前言一、Group normalization二、批量规范化(Batch Normalization)三、层规范化&#xff08;Layer Normalization&#xff09; 前言 批量规范化和层规范化在神经网络中的每个批次或每个层上进行规范化&#xff0c;而GroupNorm将特征分成多个组&#xff0c;并在每个组内…

表格制作一对多,多对多

<!-- <tr><td>第1行第1列</td><td>第1行第2列</td></tr><tr><td rowspan"4">第2行第1列</td><td colspan"2">第2行第2列</td><td colspan"3">第2行第2列</td>…

STM32CubeMX学习笔记8 -ADC

1. ADC简介 ADC 是Analog-to-Digital Converter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。简单地说就是将模拟电压值&#xff0c;转换成对应的肉眼…

力扣--动态规划152.乘积最大子数组

思路分析&#xff1a; 使用动态规划&#xff0c;定义一个二维数组dp&#xff0c;其中dp[i][0]表示以第i个元素结尾的乘积最大子数组的乘积&#xff0c;dp[i][1]表示以第i个元素结尾的乘积最小子数组的乘积。初始化dp数组的第一个元素为数组的第一个元素。遍历数组&#xff0c;…

c语言经典测试题11

1.题1 #include <stdio.h> int main() { int a[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, *p a 5, *q NULL; *q *(p5); printf("%d %d\n", *p, *q); return 0; }上述代码的运行结果是什么呢&#xff1f; 我们来分析一下&#xff1a;我们创建了一个数…

《汇编语言》 第3版 (王爽)实验6解析

第7章 实验6解析 &#xff08;1&#xff09;.编程&#xff0c;完成问题7.9中的程序。 问题7.9 编程&#xff0c;将datasg段中每个单词的前4个字母改为大写字母。 assume cs:codesg,ss:stacksg,ds:datasgstacksg segment ;开辟了栈段空间&#xff0c;容量为16个字节dw 0,0,0,0…

Ai-WB2-32S在window下使用vs 和 msys2编译以及烧录

文章目录 前言一、使用前准备第一步 安装vscode第二步 安装msys2 二、使用步骤1.打开MSYS2 MINGW64&#xff08;1&#xff09;在开始栏中找到MSYS2 MINGW64并打开&#xff08;2&#xff09;安装git&#xff08;3&#xff09;安装make&#xff08;4&#xff09;安装好之后的文件…

C# 中 Interpreter 用于解释执行代码的工具

在 C# 中&#xff0c;Interpreter 是一个用于解释执行代码的工具&#xff0c;它提供了一种在运行时动态解释和执行 C# 代码的方式。Interpreter 类位于 Microsoft.CodeAnalysis.CSharp.Scripting 命名空间中&#xff0c;它允许你通过编写代码字符串来执行 C# 代码。 下面是一些…

每日一题——LeetCode1576.替换所有的问号

方法一 3个字母原则 把&#xff1f;替换为和他左右都不相等的字符&#xff0c;那么找3个字符abc&#xff0c;&#xff1f;总能替换为abc中的一个字符&#xff0c;遍历字符串找到所有&#xff1f;&#xff0c;再遍历abc把&#xff1f;替换为abc中的一个字符 var modifyString …

Redis缓存【重点】

参考链接 https://xiaolincoding.com/redis/cluster/cache_problem.html#%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9 目录 缓存雪崩大量数据同时过期Redis 故障宕机 缓存击穿第一种方案&#xff0c;非法请求的限制第二种方案&#xff0c;缓存空值或者默认值第三种方案&#xff0c;使…