【Linux】静态库与动态库

这篇具有很好参考价值的文章主要介绍了【Linux】静态库与动态库。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

对于C/C++的学习者,我们经常听到C/C++的标准库,我们也经常使用它们,但是我们在使用的时候经常只包含一下头文件,然后就使用了,我们从来没有认真的研究过C/C++的标准库,而且C/C++的头文件中只有声明并没有声明的内容的具体实现,为什么我们只包含头文件就能使用库呢?本篇文章我们就来一起探讨一下。

一、什么是库

简单来说:库是一些可重定向的二进制文件,这些文件在链接时可以与其他的可重定向的二进制文件一起链接形成可执行程序。

一般来说库被分为静态库动态库,他们是有不同的后缀来进行区分的。

系统平台 静态库 动态库
Windows .lib .dll
Linux .a .so

另外对于C/C++来说其库的名称也是有规范要求的,例如在Linux下:一般要求是lib + 库的真实名称 +(版本号)+ .so /.a + (版本号),版本号是可以省略不写的。

例如这两个标准库 :
libstdc++.so.6    真实名称是 c++
libc-2.17.so     真实名称是 c

头文件与库的关系

  1. 头文件提供方法说明,库提供方法的实现,头和库是有对应关系的,是要组合在一起使用的
  2. 头文件是在预处理阶段就引入的,程序在链接时链接的本质其实就是链接库!

有了上面的一点基础知识以后我们就能够去见一见库了,Linux系统在安装时已经为我们预装了C&C++的头文件和库文件。

对于C/C++头文件在Linux里面一般在/usr/include目录下面存放我们的头文件

【Linux】静态库与动态库

对于C/C++的库文件,一般在/usr/lib64/lib64里面,/lib64里面给的是root和内核所需so或者a之类的库文件,而/usr/lib64是普通用户能够使用的。

【Linux】静态库与动态库

【Linux】静态库与动态库

到这里我们也能够理解一些现象了:

  1. 我们在使用像vs2019这样的编译器时要下载并安装开发环境,这其中是在下载什么?

    答案是:安装编译器软件,安装要开发的语言配套的库和头文件。

  2. 我们在使用编译器,都会有语法的自动提醒功能,但是都需要先包含头文件,这时为什么呢?

    答案是:语法提醒本质是编译器或者编辑器,它会自动的将用户输入的内容,不断的在被包含的头文件中进行搜索,自动提醒功能是依赖头文件而来的!

  3. 我们在写代码的时候,我们的环境怎么知道我们的代码中有哪些地方有语法报错,哪些地方定义变量有问题?

    答案是:不要小看编译器,编译器有命令行的模式,还有其他自动化的模式,编辑器或集成开发环境可以在后台不断的帮我们调用编译器检查语法而不生成可执行文件,从而达到语法检查的效果。

二、怎么制作一个库

库的使用能够提高我们的开发效率,接下来我们来制作一个库!

1、静态库

静态库:程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库,当然这也会导致我们编译出来的可执行程序会变大。

看下面一段代码来演示库:

头文件:
【Linux】静态库与动态库

源文件:

【Linux】静态库与动态库

主程序:

【Linux】静态库与动态库

文件目录结构:

【Linux】静态库与动态库

可以看到我们将库的头文件与库的实现文件放在了mylib文件夹里面了,将main.c 放在了otherPerson里面,此时mian.c与库的头文件以及实现文件不在一起,此时编译会报错。

【Linux】静态库与动态库

提示我们找不到头文件,就算我们将头文件移过去也会有链接错误,如果我们不想将源码给otherPerson,但是我们又想要main.c能完成编译形成可执行程序,我们就要对我们的库文件的实现进行编译但不生成最终的可执行程序。

【Linux】静态库与动态库

然后我们将我们的头文件和可重定向的二进制文件进行拷贝到otherPerson里面
再进行编译链接,我们就形成了可执行程序test

【Linux】静态库与动态库

运行test,程序执行成功

【Linux】静态库与动态库

