目录

一、认识动静态库

二、回顾编译链接的过程

三、库的制作和使用

1.静态库的制作

1.生成二进制(.o)文件

2.打包

3.发布静态库

2.静态库的使用

方法一

方法二

3.动态库的制作

1.生成二进制(.o)文件

2.打包

3.发布动态库

4.动态库的使用

方法一

方法二

四、动态库与静态库特点总结


一、认识动静态库 

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

 我们可以通过 [ ldd 可执行程序文件名 ]来查看可执行程序所依赖的库。

其中 /lib64/libc.so.6 就是可执行程序的库文件,它其实是一个软链接。我们可以通过以下命令来查看

[mlg@VM-20-8-centos lesson5-动静态库]$ ls /lib64/libc.so.6 -l

如何辨别它采用的是哪一种库呢?

1.我们可以通过后缀来区分(在Linux中)

        在Linux中,以 .so 结尾的后缀,是动态库;以 .a 结尾的是静态库  

        在Windows中,以 .dll 结尾的后缀,是动态库;以 .lib 结尾的是静态库  

注:

        库文件的名字:libxxx.so 和 libxxx.a

        库的真实名字:去掉lib前缀,去掉 .a 、.so后缀,剩下的就是库的名称。

2.我们还可以通过file命令查看

        上图中分别使用了动静态库对同一个文件进行编译的,通过file命名可以查看到所对应的链接信息,如果为安装静态库,是编译不通过的,具体安装教程可以点这里Linux——环境基础开发工具的使用

二、回顾编译链接的过程

在Linux中,gcc的编译可以分为一下四个步骤:

  • 预处理:在预处理阶段主要负责的是头文件的展开、去掉注释、宏替换、条件编译等。以#号开头的是预处理指令:#define #if #include...... 此阶段产生【.i文件】
gcc -E mytest.c -o test.i
  • 编译 此阶段完成语法和语义分析,然后生成中间代码,此中间代码是汇编代码,但是还不可执行,gcc编译的中间文件是[.s]文件。在此阶段会出现各种语法和语义错误,特别要小心未定义的行为,这往往是致命的错误。
gcc -S test.i -o test.s
  • 汇编:此阶段主要完成将汇编代码翻译成机器码指令,并将这些指令打包形成可重定位的目标文件,[.o]文件,是二进制文件。此阶段由汇编器完成。
gcc -c test.s -o test.o
  • 链接  此阶段完成文件中叼用的各种函数跟静态库和动态库的连接,并将它们一起打包合并形成目标文件,即可执行文件。此阶段由链接器完成。
gcc test.o -o test

        从以上四个阶段来看,我们要使用自己制作的库或者别人的库,一定是汇编完后产生的.o文件,我们只需要对这个.o文件进行链接就可以了;

三、库的制作和使用 

        库是一个二进制文件,想要使用库(给别人使用自己的制作的库或者使用别人的库)一定是由三个部分组成:库文件、头文件、文档说明;一般这个库文件就是函数的定义,头文件就是函数声明,我们只需要将这些打包好,别人使用我们头文件所给的接口就行。

        编写如下四个文件:其中源文件包含add.csub.c,头文件包含add.hsub.h;用来制作静态库并打包

//add.h
#pragma once
#include <stdio.h>
extern int my_add(int x, int y); 
//add.c
#include "add.h"
int my_add(int x, int y)
{return x + y;
}
//sub.h
#pragma once
#include <stdio.h>
extern int my_sub(int x, int y); 
//sub.c
#include "sub.h"
int my_sub(int x, int y)
{return x - y;
}

1.静态库的制作

1.生成二进制(.o)文件

首先将上面的.c文件生成.o文件

2.打包

我们将生成好的.o文件进行打包:

[mlg@VM-20-8-centos test_lib]$ ar -rc libmymath.a add.o sub.o

ar命令是gnu的归档工具,常用于将目标文件打包为静态库,下面我们使用ar命令的-r 选项和-c选项进行打包。

  • -r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件。
  • -r(rreate):建立静态库文件。

我们可以用 ar 命令的 -t 选项和 -v 选项查看静态库当中的文件。

  • -t:列出静态库中的文件。
  • -v:显示详细的信息

3.发布静态库

        静态库要发布出去供别人使用,只要库文件(所有的.o文件)是不够的,我们需要将其和头文件一起发布出去,别人只要看到头文件,就大致了解如何使用了

当然,我们也可以直接编写Makefile,就不需要我们一步一步的完成静态库的打包及发布

2.静态库的使用

方法一 

        上文中,我们已经有了静态库output了,别人该如何使用呢? 例如:想要在friend文件下使用这个库:

现在在friend目录下有一个mytest.c文件和一个静态库文件lib,mytest.c想要使用lib,我们先编写一下mytest.c代码:

