Linux静态库和动态库

  • 1. 编译与ELF格式
  • 2. 库的基本概念
  • 3.静态库的制作:(假设要将a.c、b.c制作成静态库)
  • 4.静态库的常见操作
  • 5.静态库的使用
  • 6. 多个库的相互依赖
    • 举例1.(库文件制作、错误处理)
  • 7.静态库和动态库的关系和区别
  • 8.动态库的制作
    • 软链接 | 硬链接
    • 软连接和硬链接区别


1. 编译与ELF格式

预处理:解释并展开源程序当中的所有的预处理指令,此时生成 *.i 文件。(宏替换)
命令:gec@ubuntu:~$ gcc hello.c -o hello.i -E
编译:词法和语法的分析,生成对应硬件平台的汇编语言文件,此时生成 *.s 文件。
命令:gec@ubuntu:~$ gcc hello.i -o hello.s -S
汇编:将汇编语言文件翻译为对应处理器的二进制机器码,此时生成 *.o 文件。
命令:gec@ubuntu:~$ gcc hello.s -o hello.o -c
链接:将多个 *.o 文件合并成一个不带后缀的可执行文件。
命令:gec@ubuntu:~$ gcc hello.o -o hello -lc

重点关注最后一步,库文件的链接:链接实际上是将多个.o文件合并在一起的过程。这些 *.o 文件合并前是 ELF 格式,合并后也是 ELF
格式。ELF全称是 Executable and Linkable Format,即可执行可链接格式
库的本意是library图书馆,库文件就是一个由很多 *.o 文件堆积起来的集合。 ELF需要对各个 *.o
文件中的静态数据(包括常量)、函数入口的地址做统一分配和管理,这个过程就叫做“重定位”,因此未经链接的单独的 *.o
文件又被称为可重定位文件,经过链接处理合并了相同的段的文件称为可执行文件。

2. 库的基本概念

库文件分为两类:静态库和动态库。如:

静态库:libx.a
动态库:liby.so
lib库名.后缀

其中,lib是任何库文件都必须有的前缀,库名就是库文件真正的名称,比如上述例子中两个库文件分别叫x和y,在链接它们的时候写成 -lx 和 -ly ,后缀根据静态库和动态库,可以是 .a 或者 .so:

静态库的后缀:.a (archive,意即档案)
动态库的后缀:.so (share object,意即共享对象)
注意:不管是静态库,还是动态库,都是可重定位文件 *.o 的集合。

3.静态库的制作:(假设要将a.c、b.c制作成静态库)

*第一步,制作 .o 原材料

gec@ubuntu:~$ gcc a.c -o a.o -c
gec@ubuntu:~$ gcc b.c -o b.o -c

*第二步,将 .o 合并成一个静态库

gec@ubuntu:~$ ar crs libx.a a.o b.o

4.静态库的常见操作

#查看 *.o 文件
gec@ubuntu:~$ ar t libx.a  #(t意即table,以列表方式列出*.o文件)
a.o
b.o
# 删除 *.o 文件
gec@ubuntu:~$ ar d libx.a b.o #(d意即delte,删除掉指定的*.o文件)
gec@ubuntu:~$ ar t libx.a
a.o
# 增加 *.o 文件
gec@ubuntu:~$ ar r libx.a b.o #(r意即replace,添加或替换(重名时)指定的*.o文件)
gec@ubuntu:~$ ar t libx.a
a.o
b.o
# 提取 *.o 文件
gec@ubuntu:~$ ar x libx.a #(x意即extract,将库中所有的*.o文件释放出来)
gec@ubuntu:~$ ar x libx.a a.o #(指定释放库中的a.o文件)

5.静态库的使用

库文件最大的价值,在于代码复用。假设在上述库文件所包含的*.o文件中,已经包含了若干函数接口,那么只要能链接这个库,就无需再重复编写这些接口,直接链接即可。

假设a.c中包含了如下函数:

// a.c
void func()
{printf("我是a.c中的函数func\n");
}

那么,就可以使用链接库的形式,使用这个接口:

// main.c
void func(); //函数要声明
int main()
{func();return 0;
}

编译并运行的结果是: -L/库路径 -l库名 -i 头文件路径

gec@ubuntu:~$ gcc main.c -L/home/gec -lx -o main
gec@ubuntu:~$ ./main
我是a.c中的函数func
gec@ubuntu:~$

注意:

编译语句中的 -L/home/gec 指明库文件 libx.a 的具体位置,否则系统找不到该库文件。 编译语句中的 -lx
指明要链接的库文件的具体名称,注意不包含前缀后缀。 对于静态库而言,由于编译链接时会将 main.c
所需要的库代码复制一份到最终的执行文件中,这直接导出静态库的如下特性: 执行程序在编译之后与静态库脱离关系,其执行也不依赖于静态库。
执行程序执行时由于不依赖静态库,因此也省去了运行时动态。

6. 多个库的相互依赖

假设有两个库文件:liba.a 和 libb.a,它们分别只包含了 a.o 和 b.o,假设这两个源程序有如下依赖关系:

// a.c
#incldue <stdio.h>
void fa()
{printf("Hey!\n");
}// b.c
#incldue <stdio.h>
void fa();  //fa()在这里被声明了
void fb()
{fa(); // fb() 调用了 fa(),即libb.a依赖于liba.a
}

很明显,b.c中的功能接口是依赖于 a.c 的,换句话说,库文件 libb.a 是依赖于 liba.a 的。
现在再来写一个调用 fb() 的主函数:

void fb();
int main(void)
{fb();
}

编译情况如下:

gec@ubuntu:~$ gcc main.c -o main -L. -lb -la                     //谁要用我的方法,谁就在我的前面
gec@ubuntu:~$ gcc main.c -o main -L. -la -lb
./libb.a(b.o): In function `fb':
b.c:(.text+0xa): undefined reference to `fa'
collect2: error: ld returned 1 exit status

从以上编译信息来看,得出结论:

当编译链接多个库,且这些库之间有依赖关系时,被依赖的基础库要放在编译语句的后面。 在以上示例中,库 libb.a 依赖于 liba.a,即
liba.a 是被依赖的基础库,因此 -la 要放在 -lb 的后面才能通过编译。 注意:以上结论对于静态库、动态库都适用。

举例1.(库文件制作、错误处理)

【1】将常用的文件IO函数封装成自报错的静态库和动态库,并在要以后的程序中根据需要调这些库文件。read.c

