【Linux】动态库与静态库

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

目录

一、前言

二、静态库与动态库

三、生成静态库

1、生成原理

2、完整过程

3、总结

四、生成动态库

1、环境变量

2、建立软链接

3、配置文件

五、动态库的加载

1、动态库加载的过程

2、动态库地址的理解

3、补充内容


一、前言

 关于动态库与静态库的一小部分前置内容,我曾在文章《编译器 - gcc && 函数库》中有过详细的说明。

 实际上,系统已经预装了C/C++的头文件和库文件。头文件提供方法的说明,库函数提供方法的实现,头和库是要组合在一起使用的。头文件在预处理阶段就引入了,链接的本质就是链接库。

 所以我们在安装开发环境时,实际上就是在安装对应语言配套的库和头文件。在使用编译器时,都会有语法的自动提醒功能,这需要先包含头文件。语法提醒的本质是,编译器会自动将用户输入的内容,不断地在被包含的头文件中进行搜索,自动提醒功能是依赖头文件实现的。

 在写代码时,环境之所以知道代码中哪些地方有语法错误,哪些地方定义变量有问题,是因为编译器工作模式有命令行模式和其他自动化的模式,在用户写代码时,会不断的进行预处理、编译操作,帮助用户不断地进行语法检查。

 库存在的目的是为了提高开发效率。

二、静态库与动态库

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

三、生成静态库

1、生成原理

这里先实现一个简单的加减法程序:

//myadd.h
#pragma once
int myadd(int d1, int d2);

//myadd.c
#include "myadd.h"
int myadd(int d1, int d2)
{
    return d1 + d2;
}

//mysub.h
#pragma once
int mysub(int d1, int d2);

//mysub.c
#include "mysub.h"
int mysub(int d1, int d2)
{
    return d1 - d2;
}

以上程序编写完成后,可以直接把源代码打包给其他程序使用:

【Linux】动态库与静态库

 编译运行:

【Linux】动态库与静态库

 结果符合预期。


 如果我们想让其他人调用自己程序的一些功能,但是不想把源代码交给其他人,则可以把自己的程序经过预处理、编译、汇编,生成 .o 文件,即可重定位目标二进制文件,交给别人使用。

现在先把实现功能的源代码与使用功能的程序分别分离到 mylib 与 otherPerson 目录中:

【Linux】动态库与静态库

 使用指令 gcc -c [源文件] 生成 .o 文件,并把它放到 otherPerson 目录中:

【Linux】动态库与静态库

 进入到 otherPerson 目录中后,先把 main.c 文件也使用指令 gcc -c 生成 .o 文件,再与其他 .o 文件进行链接,最后生成可执行文件:

【Linux】动态库与静态库

 最终结果符合预期。


为了方便传输 .o 文件,我们通常会对这些文件进行打包。打包生成静态库指令:

ar -rc [lib文件名.a] [*.o]

【Linux】动态库与静态库

 把 *.a 文件和 *.h 文件都复制到 otherPerson 中后,编译 main.c 生成可执行程序:

【Linux】动态库与静态库

 出现了如上报错,这是因为当有了库之后,要将库引入项目中,必须要让编译器找到头文件与库文件。由于gcc 与 g++ 只认识 C语言 和 C++ 的库,我们自己引入的库属于第三方库,编译器不认识,当然也就找不到。

 因此,必须自己说明需要链接哪一个库:

gcc -o [可执行程序] [被编译文件] -L[库所处路径] -l[库名]

【Linux】动态库与静态库

 结果符合预期。

2、完整过程

 有了以上知识,我们已经知道静态库是怎么封装以及交给别人使用的了。但实际上静态库的传输与使用的真正步骤与上面演示的有所不同,具体过程如下:

 形成静态库后,创建一个 include 目录和一个 lib 目录,分别放入 .h 文件与 .a  文件:

【Linux】动态库与静态库

 接下来为了让别人使用自己的静态库,则可以把这两个目录打包并上传,供别人下载使用:

【Linux】动态库与静态库

 使用静态库指令:

gcc -o [可执行文件] [源代码文件] -I[头文件路径] -L[库文件路径] -l[库文件名称]

 结合静态库编译并运行观察结果:

【Linux】动态库与静态库

 结果符合预期。

 如果不想在编译时指明这么一长串的路径,也可以直接把对应的头文件与库文件拷贝到 gcc、g++ 的默认搜索路径下:

【Linux】动态库与静态库

 之后就无需再指明头文件与库的路径,只需说明使用第三方库的名字就可以正常编译使用了。

3、总结

自己生成使用第三方库时,需要满足两个条件:

  1. 需要指定的头文件和库文件
  2. 如果库没有默认安装到系统gcc、g++默认的搜索路径下,用户必须指明对应的选项告知编译器:头文件在哪里、库文件在哪里、库文件是什么名字。
  3. 将下载下来的库和头文件,拷贝到系统默认路径下,这就叫做操作系统中库的安装。对于任何软件而言,安装和卸载的本质就是拷贝到系统特定的路径下,或者从特定路径下删除。
  4. 如果我们安装的库是第三方的(第一方是语言,第二方是操作系统调用接口),在使用时,需要用 -l 说明对应库的名字。
  5. 无论我们是从网络中直接下载的库,还是源代码(编译方法)。都会提供一个 make install 安装的命令,这个命令所做的就是安装到系统中的工作。我们安装大部分指令、库等等都是需要 sudo 提权的。

四、生成动态库

shared: 表示生成共享库格式
fPIC:产生位置无关码(position independent code)
库名规则:libxxx.so

 在生成动态库 .o 文件时,需要给指令gcc加上 -fPIC 命令选项,产生位置无关码:

【Linux】动态库与静态库

 接下来与静态库相同,也需要把 .o 文件打包以便上传。不同之处在于动态库是使用 gcc 指令进行打包:

gcc -shared -o [lib库名.so] [*.o]

【Linux】动态库与静态库

  形成动态库后,创建一个 include 目录和一个 lib 目录,分别放入 .h 文件与 .a  文件:

【Linux】动态库与静态库

 接下来为了让别人使用自己的动态库,则可以把这两个目录打包并上传,供别人下载使用:

【Linux】动态库与静态库

 使用动态库编译后运行观察结果:

【Linux】动态库与静态库

 发现程序运行报错,提示无法打开共享对象文件。

 这是因为我们使用 -l -L 选项说明路径,是向编译器说明的,而不是向OS说明。在程序运行的时候,因为 .so 没有在系统的默认路径下,所以OS依旧找不到。

 注意这里与静态库进行区分,静态库这样可以运行是因为,静态库的链接原则是将用户使用的二进制代码直接拷贝到目标可执行程序中,但是动态库不会。

 OS查找动态库有以下几种方法:

  1. 设置环境变量:LD_LIBRARY_PATH。
  2. 在系统指定路径下建立软链接,指向对应的库。
  3. 配置文件。

1、环境变量

  使用 echo 指令查看环境变量 LD_LIBRARY_PATH
【Linux】动态库与静态库

 直接使用 export 指令将库的路径添加进该环境变量就可以了:

【Linux】动态库与静态库

 此时程序可以正常执行,且结果符合预期。

 因为环境变量在我们退出终端再次登录的时候会被重置,所以我们下一次登陆时就需要重新设置一遍环境变量,否则无法正常运行。

2、建立软链接

 因为库的默认搜索路径是 /usr/lib64 /lib64 。所以我们可以直接挑选一个路径,在该路径下建立对应库的软链接,这里以 /lib64 为例:

【Linux】动态库与静态库

编译运行,结果符合预期。

因为软链接是一个正常的文件,永远保存在磁盘上,所以我们退出后再次登录时,程序依然可以正常运行。 

3、配置文件

相关配置文件所处路径: /etc/ld.so.conf.d

【Linux】动态库与静态库

这些配置文件中存放库所在的路径。

现在我们自己在此目录下 touch 一个配置文件,并在该配置文件内输入所需库的路径:

【Linux】动态库与静态库

 更改完配置文件后,需要让该配置文件生效。采用指令:

ldconfig

【Linux】动态库与静态库

 运行程序,结果符合预期。

五、动态库的加载

