【Linux:动态库与静态库】

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

1 动态库与静态库的概念

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

 我们可以简单的

 看看我们常用的c/c++库:

【Linux:动态库与静态库】

 那库的名字是啥呢?

我们拿上面图中最下面的两个来说明:

libstdc++.so.6  libstdc++.so.6.0.19

我们的规则是:去掉开头lib,去掉.so或者.a后的内容

所以我们这里得到的库名字都是:stdc++ 

一般来说云服务器只会默认存在动态库,静态库需要我们自己安装。

C/C++静态库安装命令:

sudo yum install -y glibc -static
sudo yum install -y libstdc++ -static

2 为什么要用库

有了库,程序员开发时就能够少去不少麻烦,比如我们如果要自己写一个cout打印函数来帮助打印的话会浪费很多不必要的时间,所以我们一般写C/C++代码时喜欢包含头文件,头文件中就包含了一些常用的接口的声明,那么定义呢?

其实接口的定义我们使用的编译器已经帮助我们将函数定义打好包安装到了默认的搜索路径下,当我们只要包含了头文件,在链接的时候就会去默认路径下找到接口定义的目标文件,然后链接。

我们经常使用的VS2019叫做集成开发环境,其中包含了编辑器,头文件和库,这也是为什么在我们包含了头文件时写头文件中的接口时会有语法提醒,本质上其实就是在头文件中找到该接口。


3 制作静态库

我们首先创建4个文件,将四个文件中.c文件编译生成了.o文件后 ,将.o文件与.h文件交给otherUsr目录中:

【Linux:动态库与静态库】

 再将main.c拷过去:

【Linux:动态库与静态库】

 现在我们在otherUsr中运行:

【Linux:动态库与静态库】

 很显然此时能够运行成功。但是我们一般是把.o文件打包成一个库,打包命令为:

ar -rc libXXX.a *.o

 我们可以来试试:

【Linux:动态库与静态库】

 这时我们为了规范性将libmymath.a放在一个名叫dir的目录下,将*.o的文件放在include的目录下:

【Linux:动态库与静态库】

 这时为了能够找到*.h文件和打包的库文件我们要加上3个选项来帮助编译器来找寻:

-I *.h的文件路径
-L 打包库的路径    //L后面空格可加可不加
-l 打包库名    //l后面空格可加可不加,注意库名不包括lib前缀和.a后缀

 这样就能够成功运行了:

【Linux:动态库与静态库】

 但是为啥我们用C/C++的库就不用这么麻烦呢?原因C/C++的库是安装到指定路径下的,所以我们不用指定路径,如果我们想要将我们自己的库和头文件添加到系统默认配置里面可以用下面方法:

【Linux:动态库与静态库】

 【Linux:动态库与静态库】

 其中系统默认的头文件安装路径是:/usr/include

默认库安装路径是:/lib64

此时我们运行:

【Linux:动态库与静态库】

 我们发现仍然是会报错的,但是已经不是找不到头文件了,而是链接错误,为什么呢?

因为这个是我们自己配置的第三方库,所以我们必须的指定库名称,否则将会找不到库,当我们指定库名称时来试试:

【Linux:动态库与静态库】

 很显然已经成功运行了。

其实这就是第三方库,非语言层面非操作系统层面给我们提供的库,我们自己下载的库一般都会下载到系统编译器默认的搜索路径下方便使用。

总结:第三方库的使用

  • 要指定头文件和库文件。
  • 如果没有安装到系统gcc/g++默认的搜索路径下,用户必须指定选项来告知编译器:a:头文件在哪里b:库文件在哪里c:库文件名称
  • 将我们下载到的头文件和库文件拷贝考系统的默认路径下,需要带上库文件的名称来找到库文件。
  • 一般来说,普通用户将下载好的库安装到系统默认路径下都是需要sudo来提权的。

 4 制作动态库

首先来说,制作动态库时生成目标文件要加上 -fPIC 选项,表示的是与位置无关码

(position ignore code)至于为啥是这样文章末尾会给出解释。