例如:
gcc read.c -o read.o -c   生成连接文件
ar  crs  libread.a read.o    生成静态库
ssize_t Read(int fd, void *buf, size_t count)
{int total = 0;int n;while(count > 0){while((n=read(fd, (char *)buf+total, count))==-1 &&errno == EINTR);//(char *)buf+total :  buf指针,指向每次读取到的数据  加total确保数据不被覆盖  准确定位数据增加后每次的位置if(n == -1) // 遇到了错误{perror("read失败");return -1;}if(n == 0) // 遇到了文件尾时=0break;count -= n;  //n每次读到的大小   count 总的大小   count = count-n  :减去每次读的数据total += n;  //total统计每次读到的数据   total =total+n  }// 返回总共读到的字节数return total;
}

7.静态库和动态库的关系和区别

静态库(相当于书店,只卖不借)
原理:编译时,库中的代码将会被复制到每一个程序中
优点:程序不依赖于库、执行效率稍高
缺点:浪费存储空间、无法对用户升级迭代
动态库(相当于图书馆,只借不卖)
原理:编译时,程序仅确认库中功能模块的匹配关系,并未复制
缺点:程序依赖于库、执行效率稍低
优点:节省存储空间、方便对用户升级迭代

8.动态库的制作

lib库名.后缀 对于动态库而言,在后缀后面还经常会带着版本号: lib库名.后缀.版本号 完整的动态库文件名称是:
lib库名.so.主版本号.次版本号.修订版本号,比如: libx.so.1.3.1 动态库一般会用一个只带主版本号的符号链接(软连接ln
-s 生成)来链接程序(方便版本更新换代),

软链接 | 硬链接

1、软链接就是:“ln –s 源文件 目标文件”,只会在选定的位置上生成一个文件的镜像,不会占用磁盘空间,类似与windows的快捷方式。
2、硬链接ln源文件 目标文件,没有参数-s, 会在选定的位置上生成一个和源文件大小相同的文件,无论是软链接还是硬链接,文件都保持同步变化。

2.通过实验加深理解
[oracle@Linux]$ vi      test.log
#创建一个测试文件f1
[oracle@Linux]$ ln   test.log    test1.log
#创建f1的一个硬连接文件test1.log
[oracle@Linux]$ ln  -s   test.log   test2.log
#创建f1的一个符号连接文件test2.log
[oracle@Linux]$ ls   -li
# -i参数显示文件的inode节点信息

软连接和硬链接区别

1.软连接有个主体,删除其他一个不会影响,其余的连接,但是删除主体(源文件),所有文件都失效变红
2.硬链接主次不分,只要生成以后,删除谁都不影响。
如:

gec@ubuntu:~$ ls -l
lrwxrwxrwx 1 root root    15 Jan 16 2020 libbsd.so.0 -> libbsd.so.0.8.7

动态库的制作
不管是静态库还是动态库,都是用来被其他程序链接的一个个功能模块。与静态库一致,制作动态库的步骤如下:

将 *.c 编译生成 *.o
将 *.o 编译成动态库
例如:
gec@ubuntu:~$ ls
a.c b.c
# 第一步:将源码编译为 *.o
gec@ubuntu:~$ gcc a.c -o a.o -c -fPIC
gec@ubuntu:~$ gcc b.c -o b.o -c -fPIC
gec@ubuntu:~$ ls
a.c b.c a.o b.o
# 第二步:将 *.o 编译为动态库
gec@ubuntu:~$ gcc -shared -fPIC -o libx.so a.o b.o
gec@ubuntu:~$ ls
a.c b.c a.o b.o libx.so
# 第三步:将连接库生成可执行文件
gec@ubuntu:~$ gcc main.c -o main -L./lib -lx

解释:当前目录lib文件夹下 -l库名 库被放在了/lib下
说明:
-L 选项后面跟着动态库所在的路径。
-l 选项后面跟着动态库的名称

如果程序运行时找不到动态库,运行就会失败,例如:

gec@ubuntu:~$ ./main

报错

出现上述错误的原因,就是因为运行程序 main 时,无法找到其所依赖的动态库 libx.so,解决这个问题,有三种办法:
编译时预告:

gec@ubuntu:~$ gcc main.c -o main -L. -lx -Wl,-rpath=/home/gec/lib

设置环境变量:

gec@ubuntu:~$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/gec/lib

修改系统默认库路径:(不推荐)

gec@ubuntu:~$ sudo vi /etc/ld.so.conf.d/libc.conf
gec@ubuntu:~$ sudo ldconfig

在以上文件中,添加动态库所在路径即可。 注意: 此处要小心编辑,一旦写错可能会导致系统无法启动,这是一种 污染 系统的做法,不推荐。
在gcc中,如果遇到动态库和静态库同名,则会默认优先进行动态链接,如果此时需要用静态链接,可以使用编译选项 -static 达到此目的

gec@ubuntu:~$ ls ./lib  # 假设有两个重名的静态、动态库
libx.a  libx.so
gec@ubuntu:~$
gec@ubuntu:~$ gcc main.c -o main1 -L./lib -lx
gec@ubuntu:~$ gcc main.c -o main2 -L./lib -lx -static
gec@ubuntu:~$ ls -l
total 868
drwxr-xr-x 2 gec gec   4096 1月   4 17:45 lib/
-rwxr-xr-x 1 gec gec   8288 1月   4 17:46 main1 # 默认动态链接
-rwxr-xr-x 1 gec gec 845120 1月   4 17:46 main2 # 指定静态链接
-rw-r--r-- 1 gec gec     56 1月   4 17:42 main.c
gec@ubuntu:~$

很明显可以看到,静态链接的文件尺寸要大得多。


【Linux静态库和动态库】相关推荐

  1. 关于Linux静态库和动态库的分析

    From: http://hi.baidu.com/bdccutysj/blog/item/5bae7f0202abac7c3912bb15.html 1.什么是库 在windows平台和linux平 ...

  2. linux 中如何将文件粘贴到usr下的lib内,学会在Linux下GCC生成和使用静态库和动态库...

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

  3. Linux中gcc的编译、静态库和动态库的制作

    欢迎大家关注笔者,你的关注是我持续更博的最大动力 Linux中gcc的编译.静态库.动态库 文章目录: 1 gcc的编译过程 1.1 gcc的编译过程 1.2 gcc的常用参数 2 gcc 静态库的制 ...

  4. Linux下的静态库、动态库和动态加载库

    from: http://www.techug.com/linux-static-lib-dynamic-lib 库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从L ...

  5. linux下的共享库(动态库)和静态库

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

  6. Linux基础——gcc编译、静态库与动态库(共享库)

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

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

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

  8. Linux 之三 静态库及动态库的编写和使用

      最近在整理旧电脑时,发现了一些刚入行时的学习记录,以及最早使用新浪博客 http://blog.sina.com.cn/zcshou 写的一些文章.最近要重拾 Linux,所以把这些 Word 文 ...

  9. Linux学习:静态库和动态库

    1.库是什么? 将"源代码"变为"二进制格式的源代码"(作用:加密,别人可以用,但不知道其中的内容). 2.库制作出来之后,如何给用户使用? 需要给用户:头文件 ...

  10. linux 动态库建立,浅析linux下静态库和动态库的建立和使用

    在粤嵌学了很多知识,我们把常用的公用函数放在一起做成一个函数库,可以供其他程序共同使用,函数库本质上说,是一个可执行代码的二进制形式,可被操作系统载入内存执行.linux下的库分为两种:静态库,后缀名 ...

最新文章

  1. XPath 详解,总结
  2. Jakarta Commons Logging学习笔记
  3. 关于域帐户将计算机加入域登陆上限问题
  4. 岳翔南京大学计算机,基于组合IIS路径抽取的组合线性混成系统有界可达性分析-中国科学.PDF...
  5. Educational Codeforces Round 114 (Rated for Div. 2) D. The Strongest Build 暴力 + bfs
  6. 规范化流程化提交自己代码到远程gitlab服务器
  7. scipy.sparse.csr_matrix函数和coo_matrix函数
  8. python docx 表格打印不显示_python-docx 设置 word 文档中表格格式
  9. 09年全年的case处理总量
  10. 【hdoj1021】类斐波那契数列的循环节(f[i]能否mod3?找规律)
  11. maven 手动安装 ojdbc7
  12. python tk隐藏窗口_显示tkinter消息框时,隐藏root窗口
  13. 时域采样与频域采样实验【matlab】
  14. 从windows向vmware中传输压缩包出现的压缩包异常的问题
  15. 欧拉公式求四面体的体积
  16. 用matlab产生chu序列和frank序列
  17. 详解如何在Sbo Add-on开发中使用Folder控件
  18. ImmunoChemistry艾美捷总细胞毒性试验试剂盒方案
  19. Android开门动画和关门动画的实现
  20. JVM-三色标记算法

热门文章

  1. 网络扫描技术揭秘学习笔记《二》NetBIOS/NrtBEUI协议编程
  2. xbox虚拟服务器,《微软模拟飞行》体积减半,主机版也快到来了
  3. iOS语音通话(语音对讲)
  4. 目标检测算法Fast R-CNN简介
  5. 小孩子上机器人课好还是编程课好
  6. Linux时间编程三大步骤
  7. UE4 蓝图设置怪物自动寻路
  8. jtitle=Reactions Weekly,2013MBA联考英语试卷(附答案) 2
  9. 昆明理工大学控制工程考研经验贴
  10. 当我谈过年时,我该谈些什么?