#include "add.h"
#include "sub.h"                                                                                                                                                  int main()
{int x = 30;int y = 20;int ret1 = my_add(x, y);int ret2 = my_sub(x, y);printf("ret1 = %d\n",ret1);printf("ret2 = %d\n",ret2);return 0;
}

 进行编译:

        编译后,报警告:没有头文件,可是明明在lib文件下有我们要的有文件以及库文件,这是为什么呢?

        其实,编译器在编译的时候,会在当前的目录的文件中去找,不会去当前目录的文件夹中去找,lib目录下的头文件以及库文件,和mytest.c不是同级目录,所以编译会出错;

        我们在编译的时候就需要告诉编译器,需要的头文件在哪个目录下。

[mlg@VM-20-8-centos friend]$ gcc mytest.c -I ./lib

        此时,又有警告了:链接错误,未定义的两个函数?在lib目录下已经定义了两个函数,并且打包好了?为什么还是报错呢?

        其原因和上面一样;所以我门还需要告诉编译器库文件在lib目录下:

[mlg@VM-20-8-centos friend]$ gcc mytest.c -I ./lib -L ./lib

头文件和库文件所在位置都告诉编译器了,怎么还是报错呢?

        其实,头文件和库文件都在lib目录下,在mytest.c文件中,是明确的包含了,add.h和sub.h的,gcc在编译的时候能够认识,但不认识库文件,如果在lib目录下有多个库文件,gcc是不知道你想要使用哪个库的。所以我们还需要指明库的名字。

[mlg@VM-20-8-centos friend]$ gcc mytest.c -I ./lib -L ./lib -l mymath

 此时,整个程序才能够正确编译并运行

总结:

我们在使用静态库进行编译链接时,需要指定头文件的所在路径,库文件的所在路径以及所要掉用的库名称

  • -I:指定头文件所在路径。
  • -L:指定库文件所在路径。
  • -l:指明需要链接库文件路径下的哪一个库
[mlg@VM-20-8-centos friend]$ gcc mytest.c -I ./lib -L ./lib -l mymath

 同样,我们也可以编写Makefile:

方法二

        对比我们之前在编译某个.c文件时,为什么有加上这些选项呢?。这是因为之前的库都是在系统的默认路径下,所以我们可以将我们做好的静态库拷贝到系统的默认路径下,也是可以达到不需要加这些选项的效果;但是严重不推荐。

3.动态库的制作

        编写如下四个文件:其中源文件包含add.csub.c,头文件包含add.hsub.h;用来制作动态库并打包

//add.h
#pragma once
#include <stdio.h>
extern int my_add(int x, int y); 
//add.c
#include "add.h"
int my_add(int x, int y)
{return x + y;
}
//sub.h
#pragma once
#include <stdio.h>
extern int my_sub(int x, int y); 
//sub.c
#include "sub.h"
int my_sub(int x, int y)
{return x - y;
}

1.生成二进制(.o)文件

首先将上面的.c文件生成.o文件

[mlg@VM-20-8-centos test_lib]$ gcc -fPIC -c add.c -o add.o
[mlg@VM-20-8-centos test_lib]$ gcc -fPIC -c sub.c -o sub.o

-fPIC:作用是告知编译器 生成位置无关代码(编译产生的代码没有绝对位置,只有相对位置);从而可以在任意地方调用生成的动态库。

2.打包

我们将生成好的.o文件进行打包:

[mlg@VM-20-8-centos test_lib]$ gcc -shared -o libmymath.so add.o sub.o

-shared:linux在gcc编译时加上 -shared 参数时,目的是使源码编译成动态库 .so 文件;

3.发布动态库

将库文件和所有的头文件组织起来,放到lib目录下,这样就可以发布动态库了

当然,我们也可以直接编写Makefile,就不需要我们一步一步的完成静态库的打包及发布

4.动态库的使用

        动态库的使用大致和静态库类似,但略有区别。我们先使用静态库的方法来实现动态库的链接。

能够成功编译,但是运行却报错了,为什么呢?

        我们通过ldd命令列出动态库依赖关系,发现是not found。虽然已经告诉了编译器库文件和头文件的路径所在位置,但是当编译器编译好后,就与编译器无关了;当我们执行(运行)可执行程序a.out时,是由加载器来完成的。所以我们需要在运行时,告诉系统库文件在哪里;

方法一

 拷贝到系统的默认路径下,一般指/usr/lib 这里不做演示,严重不推荐;

方法二 

更改  LD_LIBRARY_PATH

[mlg@VM-20-8-centos lib]$ export LD_LIBRARY_PATH=/home/mlg/lesson5-动静态库/friend/lib

        LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径.注意,LD_LIBRARY_PATH中指定的路径会在系统默认路径之前进行查找;

添加好后,我们再次查看,发现路径已经指定好了 

再次编译运行: 

四、动态库与静态库特点总结