1、动态库加载的过程

 当使用动态库编译好了一个可执行文件后,该可执行文件存储在磁盘当中,并在运行时加载到内存里。

 我们知道,程序被加载到内存后就变成了进程,OS会在内存中创建对应的 task_struct mm_struct 、 页表 。用户在执行程序中的代码时,正常执行。当需要执行动态库内的代码时,OS会找到动态库,把动态库加载到内存中,并建立页表映射关系,映射到虚拟地址空间的共享区中。这些动作都是由OS自动完成的。

 可执行文件在被编译完成时,就已经具备了对应的虚拟地址。以上动作完成后,再执行动态库内的代码,OS会自动识别,并跳转到虚拟地址的共享区部分,通过页表的映射关系,执行内存中对应的动态库代码,动态库代码执行完毕后,再回到虚拟地址的代码区部分,继续执行下面的其他代码。

 换句话说,只要把库加载到内存,映射到进程的地址空间后,进程执行库中的方法,就依旧还是在自己的地址空间内进行函数跳转即可。

 所以动态库节省资源的原因就在于,动态库里的所有方法在内存里只需要存放一份就可以了,其他所有进程都可以调用。

2、动态库地址的理解

 在程序编译链接形成可执行程序的时候,可执行程序内部就已经有地址了,地址一共有两类,分别是绝对编址与相对编址。

 动态库必定面临一个问题:不同的进程,运行程度不同,需要使用的第三方库是不同的,这就注定了每一个进程的共享区中的空闲位置是不确定的。因此,动态库中函数的地址,绝对不能使用绝对编址,动态库中的所有地址都是偏移量,默认从 0 开始。简单来说,库中的函数只需要记录自己在该库中的偏移量,即相对地址就可以了。

 当一个库真正的被映射到进程地址空间时,他的起始地址才能真正的确定,并且被OS管理起来。OS本身管理库,所以OS知道我们调用库中函数时,使用的是哪一个库,这个库的起始地址是什么。当需要执行库中的函数时,只需要拿到库的起始地址,加上对应函数在该库中的偏移量,就能够调用对应函数了。

 借助函数在库中的相对地址,无论库被加载到了共享区的哪一个位置,都不影响我们准确的找到对应函数。所以这种库被称为动态库,动态库中地址被称为与位置无关码。

3、补充内容

  1.  动态库和静态库同时存在,默认使用动态链接。如果想要使用静态链接,则需要在编译时加上 -static 命令选项。
  2.  如果不提供动态库,只提供静态库,且在编译时不加 -static 命令选项。那么程序在链接时,对于该库,会默认使用静态链接。而对于其他的,比如C库等等,依然默认使用动态链接。

 关于动静态库的相关内容就讲到这里,希望同学们多多支持,如果有不对的地方,欢迎大佬指正,谢谢!文章来源地址https://www.toymoban.com/news/detail-429509.html

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

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

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

相关文章

  • 【Linux】静态库与动态库制作及运行原理

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

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

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

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

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

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

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

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

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

    2024年02月07日
    浏览(40)
  • VS2019静态库与动态库入门操作指南

    源代码的二进制文件; 分为动态编译与静态编译; 1)区别 (1)动态编译不便于发布,静态编译便于发布; (2)动态编译生成的可执行文件体积较小,静态生成的可执行文件体积较大。 ​ Windows中静态库后缀为.lib 动态库后缀为.dll ​ Linux中静态库后缀为.a 动态库后缀为.

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

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

    2023年04月20日
    浏览(42)
  • .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日
    浏览(37)
  • 「C/C++」C/C++静态链接库与动态链接库

    博客主页:何曾参静谧的博客 文章专栏:「C/C++」C/C++学习 静态链接库(Static Linking Library): 是在编译时将库代码与应用程序静态链接在一起的库。它们被编译为二进制文件,并在运行时作为应用程序的一部分被载入内存。这种库被称为“静态”是因为它们在编译时被链接,

    2024年02月01日
    浏览(43)
  • 【看表情包学Linux】软硬链接 | 软连接数 | 创建软硬链接 | 动静态库 | 生成静态库 | 生成动态库

       🤣  爆笑 教程  👉 《看表情包学Linux》👈   猛戳订阅     🔥 💭 写在前面: 上一章我们讲解了 inode,为文件系统收了尾,这几章我们充分地讲解完了文件系统的知识点,现在我们开始开始学习软硬链接了。如果没有文件系统的铺垫,想直接理解软硬链接难免有些困

    2024年02月14日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包