Linux下的动态库和静态库详解

article/2025/8/30 6:38:24

动态库和静态库

文章目录

  • 动态库和静态库
    • 静态库与动态库的概念
    • 理解动静态库
      • 如何打包动静态库与如何使用动静态库
      • 如何制作打包动态库

为什么我们要使用别人(一般是顶尖的工程师写的)的代码?

为了开发效率和鲁棒性(健壮性)

如何使用别人的功能?

1、库 2、开源代码 3、基本的网络功能调用(各自网络接口,语音识别)

库一般分为动态库和静态库,动态库一般的命名为libc.so,静态库一般的命名为libc.a,去掉前缀lib,去掉.之后的内容,剩下的就是库的名字,这里就是c库,生成可执行程序的方式有两种:动态链接和静态链接

#include<stdio.h>
int main()
{printf("hello world!\n");return 0;
}

ldd 可执行程序名字:查看可执行程序的动态链接关系

image-20220228135628014

在linux当中,默认情况下形成的可执行程序是动态链接的,可以看到这里是.so为后缀的

下面我们举个例子来解释一下动态链接和静态链接:

比如你在宿舍写作业,写到某个题突然不会了,学校旁边有个网吧,于是你就去网吧去查找资料解决问题,解决完了然后回到宿舍继续完成作用,还有一种方法就是你告诉你爸让给你买台电脑,你在宿舍有台电脑,于是你就不需要再去网吧去使用电脑去查阅资料,直接在自己买的电脑上面查找资料即可,前面说的那种方法类似于动态链接,后面的那种方法叫做静态链接

当调用库频率增加时或者在上面的例子中说去网吧查阅资料频繁时,就变得很麻烦,就和上面的例子一样我们自己买个电脑,这样就省事了不少。相对应的把库中的我的可执行程序中所需要使用的二进制代码,拷贝进我的可执行程序当中,这就叫做静态链接。

如果想使用静态链接,那就在gcc后面+static选项:一般,为了更好的支持开发,第三方库或者语言库,必须提供两个库,一个叫做静态库,一个叫动态库,方便程序员根据需要进行bin的生成

image-20220228142033129

动态链接的特点:体积小,节省资源(磁盘,内存),但是一旦库丢失,bin不可执行

静态链接的特点:体积大,浪费资源(磁盘,内存),不依赖库,库丢失不影响可执行程序

静态库与动态库的概念

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

理解动静态库

如何打包动静态库与如何使用动静态库

不想将源代码暴露给别人,就需要打包动静态库,下面我们来看如何打包动静态库:

我们首先写好自己想要打包的程序代码:

add.c

#include"add.h"
int myadd(int x,int y)
{return x+y;
}

add.h

#pragma once
#include<stdio.h>
int myadd(int x,int y);

sub.c

#include"sub.h"
int mysub(int x,int y)
{return x-y;
}

sub.h

#pragma once
#include<stdio.h>
int mysub(int x,int y);

我们想让别人能使用我的库,前提是别人需要首先知道你的库能给我提供什么方法,通过头文件体现,然后将源文件编译生成目标文件:

gcc -c add.c

生成.o文件,这个.o文件可以被别人链接

gcc -c sub.c

然后使用ar -rc命令生成静态库:

ar -rc libmymath.a add.o sub.o

我们只需要将头文件和这个刚生成的库文件给别人就好了,别人就可以用该库,形成自己的可执行程序

我们将头文件和这个刚生成的库文件都放进lib目录下,自己写个程序使用它:

#include<stdio.h>
#include"Add.h"
#include"sub.h"
int main()
{printf("%d\n",myadd(10,20));printf("%d\n",mysub(10,20));return 0;
}

这里会报错,找不到:image-20220228144018395

因为去当前路径或者默认路径(/usr/include)下找头文件,所以需要告诉gcc在指定路径下去找一下头文件:

-I选项:

gcc test.c -o mytest -I ./lib

我们发现还会有问题:

image-20220228144100170

我们需要告诉gcc除了默认路径(/lib64/libc)以及当前路径之外,在指定的路径下也找一下库文件:

-L(大写)选项:

gcc test.c -o mytest -I ./lib -L ./lib -lmymath

-l(小写)库名称:具体你要链接哪一个库

image-20220228144231837

可以看到成功执行了

为什么C语言在编译的时候,从来没有明显的使用过-I -L -l等选项呢?

  1. 库文件和头文件在默认路径下gcc能找到
  2. gcc编译C代码,默认就应该链接libc

如果我们也不想使用这些选项呢?