上面的整个过程就是我们制作静态库的基本流程,当然这样的制作其实还是有缺陷的,当我们的项目文件过于庞大时,我们要给一个.c文件十几个这样的.o文件,而且文件过于分散了,不利于管理,于是我们就需要将多个这样的.o文件打成一个包,我们将这个包直接给别人,别人就能直接使用了。

打包的命令是:ar -rc命令

ar命令用于建立或修改备存文件,或是从备存文件中抽取文件。可集合许多文件,成为单一的备存文件,在备存文件中,所有成员文件皆保有原来的属性与权限。

r :如果打包好的xxx.a库中没有 xxx.o 那么就会把模块 xxx.o 添加到库的末尾,如果有的话就会替换之(位置还是原来的位置)。

c :建立备存文件。

于是我们就尝试将原来的.o文件进行打包,不过要注意的是打包好的库要遵循库的命名规范。

【Linux】静态库与动态库

此时我们的当前目录里面就有了静态库了,当我们删除静态库以后,我们用静态库生成的可执行程序还能够正常运行,这就是静态库的特点!!!

2、静态库的使用

指明路径

在我们实际使用库时,我们一般将头文件放在一个目录里面,将库放到另外一个文件里面,这样便于我们进行分类管理。我们也按照这种标准化的做法,来整理一下我们的目录结构。

【Linux】静态库与动态库

我们libmymath.a静态库不是C的标准库,所以gcc不会在进行编译时去链接我们自己写的静态库,所以我们还要给gcc添加一些参数用来指明我们要链接的静态库。

【Linux】静态库与动态库

(其中 -I - L -l ,其后面传递的内容可以加空格进行分割,也可以不加空格)

-I: 指明我们要包含的头文件路径
-L :指明我们包含的库的路径
-l:指明我们要包含的库文件名(这里的库文件名是指真实名称)

./test运行我们的程序,发现程序可以正常启动。

【Linux】静态库与动态库

转移到系统的默认搜索路径中

对于C/C++的头文件Linux系统默认搜索路径是 :/usr/include
对于C/C++的库文件Linux系统默认的搜索路径是:/usr/lib64/lib64

我们将文件移动到对应的默认搜索路径中:
【Linux】静态库与动态库

此时我们再进行编译我们的mian.c
【Linux】静态库与动态库

这时gcc编译器报链接错误,提示我们找不到库,这时因为我们使用的是第三方库,编译时无论如何都要指明文件名!

【Linux】静态库与动态库
指明路径以后,我们就能够正常编译了!

总结:第三方库的使用

  1. 需要指定的头文件,和库文件
  2. 如果没有默认安装到系统gccg++默认的搜索路径下,用户必须指明对应的选项,告知编译器: a.头文件在哪里 b.库文件在哪里 c.库文件具体是谁
  3. 将我们下载下来的库和头文件,拷贝到系统默认路径下,在Linux下就是安装库! 那么卸载呢?对任何软件而言,安装和卸载的本质就是拷贝到系统特定的路径下!
  4. 如果我们安装的库是第三方的库,我们要正常使用,即便是已经全部安装到了系统中,gcc g++必须用-l指明具体库的名称!

3、 动态库

动态库:程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。如果我们删除动态库,则使用动态库生成的可执行程序都将无法运行!

我们制作动态库时不再需要ar命令,我们需要一下两个步骤:

  1. gcc形成二进制文件时加上-fPIC参数,这样产生的可重定向二进制文件就会形成与位置无关码。
  2. 然后用gcc加上-shared参数,把所有有与位置无关码的可重定向二进制文件进行打包形成一个动态库。

先看一下我们的目录结构:

【Linux】静态库与动态库
形成与位置无关码:

【Linux】静态库与动态库

打成动态库:
【Linux】静态库与动态库

当我们有了动态库以后,我们是可以删除可重定向的二进制文件的,但是动态库不能够删除,动态库删除的话,依赖此动态库的程序也将不能够运行!

下面我们尝试用动态库去链接形成可执行程序:

【Linux】静态库与动态库

注意:我们自己写的库是属于第三方库,我们要编译时要指明:头文件路径,库文件路径,库文件名(真实名称)。