静态库的特点:

  • 静态库在可执行程序链接时就加入到可执行代码中,在物理上成为可执行程序的一部分;程序运行时将不再需要该静态库。
  • 相对于动态库链接生成的程序,静态函相当于编译器将代码补充完整了,因此执行程序会大一些,但是运行起来相对快些;
  • 静态库是牺牲了空间效率,换取了时间效率;

动态库的特点:

  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在;
  • 动态库只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。这样就使可执行文件比较小, 节省磁盘空间;
  • 由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些;
  • 动态库是牺牲了时间效率,换取了空间效率;

Linux —— 动态库和静态库相关推荐

  1. linux代码动态分析软件,举例分析Linux动态库和静态库

    函数库分为静态库和动态库两种.创建Linux静态库和Linux动态库和使用它们在这里将以举例的形式详述一下.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不 ...

  2. Linux动态库和静态库比较

     Linux动态库和静态库比较文件预览 文件目录树如下,如你所见,非常简单.    1. libtest/    2. |-- lt.c    3. |-- lt.h    4. `-- test.c ...

  3. Linux中的动态库和静态库(.a/.la/.so/.o)

    为什么80%的码农都做不了架构师?>>>    Linux中的动态库和静态库(.a/.la/.so/.o) Linux中的动态库和静态库(.a/.la/.so/.o) C/C++程序 ...

  4. 举例分析Linux动态库和静态库

    转自:http://www.xxlinux.com/newxxlinux/development/gui/2012-01-05/499.html 函数库分为静态库和动态库两种.创建Linux静态库和L ...

  5. Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库

    文件描述符 重定向 文件系统 软链接和硬链接 动态库和静态库 文件描述符 上面两个接口分别是c语言的fread接口和linux的read接口,当我们在使用的时,可能会有疑问,为什么linux的io接口 ...

  6. linux系统下的“静态库和动态库”专题之二:库的创建和使用

    接上文[linux系统下的"静态库和动态库"专题之一:库的概念和规则]所述,我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种. – 静态库在程序编译 ...

  7. linux系统下的“静态库和动态库”专题之一:库的概念和规则

    什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的本质不同,因此二者的库也是不兼 ...

  8. gcc g++ Linux下动态库_静态库

    关于Unix静态库和动态库的分析 基本概念 库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀. 例如:libhello.so libhello.a 为了在同一系统中使用不同版本的库,可以在 ...

  9. Linux库概念及相关编程(动态库、静态库、环境变量)

    分文件编程: 好处:分模块编程思想,功能和责任划分清楚便与调试,main函数简洁,代码易于阅读. 编程时头文件有的是使用<>这个符号括起来的,有的是" "使用的是双引号 ...

  10. linux动态库与静态库混合连接

    在应用程序需要连接外部库的情况下,linux默认对库的连接是使用动态库,在找不到动态库的情况下再选择静态库.使用方式为: gcc test.cpp -L. -ltestlib 如果当前目录有两个库li ...

最新文章

  1. 智源大会参会指南:4天 100+场顶尖报告,硬核高密度,如何才能不留遗憾?
  2. 离开百度三年多,吴恩达纽交所敲钟,身价再增20亿
  3. 本地windows上传大文件到Linux服务器工具的选择以及使用方法
  4. Windows10选择文件打开方式没有始终允许的解决方案
  5. 数据库-优化-pt-query-digest使用简介
  6. 关系数据库查看器应用程序-ASP.NET Core
  7. 简单实现系统托盘 - 回复 闪 的问题
  8. Start Developing iOS Apps Today系列之应用程序(七)
  9. c语言数组的概念和指针的加减使用
  10. Linux学习笔记(更新中)
  11. 华为云devops认证考试课堂笔记4
  12. mac vs 返回上一步_mac 后退一步 快捷键
  13. 信创办公--基于WPS的Word最佳实践系列(应用导航窗格:轻松掌握文章结构)
  14. 基于android手机实时监控ipcam视频之三:H.264的RTP打包解析
  15. 【主板上各种接口和附属部件科普】
  16. 第一节:(2)逻辑芯片工艺特性指标
  17. 产品分析报告—年轻人的体育社区—虎扑
  18. Bootloader的启动与功能
  19. java回收策略_Java 中的垃圾回收策略
  20. 超快速的桌面搜索工具 - EveryThing绿色汉化版

热门文章

  1. 《Windows程序设计》学习笔记(chap10菜单及其它资源)(一)
  2. 如何修改PDF,PDF怎么旋转页面方向
  3. Spring框架学习总结(上)
  4. 【Linux】Linux基本操作指令
  5. 各种文件后缀名与打开方式
  6. libcurl官方手册
  7. C++程序设计基础(揣锦华版)课后习题答案-第一章:程序设计基础知识
  8. 基于Qt的NAT检测和NAT穿透
  9. 五阶段--使用 Kibana 操作 ES/ 搜索
  10. Tuxera NTFS2023Mac读写ntfs磁盘工具