头文件库文件分别拷贝到默认路径下,这个过程叫做库的安装,对于第三方库例如我们自己写的,一般也要带上-lname

如何制作打包动态库

生成动态库:

Makefile的编写

libmymath.so add.o sub.ogcc -shared -o $@ $^
add.o:add.cgcc -fPIC -c $^ 
sub.o:sub.cgcc -fPIC -c $^

gcc选项 -fPIC:产生与位置无关码

在进程地址空间中有共享区,一般动态库的代码是映射在共享区的,我们将库代码加载到内存,通过页表映射到进程地址空间的共享区,当其他程序想要相同的库代码时,可以通过页表映射到内存中相同库代码的部分,这样就大大减少了空间的使用情况,库有可能加载到物理内存的任意位置,也可能被映射到进程地址空间中共享区的任意区域,所以必须保证库当中的代码怎么执行都不会错,为了保证这个库当中的代码地址不随着加载到内存的位置发生变化而变化,需要告诉gcc,我们进行fPIC选项产生与位置无关码进行编译

我们通过静态库的那套方式进行编译链接:

gcc test.c -o mytest -I ./dy_lib -L ./dy_lib -lmymath

我们运行可执行程序,发现无法正常运行:

image-20220228153922235

此时和编译器gcc还有关系吗?毫无关系,是运行时出现的问题,属于运行问题,也要能够让系统帮我们找到运行时需要使用的动态库。

为什么之前动态链接的其他程序可以直接运行呢?因为库可以找到

环境变量LD_LIBRARY_PATH,需要将库的路径导入到环境变量LD_LIBRARY_PATH中:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/whb/101/lesson18/dy_lib/test/lib/

image-20220228154358535

可以看到此时就可以正常执行了

image-20220228154453152


http://chatgpt.dhexx.cn/article/eF7qbgo5.shtml

相关文章

静态链接库和动态链接库

一、前言 1、代码复用是提高软件开发效率的重要途径。 2、一般而言&#xff0c;只要某部分代码具有通用性&#xff0c;就可将它构造成相对独立的功能模块并在之后的项目中重复使用。小到一个函数、一种数据类型、一个类&#xff0c;大到一种类、一个模块、库。 3、复用从方式上…

linux之静态库与动态库

我们在写c语言的时候&#xff0c;经常会去包含一个.h的头文件&#xff0c;这个头文件就是库文件&#xff0c;比如<stdio.h>,<stdlib.h>这些都是标准的头文件&#xff0c;一般放在/usr/include,也就是说&#xff0c;从这个目录中我们可以找到这个头文件&#xff0c;…

理解和创建Windows和Linux下的动态和静态库区别

一、引言 在计算机编程的世界中&#xff0c;库是一个非常重要的改变。它的出现提供了一种共享和重用代码的可能性&#xff0c;复杂的程序因为动态库的出现而变得简洁和方便。然而&#xff0c;库并不是单一的&#xff1a;它们可以是动态的&#xff0c;也可以是静态的&#xff0…

静态库与动态库的区别和使用

动静态库所用到的一些库文件&#xff1a; .o 是目标对象文件,相当于windows中的.obj文件。可由一个或多个.c /.cpp来生成 .a 为静态库&#xff0c;可以是一个或多个.o合在一起,用于静态连接&#xff1b;多个.o文件可以链接生成一个.exe的可执行文件。静态库在程序编译时会被连…

静态库和动态库的使用与区别

引文 库文件是计算机上的一类文件&#xff0c;可以理解为一种代码仓库&#xff0c;提供给使用者一些可以直接使用的变量、函数或类。 库文件分为两类&#xff1a; 静态库&#xff1a;在链接阶段&#xff0c;会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中…

【Linux静态库和动态库】

Linux静态库和动态库 1. 编译与ELF格式2. 库的基本概念3.静态库的制作&#xff1a;&#xff08;假设要将a.c、b.c制作成静态库&#xff09;4.静态库的常见操作5.静态库的使用6. 多个库的相互依赖举例1.(库文件制作、错误处理) 7.静态库和动态库的关系和区别8.动态库的制作软链接…

如何理解静态库与动态库

究竟什么是库&#xff1a; 日常生活中有很多所谓的库&#xff0c;比如车库啊&#xff0c;优衣库啊&#xff0c;甚至还有一库&#xff08;日语&#xff09;咳咳。然后对程序员来说&#xff0c;所谓的库&#xff0c;即是程序库&#xff0c;当一段代码十分耐用&#xff0c;又经过…

C++静态库与动态库的区别