【Linux】静态库与动态库

4、动态库的使用

可以看到我们已经使用动态库编译成功了,下面我们来运行一下我们的程序。

【Linux】静态库与动态库
发生了错误,系统提示我们程序运行时,没有办法找到动态库,这是为什么呢?

这就和动态库的特性有关了,由于采用动态库的程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码,所以运行的程序必须要知道去哪里链接我们的库,即对于动态库在编译期间我们要告诉编译器去哪里链接库进行编译,在运行期间要告诉操作系统去哪里链接库进行运行。

静态库不需要链接是因为:静态库在编译链接期间将用户使用的二进制代码直接拷贝到目标可执行程序中,编译后的程序是一个完整的程序,不需要再运行时再使用静态库了。

解决操作系统找不到动态库的方法有三种:

环境变量

在我们Linux下有一个环境变量:LD_LIBRARY_PATH,操作系统会去这个环境变量下的路径去搜索动态库,我们可以将我们的第三方库加入到这个环境变量中,然后我们再运行我们的可执行程序就能成功了。

【Linux】静态库与动态库
执行我们的程序:

【Linux】静态库与动态库
程序执行成功!

但是我们都知道,环境变量只在一次登录内有效,如果我们采用环境变量的方法我们下次登录时依旧无法运行,所以这种方法具有临时性。

软连接

我们知道Linux中C/C++的默认库路径是/usr/lib64/lib64,这也是系统搜索库的默认路径,我们可以将我们的第三方库在这个目录下面建立一个软连接(不推荐直接将第三方库拷贝到默认库路径/usr/lib64/lib64下面),这样我们也能够正常使用了。

【Linux】静态库与动态库

执行我们的程序,正常运行,软链接一个比较好的寻找库目录方法。

【Linux】静态库与动态库

修改配置文件

在我们的Linux系统中有一个配置文件目录/etc/ld.so.conf.d,在这个目录里面我们可以创建一个文件,文件里面写上动态库的路径,这样我们系统在搜索动态库时也会搜索到该路径。

【Linux】静态库与动态库
创建文件并填上我们的路径:
【Linux】静态库与动态库

这样我们是配置文件就修改完毕了,但是我们还要让配置文件立即生效,我们可以使用ldconfig命令。

【Linux】静态库与动态库

一切准备好以后我们就可以运行我们的程序了!

【Linux】静态库与动态库

三、动静态库的加载

1、静态库的加载

在形成可执行程序的链接期间,静态库中的代码会被直接拷贝一份进入可执行程序内。所以在程序运行期间静态库可以理解为不会被加载,或者说静态库和程序一起被加载。

但是由于是静态库,当多个进程包含相同的静态库时这会导致内存中存在大量的重复代码,导致内存资源的浪费。

2、动态库的加载

采用动态库的程序在使用库中的方法时,会在使用的地方留下一个标记,在程序运行以后进行动态链接时,会将这个标记替换为动态库中的地址。

当一个使用了动态库的进程A运行起来以后在需要动态库a时,操作系统会先在内存中搜寻a,是否存在,如果存在,就直接将a通过页表进行映射进进程A的进程地址空间中的共享区中,如果不存在就会将磁盘中的动态库a加载进入内存,然后再通过页表进行映射。

我们知道被编译好的程序内部是有地址的!动态库内部的地址并不是绝对地址,而是偏移量!(相对地址)

因为不同的进程,运行程度不同,需要使用的第三库是不同的注定了,每一个进程的共享空间中空闲位置也是不确定的!如果采用了绝对编址,在一个进程使用了多个库时就有可能照成地址冲突!

当一个动态库,真正的被映射进地址空间的时候,它的起始地址才能真正确定! 此时动态库中的方法的地址就等于库的地址加上自己在库中的偏移量。通过这种设计方式,动态库在进程的地址空间中,可以随便加载,我们都能够找到库中的方法,也不会与其他库产生冲突了! 这就是与位置无关码文章来源地址https://www.toymoban.com/news/detail-453075.html

