linux中C的静态库和动态库分析
从开始学C语言写第一个"hello world"历程到现在,我依然困惑于到底这个程序完整的执行流程是什么样的。不过,现在我正在尝试一点一点的揭开它的面纱。现在,我尝试分析linux中C语言静态库和动态库生成和调用的方法,这可以算作实现最终愿望的一小步。
首先说明的是,本文参考于linux 静态库、共享库,这篇文章写的的确不错。笔者结合自己的学习过程,稍作修改。
一、什么是库
本质上说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux本质的不同,因此二者的二进制库是不兼容的。linux操作系统支持的函数库可分为静态库和动态库,动态库又称为共享库。linux系统有几个重要的目录存放着相应的函数库,如/lib、/usr/lib。
二、静态库和动态库
A.静态库
这类库的名字一般是libxxx.a,利用静态库编译生成的可执行文件比较大,因为整个函数库的所有数据都被整合进了可执行文件中。
它的优点就是程序执行时不需要外部的函数库支持,它的装载速度要比动态库快。它的缺点因为它的优点而产生,静态库升级后,那么你的程序就必须重新编译。当多个应用程序都用到相同的库中,执行这些程序时,会把静态库重复调入内存,而造成内存的浪费。
B.动态库
这类库的名字一般是libxxx.so,动态库又称共享库。相对于静态函数库,动态函数库在编译的时候没有被编译进可执行文件中,所以动态函数看所生成的可执行文件比较小。程序执行过程中,需要动态申请并调用相应的库才能运行,所以程序的运行环境中必须提供相应的库。
它的优点是多个应用程序可以使用一个共享的动态库,启动多个应用程序的时候,只需要动态库加载到内存一次即可,自然比较节省内存。它的缺点是启动加载时候速度比较慢。
三、函数库的创建
实验的所有文件及内容如下:
add.c
#include "heads.h"
int add(int a,int b)
{
return a+b;
} sub.c
#include "heads.h"
int sub(int a,int b)
{
return a-b;
} heads.h
#ifndef _HEADS_H_
#define _HEADS_H_
extern int add(int,int);
extern int sub(int,int);
#endif test.c
#include <stdio.h>
#include "heads.h"
int main()
{
int a=5,b=6;
printf("a+b=%d\n",add(a,b));
printf("a-b=%d\n",sub(a,b));
return 0;
}
注意:不管是静态库还是动态库,原材料都是目标文件(*.o),所以先将源文件做成目标文件。
A.静态库的创建
ar -cr libaddsub.a add.o sub.o
ar 静态函数库创建命令
-c 不管库是否存在,都将创建
-r 在库中插入模块
B.动态库的创建
gcc -shared -pic -o libaddsub.so add.o sub.o
-shared 生成共享库
-pic 产生位置无关代码
四、函数库的使用
A.静态库的使用
gcc test.c -static -L. -laddsub -o test1
static 使用静态库连接
-llibrary 用lib和.a把library包裹起来,并且在系统的标准搜索目录和L指定的目录中搜素该库文件
-Ldir 在l选项搜素目录中添加dir目录
可以看到程序编译通过并可以执行
当删除了静态库文件libaddsub.a,发现程序依然能够执行,也就是说使用静态库连接生成的程序执行时不依赖于静态库
B.动态库的使用
gcc test.c -L. -laddsub -o test2
通过这个命令可以看见仅仅是去掉了static选项。这种情况,gcc优选选择连接动态库,当没有合适动态库的动态库连接时才连接静态库。下边的实验做之前,在/work目录下已经生成了动态库libaddsub.so。
可以看到生成的test2明显比test1小很多,即证明了动态库连接可以使可执行文件比较小
但是,直接运行却提示找不到库,这是因为动态库libaddsub.so所在目录/work并没有添加到执行时搜索动态库的目录中去。
五、动态库的运行
(1) 第一种解决的办法是使用环境变量LD_LIBRARY_PATH,这个环境变量就可以指定执行时搜索动态库的目录,这里把/work目录添加进去。
(2)把动态库libaddsub.so拷贝到/lib或者/usr/lib中去,这种办法将在第七部分实验
(3)修改配置文件
#cd /etc/ld.so.conf.d 进入配置文件夹
#vi mylib.conf 建立一个配置文件*.conf,这里以mylib.conf为例,并添加动态库所在目录,这里是/work
#ldconfig 使配置生效,实际上是更新ld.so.cache文件
实验过程及结果如下:
再查看test2所有依赖的动态库
可以看到,test2依赖的动态库有三个,包含libaddsub.o和两个系统标准的动态库。可执行文件test2的大小为12037Bytes。
当删除动态库libaddsub.so后,再来运行test2,不能执行,说明动态库在运行过程中还需要动态库libaddsub.so。
六、查看库
nm 可以打印出动态库或者静态库中涉及到的所有符号
ldd 可以查看一个可执行程序依赖的共享库
七、连接和运行选项
A.将静态库libaddsub.a移动到系统标准库目录中测试编译
编译可以通过,执行也可以通过,说明系统标准库目录中的静态库可以被连接。另外,注意这时的test1大小是423629Bytes
将static去掉重现编译,发现test1大小变成了11817Bytes,莫非此时libaddsub.a是被动态连接上的?
但是,将libaddsub.a删除之后,重新运行test1,仍然可以执行,可以得知libaddsub.a是被静态连接的。查看,test1的构造,可以看到它依赖于两个标准动态库。说明,没有static连接器选项时,默认找的是动态库,但是没有动态库时就连接静态库。
test1中libaddsub.a是被动态连接,而另外两个标准库是被动态连接的。
B.用类似的方法分析动态库
可以看到系统标准库目录中的动态库可以被连接,而且在执行时可以被搜索到。
从第五部分可以知道,使用环境变量LD_LIBRARY_PATH可以指定执行时搜索动态库的目录,那么它是否能指定连接器的搜索目录呢?
从上边的实验,可以看出环境变量LD_LIBRARY_PATH不能指定连接器的搜索目录。
参考博客:linux 静态库、共享库
Linux 共享库: LD_LIBRARY_PATH 与ld.so.conf
linux中C的静态库和动态库分析的更多相关文章
- 在Linux中创建静态库和动态库
我们通常把一些公用函数制作成函数库,供其它程序使用. 函数库分为静态库和动态库两种. 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库. 动态库在程序编译时并不会被连接到目标代码中 ...
- Linux学习笔记7——linux中的静态库和动态库
一.静态库的编译 静态库的编译过程如下: 1.编译成目标文件 这里有一个可选项-static,调用格式:gcc -c -static 代码文件名.c 2.归档成静态库 A.归档的工具是ar工具,使用a ...
- 在Linux中创建静态库和动态库 (转)
我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种.静态 库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而 ...
- Linux中的静态库与动态库
什么是库文件? 库文件是事先编译好的方法的合集.比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写. Linux系统中: 1.静态库的扩展名为.a:2. ...
- linux中创建静态库和动态库
1. 函数库有两种:静态库和动态库. 静态库在程序编译的时候会被连接到目标代码中,程序运行时将不再需要改静态库. 动态库中程序编译的时候并不会连接到目标代码中,而是在程序运行时才被载入,因此在程序运行 ...
- Linux下Gcc生成和使用静态库和动态库详解(转)
一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...
- 在Linux下如何使用GCC编译程序、简单生成 静态库及动态库
最近在编写的一个Apache kafka 的C/C++客户端,,在看他写的 example中,他的编译是用librdkafka++.a和librdkafka.a 静态库编译的,,,而我们这 ...
- Linux下Gcc生成和使用静态库和动态库详解
参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...
- C语言中静态库和动态库笔记
库 库,故名思议,是存放东西的地方,其中存放的东西可以被多个人公用. 程序中借用库的概念,描述将代码进行抽取,这种代码被大多数程序使用, 其过程具有一定的模块化.封装.抽象的特征. 按照库的使用方式, ...
随机推荐
- java07 map
map底层,数组加链表 集合: 是一个对象,只不过这个对象可以容纳别的对象.存放对象就是操作地址. List:是有序可重复的. Set:无顺序,不可重复,有重复则后面把前面的覆盖. Map:键值对. ...
- cocos js响应过程
使用ccbi: js加载ccbi时候,会调用CCBReader的函数readNodeGraphFromData,从根节点递归解析子节点,使用readNodeGraph函数解析单个节点. 当碰到CCMe ...
- 高质量CSS编写规范
①id和class的命名在保持语义性的同时尽可能的短.不推荐的写法:#navigation {} .atr {}推荐的写法 : #nav {} .author {}可以缩写单词,但缩写后务必能让人明 ...
- Nginx/LVS/HAProxy负载均衡软件的优缺点详解(转)
PS:Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件,本人都在多个项目中实施过,参考了一些资料,结合自己的一些使用经验,总结一下. 一般对负载均衡的使用是随着网站规模的提升根据不 ...
- .Net设计模式_工厂模式(2)
2.工厂方法模式 引言: 上一篇中我们描述了简单工厂的缺点,而解决方法就是把工厂接口化,把工厂的行为标准化,这就是工厂方法模式. 理解: 工厂能制造A和B鞋,如果消费者现在要求制造C鞋.D鞋...咋办 ...
- Android 开发第四天
- HttpClient4.4 进行Http连接通讯
以前一直使用jdk自带的urlConnection来进行http通讯,HttpClient与之相比,HttpClient更具有灵活度和易用性.HttpClient能够方便使用连接池,使用时需要重新创建 ...
- 封装一个ISortable接口
using System;/// <summary>/// 排序规范/// </summary>/// <typeparam name="T"> ...
- Java输出日历
源码链接:http://pan.baidu.com/s/1o6xeybK
- dapper的一个小扩展以支持dataset
废话不多,直接上方法 public static DataSet ExecuteDataSet(this IDbConnection cnn, IDbDataAdapter adapter, stri ...