动静态库

文章目录

  • 动静态库
    • 动静态库的概念
    • 动态链接的特点
    • 静态链接的特点
    • 查看文件的动静态链接属性
    • 动态链接的机理
    • 生成&&使用静态库
    • 生成&&使用动态库
    • 使用外部库

动静态库的概念

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

动态链接的特点

ldd 文件名

/lib64/libc.so.6是软链接

当顺序执行到printf中程序中没有该函数,跳转到库中执行完再返回后续代码执行。动态库并没有把代码拷贝进来,因此程序体积比较小。

objdump -d test:

  • 动态链接的特点

    • 体积小

    • 依赖库

      • 因此删库之后连系统中以C为依赖的命令都用不了了。
    • 运行的时候加载的,可以只有一份。而进程在内存中,没跑到对应函数的时候是不会将处于磁盘上的动态库中的对应代码加载到内存中的

静态链接的特点

gcc -o $@ $^ -static

静态库是将对应的printf函数部分拷贝到自己的程序中。

objdump -d test-s

  • 静态链接的特点

    • 将对应代码拷贝进bin,体积比较大
    • bin可移植性强
    • 链接的时候纳入进来,可能比较占资源(硬盘和内存)
      • 比如每个程序都用了printf,那每份程序里面的printf其实就是冗余的

查看文件的动静态链接属性

file 文件名

动态链接的机理

通过代码区找到映射区的区域,通过页表找到内存中动态库的位置。

当前是一个进程,如果是100个动态链接的进程,代码是只读的,其他进程通过各自页表映射进程地址空间的共享区,因此库我文件只要一份就行。

而静态链接是把拷贝进来的代码放在代码区了,所以代码区变得很大。

生成&&使用静态库

我们要提供两个东西,头文件和库文件。

一批头文件:有什么方法可以使用,接口参数是什么意思

一个、多个库文件:具体的实现,供我们动静态链接。

链接的本质:链接.o文件,lib文件。

而动静态库就是把所有.o文件打包,命令成.a。

#ifndef MY_LIB_H
#define MY_LIB_H
#include<stdio.h>
void myprintf();#endif
#include"mylib.h"void myprintf()
{printf("hello world!\n");
}

gcc -c xxx.c

单纯不带包给别人用只要把.o和.h给别人即可。不过这样使用注意需要makefile的时候加上其.o为依赖项目,不然找不到对应的符号。

test:test.c mylib.ogcc -o $@ $^
.PHONY:clean
clean:rm -rf *.o test test-static
#include"mylib.h"int main()
{myprintf();
}

但是数量多起来就不方便了,需要打包。

  1. 自己定义库——一批头文件和源文件,只把源文件处理成.o,使用ar -rc(replace and create)打包成一个静态库
  2. 给别人使用的时候提供头文件和静态库。但是gcc的时候面临问题,比如头文件和静态库不在当前目录下(如果在当前目录下-I就不需要了),需要-I指出头文件目录,需要-L指明库的搜索路径,-l指出库搜索路径中的要用的库名(去掉lib和.后的,可以带空格也可以不带),-static指出静态链接。
  • 第一步:将.o文件打包成静态库
ar -rc libxxx.a xxx.o xxx.o

ar命令是gnu的归档工具,常用于将目标文件打包为静态库

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

  • 第二步:使用静态库

path = $(shell pwd) #可以不要这个path使用相对路径test:test.cgcc -o $@ $^ -I $(path)/mylib/include -L $(path)/mylib/lib -l mymath -static.PHONY:clean
clean:rm -f test
  • -I选项指定头文件搜索路径
  • -L选项指定库文件搜索路径
  • -l选项指明需要链接库文件路径下的哪一个库

但是这样挺麻烦的,怎么样不用这些选项呢?

有一种粗暴的方式是把自己的头文件和库扔到stdio.hlibc.a的系统默认的搜索路径下。但是这样做会污染其他文件环境。所以还是乖乖地放当前路径下文件夹中把选项带上。

(所谓框架就是这样,下载来之后就是一堆头文件和库)

