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语言中静态库和动态库笔记
库 库,故名思议,是存放东西的地方,其中存放的东西可以被多个人公用. 程序中借用库的概念,描述将代码进行抽取,这种代码被大多数程序使用, 其过程具有一定的模块化.封装.抽象的特征. 按照库的使用方式, ...
随机推荐
- Installing the PHP/MongoDB extension on Mac OSX 10.8
Installing PHP/MongoDB extension is a two steps task on OSX: Install the autoconf tool required for ...
- Mac OS X 10.7下找不到~/Library/Application Support的解决方案
28二 最近有台机器升级到了Mac OS X 10.7,Finder的sidebar变了不说,连用户目录下的Library目录也不见了.但是Terminal中是有的,估计是被隐藏了.直接在Finder ...
- linux如何查进程、杀进程
本文系转载,转载原文地址:http://blog.sina.com.cn/s/blog_637112040100vl53.html 1.查进程 ps命令查找与进程相关的PID号: ps a 显 ...
- iOS之应用内跳转系统设置相关界面
在iOS开发中,有时会有跳转系统设置界面的需求,例如提示用户打开蓝牙或者WIFI,提醒用户打开推送或者位置权限等.在iOS6之后,第三方应用需要跳转系统设置界面,需要在URL type中添加一个pre ...
- (整理)FORM:Oracle EBS客制化Form的菜单栏用法说明
用户最多可以定义45个form-level的trigger,名称必须为SPECIALn, 其中SPECIAL1 to SPECIAL15属于Tools菜单项,放在“工具”主菜单下. SPECIAL16 ...
- Linux下如何在打开终端的时候自动配置相关环境
参考博客“Linux启动文件.设置环境变量的位置”(http://www.2cto.com/os/201305/208251.html) 在不可取的root权限的时候可以选择编辑~/.bashrc文件 ...
- Windows Thrift安装及HelloWorld
Thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(除了二进制,也支持json等常用序列化机制),官网地址:http://thrift.apache.org 跨 ...
- C++实现多线程类Thread
Windows编程中创建线程的常见函数有:CreateThread._beginthread._beginthreadex.据说在任何情况下_beginthreadex都是较好的选择. _begint ...
- Wireshark - 过滤规则
使用 Wireshark 的默认设置抓包时,会得到大量的冗余信息,以至于很难找到自己所需的封包.使用过滤器可以帮助我们在庞杂的结果中快速地找到我们所需的封包.过滤器分为两种:捕捉过滤器和显示过滤器. ...
- MVC中HtmlHelper用法大全参考
MVC中HtmlHelper用法大全参考 解析MVC中HtmlHelper控件7个大类中各个控件的主要使用方法(1) 2012-02-27 16:25 HtmlHelper类在命令System.Web ...