四、一些其他结论

  1. 动态库和静态库同时存在,系统默认采用动态链接
  2. 一般来说可执行程序在生成时,会对多个库进行链接,我们可以使用ldd命令查看我们的程序链接了那些库,可执行程序在连接时也可以选择部分采用动态库部分采用静态库。
  3. 如果我们对gcc加上了-static参数,gcc就会默认帮我们全部采用静态链接的方式链接库。

到了这里,关于【Linux】静态库与动态库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux:动态库与静态库】

    静态库( .a ):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。 动态库( .so ):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表

    2024年02月06日
    浏览(39)
  • Linux中的动态库与静态库

    软链接 当我们不在本地路径下运行时,运行目标二进制文件一般要写明该程序路径. 但是这样运行对于路径较为复杂的程序极为耗费时间,为了简便操作,我们可以将该可执行程序的路径设置为软链接.此时的软链接一般也可认为是windows可执行程序的快捷方式. 创建软链接命令如下

    2024年02月12日
    浏览(41)
  • 深入理解Linux中的动态库与静态库

                                                      🎬慕斯主页 : 修仙—别有洞天                                                 ♈️ 今日夜电波:I Wish My Mind Would Shut Up—Ivoris                                                          

    2024年01月24日
    浏览(44)
  • 【Linux】静态库与动态库制作及运行原理

    Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。 先来总体描述下静态库与动态库的区别. 静态库是将头文件总体复制到可执行文件当中 。 动态库是在可执行程序运行时进行了动态链接 (所需要某个实现方法就去内存中查找). 所

    2024年02月05日
    浏览(31)
  • 动态库与静态库

    动态库(Dynamic Library)和静态库(Static Library)是软件开发中常用的两种库文件形式。 动态库:是一组共享的目标代码文件,它们在运行时动态链接到应用程序中。动态库在系统中独立存在,可以被多个应用程序共享。当应用程序运行时,操作系统会加载动态库,并在需要时

    2024年02月08日
    浏览(38)
  • 静态链接库与动态链接库

    由于计算机无法直接理解和执行高级语言(C、C++、Java)程序,需要将 高级语言程序 转换为 机器语言程序 (机器语言是用二进制代码表示的、计算机唯一可以直接识别和执行的一种机器指令的集合),通常把这种转换过程叫做 翻译 。 在C/C++中,整个翻译过程可以分为四步

    2024年02月04日
    浏览(46)
  • 【计算机网络】 静态库与动态库

    库有两种:静态库(.a、.lib)和动态库(.so、.dll)。所谓静态、动态是指链接。静态库是将整个库文件都拷贝到可执行文件中了,而动态库只是将索引文件拷贝到可执行文件中,可以通过索引文件找到动态库文件。 静态库实践 使用方法 首先我们用vs创建一个静态库,再创建

    2024年02月09日
    浏览(49)
  • CMake构建静态库与动态库以及使用

    用例子的方式通俗易懂地解释CMake构建静态库与动态库的过程。 任务: 建立一个静态库和动态库,提供HelloFunc 函数供其他程序编程使用,HelloFunc向终端输出Hello World 字符串。 安装头文件与共享库。 编写一个程序去使用构建的共享库。 (1)建立 t3 目录,用于存放本节涉及到

    2024年02月07日
    浏览(37)
  • .NET Native AOT的静态库与动态库

    .NET不仅可以使用 C静态库与动态库,也可以将.NET实现的函数导出为C静态库与动态库。在没有Native Aot之前,.NET只能通过P/Invoke享受C/C++生态,而在Native Aot之后,不仅可以享受这些生态,还可以开发SDK供其他语言调用。 .NET Native AOT的NativeLib参数用于指定本机库的类型。在.NET

    2024年02月16日
    浏览(36)
  • C/C++库之谜:动态库与静态库探秘

    在软件开发领域,动态库与静态库是常用的编程工具,它们的核心功能是为开发人员提供代码复用的便利性。动态库和静态库可以极大地简化开发流程,提高代码的可维护性。本文旨在探讨动态库与静态库的意义以及应用场景,分析它们在不同系统环境中的特点,并通过实际

    2023年04月20日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包