sudo cp mylib/include/* /usr/include/
sudo cp mylib/lib/libmymath.a /lib64/

需要注意的是,虽然已经将头文件和库文件拷贝到系统路径下,但当我们使用gcc编译main.c生成可执行程序时,还是需要-l指明需要链接库文件路径下的哪一个库。

./test -lmymath

为什么之前使用gcc编译的时候没有指明过库名字?

因为我们使用gcc编译的是C语言,而gcc就是用来编译C程序的,所以gcc编译的时候默认就找的是C库,但此时我们要链接的是哪一个库编译器是不知道的,因此我们还是需要使用-l选项,指明需要链接库文件路径下的哪一个库。

生成&&使用动态库

extern"C"的实例见c++基础的笔记。

windows中的动态库为.dll,静态库是.lib。

  • 第一步:让所有源文件生成对应的目标文件
gcc -fPIC -c add.c
gcc -fPIC -c sub.c

此时用源文件生成目标文件时需要携带-fPIC选项:

  • -fPIC(position independent code):产生位置无关码

说明:

  1. -fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
  2. 如果不加-fPIC选项,则加载.so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的拷贝,并且每个拷贝都不一样,取决于这个.so文件代码段和数据段内存映射的位置。
  3. 不加-fPIC编译出来的.so是要在加载时根据加载到的位置再次重定位的,因为它里面的代码BBS位置无关代码。如果该.so文件被多个应用程序共同使用,那么它们必须每个程序维护一份.so的代码副本(因为.so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)。
  4. 我们总是用-fPIC来生成.so,但从来不用-fPIC来生成.a。但是.so一样可以不用-fPIC选项进行编译,只是这样的.so必须要在加载到用户程序的地址空间时重定向所有表目。
  • 第二步:使用-shared选项将所有目标文件打包为动态库
gcc -shared -o libmymath.so add.o sub.o

-shared 代表共享库

  • 第三步:将头文件和生成的动态库组织起来

将add.h和sub.h放到include下,将动态库文件放到lib下,两个文件都放到mylib下。此时就可以给别人使用了。

  • 封装成makefile

生成动态库的makefile

libmymath.so:myadd.o mysub.ogcc -shared -o $@ $^
myadd.o:myadd.cgcc -fPIC -c $<
mysub.o:mysub.cgcc -fPIC -c $<.PHONY:output
output:     #打包发给别人的mkdir -p mylib/includemkdir -p mylib/libcp *.h mylib/includecp *.so mylib/lib.PHONY:clean
clean:rm -rf output *.o libmymath.so

生成.out的makefile

path = $(shell pwd) #可以不要这个path使用相对路径test:test.cgcc -o $@ $^ -I $(path)/mylib/include -L $(path)/mylib/lib -l mymath .PHONY:clean
clean:rm -f test

光是这样生成并不能使用动态库,因为程序要使用的时候操作系统不知道动态库在哪。上述的行为是让gcc知道的-l动态库。

因此让操作系统知道使用的动态库方法有三:

  1. 我们需要将自己的动态库文件拷贝到系统共享库路径下/usr/lib

    sudo cp mlib/lib/libmymath.so /lib64
    
  2. 更改LD_LIBRARY_PATH

    类似PATH帮我们找可执行程序,这个环境变量帮我们找动态库

ldd test

export LD_LIBRARY_PATH=/home/ycb/demo1/mylibso/mylib/lib
ldd test

此时结果正常运行

  1. 配置/etc/ld.so.conf.d/+ldconfig更新

我们可以通过配置/etc/ld.so.conf.d/的方式解决该问题,/etc/ld.so.conf.d/路径下存放的全部都是以.conf为后缀的配置文件,而这些配置文件当中存放的都是路径,系统会自动在/etc/ld.so.conf.d/路径下找所有配置文件里面的路径,之后就会在每个路径下查找你所需要的库。我们若是将自己库文件的路径也放到该路径下,那么当可执行程序运行时,系统就能够找到我们的库文件了。

使用外部库

系统中其实有很多库,它们通常由一组互相关联的用来完成某项常见工作的函数构成。

gcc -Wall test.c -o test -lm
#include <math.h>
#include <stdio.h>
int main(void)
{double x = pow(4.0, 5.0);printf("%lf\n", x);return 0;
}

对于这份代码,加不加math.h都能跑出来。当然加了C语言的第三方库的libm.so也能跑出来。

ls /usr/lib64/libm.so

但是在老版本中可能会找不到对应的库。(比如上次做yacc的编译原理lab的时候没有-l m导致pow一直没反应。

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基础——gcc编译、静态库与动态库(共享库)

    Linux基础--gcc编译.静态库与动态库(共享库) https://blog.csdn.net/daidaihema/article/details/80902012 Linux基础--gcc编译 ...

  6. Linux下制作和使用静态库和动态库

    写在前面: ldd + 可执行文件 可以查看可执行文件所依赖的库 概述: Linux操作系统支持的函数库分为静态库和动态库,动态库又称共享库.linux系统有几个重要的目录存放相应的函数库,如/lib ...

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

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

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

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

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

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

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

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

最新文章

  1. 小型星形网络结构设计示例
  2. 第四组视频:在bash脚本中使用脚本选项
  3. 独家 | 使用机器学习预测房价(附链接)
  4. 怎么样从一个疯狂下载者成为一个学习者(转)
  5. 自建ELK迁移阿里云日志服务
  6. 【vue开发】vue插件的install方法
  7. TCP三次握手及四次挥手详细图解(转)
  8. layui表格——table.render(options)(转)
  9. 裁剪左上角x左上角y填什么_少了立体裁剪,你的服装设计生涯还完整吗?
  10. Dev-C++配置问题
  11. layui 上传图片回显并点击放大实现
  12. c语言补码取反后什么意思,补码为什么取反加一
  13. 数学建模学习之模糊评价法
  14. win10如何添加linux开机引导,win10 linux 双系统怎么设置开机引导
  15. MATLAB函数step()对单位负反馈系统求阶跃响应
  16. Vue前端框架选型论证,字节跳动高级java开发面试
  17. phpstorm 报 expecting statement
  18. [日更-2019.3.31]如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
  19. 图纸上标注的是实际尺寸吗_CAD比例画图时,图上标的尺寸,是实际尺寸还是图上尺寸啊?...
  20. oracle 6i,Oracle Reports 6i培训教程.doc

热门文章

  1. 晨魅--高拍仪二次开发
  2. 高拍仪二次开发(多浏览器,BS,Web)样例
  3. 微信小程序实现自动定位
  4. html5框架如何快速搭建,AmazeUI框架搭建的方法步骤(图文)
  5. 《HybridSN: Exploring 3-D–2-DCNN Feature Hierarchy for Hyperspectral Image Classification》论文学习笔记
  6. android 极光推送教程 视频教程,Android 极光推送教程
  7. 2.Smali的基础语法
  8. 第六篇:A133 用DragonSN工具刷SN号,MAC地址细节问题
  9. 【CGAL_网格处理】平滑处理
  10. 电脑外接显示器或ipad分屏