[grm@VM-8-12-centos owner]$ gcc -fPIC -c *.c
[grm@VM-8-12-centos owner]$ ll
total 24
-rw-rw-r-- 1 grm grm   61 Apr  1 22:32 my_add.c
-rw-rw-r-- 1 grm grm   40 Apr  1 22:32 my_add.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_add.o
-rw-rw-r-- 1 grm grm   61 Apr  1 22:33 my_sub.c
-rw-rw-r-- 1 grm grm   39 Apr  1 22:33 my_sub.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_sub.o

 这时我们打包就不用ar命令了,直接用gcc打包,只是要带上选项 -shared

[grm@VM-8-12-centos owner]$ gcc -shared -o libmymath.so *.o
[grm@VM-8-12-centos owner]$ ll
total 32
-rwxrwxr-x 1 grm grm 7952 Apr  2 10:56 libmymath.so
-rw-rw-r-- 1 grm grm   61 Apr  1 22:32 my_add.c
-rw-rw-r-- 1 grm grm   40 Apr  1 22:32 my_add.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_add.o
-rw-rw-r-- 1 grm grm   61 Apr  1 22:33 my_sub.c
-rw-rw-r-- 1 grm grm   39 Apr  1 22:33 my_sub.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_sub.o

这也很好的解释了为啥云服务器默认都是动态库。

为了规范性我们将*.h的文件放进了include目录下,然后将打包生成的动态库放进lib目录下,然后再打包:

【Linux:动态库与静态库】

 将包拷贝给otherUsr并且解压:【Linux:动态库与静态库】

 我们按照之前实现静态库的方式来编译链接:

[grm@VM-8-12-centos otherUsr]$ gcc -o mytest main.c -I include -L lib -l mymath
[grm@VM-8-12-centos otherUsr]$ ll
total 28
drwxrwxr-x 2 grm grm 4096 Apr  2 10:59 include
drwxrwxr-x 2 grm grm 4096 Apr  2 11:02 lib
-rw-rw-r-- 1 grm grm  187 Apr  1 22:48 main.c
-rwxrwxr-x 1 grm grm 8432 Apr  2 11:14 mytest
-rw-rw-r-- 1 grm grm 2359 Apr  2 11:08 owner.tgz
[grm@VM-8-12-centos otherUsr]$ ./mytest
./mytest: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory

我们发现生成了可执行文件,但是运行时却发现找不到文件,这是为啥呀?我们不是已经指定了库的名称和路径了吗?为啥还是找不到呢?

我们可以反过来思考一下:我们使用-L-l选项时是将库的路径和名称告诉了谁?

是操作系统吗?显然不是,我们只是告诉了编译器,但是没有告诉操作系统,也就是操作系统找不到库在哪里了。那为啥静态库就可以呢?

回想一下静态库的原理,静态库直接将用户导的库的二进制代码拷贝到可执行程序中,所以操作系统能够直接找到,但是动态库却不会。

我们可以通过ldd命令查看一下:

【Linux:动态库与静态库】

那么操作系统是如何查找动态库的呢?主要有以下3种方式:

  • 1 通过环境变量 LD_LIBRARY_PATH

我们可以先查看该环境变量里面有什么?

[grm@VM-8-12-centos otherUsr]$ echo $LD_LIBRARY_PATH
:/home/grm/.VimForCpp/vim/bundle/YCM.so/el7.x86_64

然后我们将库路径导入到该环境变量中:

[grm@VM-8-12-centos otherUsr]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/grm/lesson14/otherUsr/lib
[grm@VM-8-12-centos otherUsr]$ echo $LD_LIBRARY_PATH
:/home/grm/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:/home/grm/lesson14/otherUsr/lib

不知道大家注意到没,我们导入环境变量时并没有具体到库的名称,而只是到了存放库的目录路径下,这是为了方便后面我们将其他库也导入该目录中也能够正确使用。

此时我们通过ldd查看:

【Linux:动态库与静态库】

 我们运行起来试试:

【Linux:动态库与静态库】

 很显然能够成功。但是这样做有一个很大的问题:那就是当我们退出的时候配置的环境变量会自动销毁,所以这种方式只是一种临时方案。

  • 2 软链接方案

前面我们介绍了软链接,这里通过软链接是一种比较好的方案:

[grm@VM-8-12-centos otherUsr]$ sudo ln -s /home/grm/lesson14/otherUsr/lib/libmymath.so  /lib64/libmymath.so

这种方式也能够让操作系统找到库:

【Linux:动态库与静态库】

 而且这种方式当我们没有删除软链接的时候是永久保存的,不想要了直接删除软链接即可。

  • 3 配置文件方案

首先我们使用unlink命令解除软链接关系,然后ldd查看:

【Linux:动态库与静态库】

这时已经没有了软链接,然后我们使用配置文件方案:

先查看一下 /etc/ld.so.conf.d 目录下的内容:

【Linux:动态库与静态库】

 然后我们提权创建一个自己的文件,并向文件中写入我们库所在的路径:

[grm@VM-8-12-centos otherUsr]$ sudo touch /etc/ld.so.conf.d/mystudy.conf
[grm@VM-8-12-centos otherUsr]$ sudo vim /etc/ld.so.conf.d/mystudy.conf 
[grm@VM-8-12-centos otherUsr]$ cat /etc/ld.so.conf.d/mystudy.conf 
/home/grm/lesson14/otherUsr/lib

用vim打开文件时一定要提权,否则可能无法保存。

这时为了让配置的文件立即生效需要用 ldconfig 命令:

[grm@VM-8-12-centos otherUsr]$ sudo ldconfig
[grm@VM-8-12-centos otherUsr]$ ldd mytest
	linux-vdso.so.1 =>  (0x00007ffed5dfb000)
	libmymath.so => /home/grm/lesson14/otherUsr/lib/libmymath.so (0x00007f853583b000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f853546d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f8535a3d000)
[grm@VM-8-12-centos otherUsr]$ ./mytest
10 + 20 = 30
10 + 20 = -10

这时便能够成功运行了。


5 动静态库的理解

5.1 静态库的理解

我们知道,静态库是直接将二进制代码拷贝到可执行文件中的,那么当我们若干个进程使用相同的静态库时势必会重复拷贝多份相同的二进制代码,那么这样文件的大小肯定会变大,我们下载时会消耗更多的资源。(所以一般情况下我们不采取静态库)

但是当我们生成了可执行文件后就算我们把静态库删除了也无所谓,因为我们已经将静态库的二进制代码拷贝到了可执行文件中,执行可执行文件依旧能够正常运行。

5.2 动态库的理解

动态库是不会将库的二进制代码直接拷贝到可执行文件的,而是链接时再去寻找,那么我们只需要load一份库的代码到内存中,通过页表映射,当我们执行时再到对应的进程地址空间寻找即可。这份库的代码在进程地址空间中对应着哪一个区呢?答案是共享区。在共享区中存放着库的二进制代码,但是这样会面临着一个问题:不同进程,运行程度是不同的,需要使用的第三方库是不同的,那么注定了每一个进程的共享空间中空闲位置是不确定的,如何找到不同进程对应的库呢?

这时我们使用绝对编址的方法就已经行不通了,那么我们就要采取相对编址的方法,记录偏移量,通过偏移量来找到库的虚拟地址。这就说明此时加载库在共享区的时候随便你怎么加载,我们是通过偏移量来寻找的。

制作动态库时生成目标文件要加上 -fPIC 选项,表示的是与位置无关码

(position ignore code)就是这个原因。文章来源地址https://www.toymoban.com/news/detail-464459.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下动态库和静态库编译实践

    之前写过JNI的文章,在JNI实践过程中,也涉及到对动态库/静态库的一些编译实践,这里统一记录一下。 注意 :-fPIC编译选项可使GCC生成位置无关代码,简单来说生成的代码中的函数与全局变量均为相对地址,通过GOT (Global offset table)来确定其位置,这种方式引入了一层额外的

    2024年01月17日
    浏览(43)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包