文章目录 什么是库静态库Linux下创建与使用静态库Windows下创建与使用静态库 动态库Linux下创建与使用动态库Windows下创建与使用动态库 动态库的显式调用在Linux下显式调用动态库在Windows下显式调用动态库显式调用C动态库注意点 附件&#xff1a;Linux下库相关命令g(gcc)编译…

动态库静态库的区别

1、动态库以及静态库区别 静态库是函数和数据编译进一个二进制文件里面&#xff08;.lib文件&#xff09;&#xff0c;在使用静态库链接成可执行程序的时候&#xff0c;链接器会复制静态库内的函数和数据进可执行程序里面(.EXE文件)&#xff0c;所以在加载库的时候不需要加载相…

详谈静态库和动态库的区别

一、什么是库&#xff1a; 库是写好的&#xff0c;现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说&#xff0c;库是一种可执行代…

【C语言】详解#define,#ifdef,#ifndef,#elif,#undef,以及相关运算符

1.明示常量 #define 预处理指令结尾不带&#xff1b;&#xff08;分号&#xff09;&#xff0c;在预编译的过程中使用宏的地方会进行展开&#xff0c;是用多少次就展开多少次&#xff0c;但是只替换 不计算&#xff0c;预处理器在发现程序中的宏后&#xff0c;会用宏等价的替换…

Vue 项目报错:‘$‘ is not defined ( no-undef )

错误描述 报错如上图所示&#xff0c;错误原因是不认识 $ 符&#xff0c;他是 JQuery 中得符号&#xff0c;我也确实引入了 JQuery&#xff1a; 解决办法 在 vue 项目的根目录下创建一个 .eslinttrc.js 文件&#xff0c;文件内容如下&#xff1a; module.exports {root: true…

undefined和is not defined区别

undefined定义&#xff1a; undefined是javascript的一种基本数据类型&#xff0c;变量未赋值或者函数没有返回值时返回。 xxx is not defined是一种错误类型&#xff0c;其完整形式是&#xff1a;Uncaught ReferenceError: xxx is not defined&#xff08;未捕获的引用错误&a…

#define #undef等基本知识

1、预处理符号 例子&#xff1a; #include <stdio.h> #define DEBUG_PRINT printf("FILE %s line %d:" \"x%d, y%d, z%d," \__FILE__,__LINE__,x,y,z) //或者如下: //#define DEBUG_PRINT printf( "File %s line %d:…

undefined和is not defined一样吗?

https://blog.csdn.net/sheldon178/article/details/48298151/ undefined和is not defined&#xff0c;字面意思看来没什么两样&#xff0c;不都是未定义吗&#xff1f; 在JavaScript中&#xff0c;可并非如此。 undefined定义如下&#xff1a; undefined是javascript的一种…

C++中 #define 与 #undef

define 宏指令 #define 与 # include类似,它的好处呢就是速度快,使用define定义函数可以减少函数调用的额外开销 define 主要体现在2个地方 1 定义一个值 2 定义一个函数或者说功能 #include <iostream> using namespace std; // 定义一个值 #define HELLO_WORLD "…

#define #undef 使用

#define 是宏定义 #define 的用法是非常多功能的&#xff0c;它不止能实现常量宏定义&#xff0c;开关&#xff0c;还能实现函数 #undef 是取消宏定义 在undef后面要加上你要取消的宏定义 不想取消在后面可以瞎写但是不能为空 例子 #include "stdio.h"int main(…

C语言 #undef的用法

C语言中#undef的语法定义是&#xff1a;#undef 标识符&#xff0c;用来将前面定义的宏标识符取消定义。 然而&#xff0c;在实际应用中&#xff0c;#undef到底可以用来做什么&#xff1f; 整理了如下几种#undef的常见用法。 1. 防止宏定义冲突 在一个程序块中用完宏定义后&…

Perl学习-undef值和defined函数

undef值 undef是未定义的意思&#xff0c;在Perl中&#xff0c;会假设undef的变量时0或者空字符串 如果当成数字&#xff0c;就是0如果当成字符串&#xff0c;就是空字符串 当成数字 1 $n 1;2 3 while($n < 10){4 $sum $n;5 $n 2;6 }7 8 print "The tota…

吊打迅雷,最好用的BT种子下载器,下载不限速

今天小七要给大家带来的是一款安卓端BT下载器&#xff0c;用它来找片&#xff0c;下片&#xff0c;简直爽到极点&#xff0c;目前完全免费&#xff0c;无广告、无会员限制、极速下载、运行稳定支持多种格子解析、支持边下边播等等&#xff0c;拥有迅雷的所有功能&#xff0c;同…