Linux下静态链接库与动态链接库的区别

引言

通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件
(object file)与牵涉到的函数库(library)被链接合成一个可执行文件
(executable file)。程序
在运行
时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库(static libaray),通常文件
名为“libxxx.a”的形式。



其实,我们也可以把对一些库函数的链接载入推迟到程序运行的时期(runtime)。这就是如雷贯耳的动态链接库(dynamic link library)技术。

一 例子详解

文件目录树如下:

1. libtest/

2. |-- myjob.c

3. |-- myjob.h

4. |-- test.c

静态库

A.做成静态库 
libmyjob.a

1. $ gcc  -c  myjob.c
 
 -o  myjob.o

2. $ ar  -c
-r
-s  libmyjob.a  myjob.o

B.链接

1. $ gcc  test.o  libmyjob.a  -o  test

C.引用库情况(无所要信息)

1. $ ldd test

2. linux-gate.so.1 => (0xffffe000)

3. libc.so.6 => /lib/libc.so.6 (0xb7e29000)

4. /lib/ld-linux.so.2 (0xb7f6e000)

动态库

A.做成动态库 
libmyjob.so

1. $ gcc  -Wall –fPIC
 
 -c  myjob.c 
 
-o  myjob.o

2. $ gcc -shared -o libmyjob.so myjob.o

-shared: 
该选项指定生成动态连接库(让连接器生成T
类型的导出符号表,有时候也生成弱连接
W
类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。

-fPIC:

表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

-L.:

表示要连接的库在当前目录中。

LD_LIBRARY_PATH:

这个环境变量指示动态连接器可以装载动态库的路径。

B.链接

链接方法I
,拷贝到系统库里再链接,让
gcc
自己查找:

1. $ cp libmyjob.so /usr/lib

2. $ gcc -o test test.o -lmyjob

这里我们可以看到了 -lmyjob 
选项,
-l[lib_name] 
指定库名,他会主动搜索。
lib[lib_name].so
这个搜索的路径可以通过 
gcc --print-search-dirs
来查找。

链接方法II
,手动指定库路径

1. $ 
gcc -o test test.o -lmyjob -B /path/to/lib

-B
 选项就添加 /path/to/lib 

gcc
搜索的路径之中。这样链接没有问题但是方法
II
中手动链接好的程序在

执行
时候仍旧需要指定库路径(
链接和执行是分开的
)。需要添加系统变量 LD_LIBRARY_PATH :

1. $ export LD_LIBRARY_PATH=/path/to/lib

这个时候再来检测一下test
程序的库链接状况
(
方法
I
情况
)

1. $ ldd test

2. linux-gate.so.1 => (0xffffe000)

3. libmyjob.so => /usr/lib/
libmyjob
.so (0xb7f58000)

4. libc.so.6 => /lib/libc.so.6 (0xb7e28000)

5. /lib/ld-linux.so.2 (0xb7f6f000)

是不是比静态链接的程序多了一个 libmyjob.so? 
这就是静态与动态的最大区别,静态情况下,它把库直接加载到程序里,而在动态链接的时候,它只是保留接口,将动态库与程序代码独立。这样就可以提高代码的可复用度,和降低程序的耦合度。

另外,运行时,要保证主程序能找到动态库,所以动态库一般发布到系统目录中,要么就在跟主程序相对很固定的路径里,这样不管主程序在本机何时何地跑,都能找得到动态库。而静态库只作用于链接时,运行主程序时静态库文件没存在意义了。

二 静态库和动态库的区别

1. 静态函数库

这类库的名字一般是
libxxx.a
;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为
如果静态函数库改变了,那么你的程序必须重新编译

2. 动态函数库

这类库的名字一般是
libxxx.so
;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。

动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。

linux静态函数库的创建和使用

A.
例程
str_out.h str_out.c main.c

/* str_out.h */

#ifndef STR_OUT_H

#define STR_OUT_H

void str_out(const char* str);

#endif

/* str_out.c */

#include "str_out.h"

void str_out(const char* str)

{

printf("%s
/
n",str);

}

/* main.c */

int main()

{

str_out("myjob world");

return 0;

}

(第一步
)

gcc -c str_out.c 
-
o
 str_out.o

B.静态函数库由
ar
命令创建

(第二步
)

ar crs libstr_out.a str_out.o

-c : create
的意思

-r :replace
的意思,表示当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar
显示一个错误消息,并不替换其他同名模块。

-s:
代表若归档文件中包含了对象模式(C++)

C.
使用方法

(第三步
)

gcc  main.c -o out -L. -lstr_out

通过gcc -o out main.c -L. -lstr_out
编译
main.c
就会把静态函数库整合进
out

-L:
指定静态函数库的位置供查找,注意L
后面还有
'.'
,表示静态函数库在本目录下查找。

-l:
则指定了静态函数库名,由于静态函数库的命名方式是lib***.a
,其中的
lib

.a
忽略。

根据静态函数库的特性,此处删除libstr_out.a

out
依然可以运行,因为静态库的内容已经整合进去了。

动态函数库的创建和使用

A.
创建动态库

(
第一步
)
gcc -fPIC -Wall -c str_out.c 

o str_out.o

(第二步
)

gcc -shared -Wl, -soname,libstr_out.so.1 -o libstr_out.so str_out.o

该命令生成libstr_out.so 
动态函数库。

-shared:

指定生成动态链接库。

-static:

指定生成静态链接库。

-fPIC:

表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。

-L.:

表示要连接的库在当前目录中。

-l:

指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib
,后面加上
.so
来确定库的名称。

-Wl,options:

把参数(options)
传递给链接器
ld
。如果
options
中间有逗号
,
就将
options
分成多个选项
,
然后传递给链接程序。

B.动态库的使用

这时还不能立即./out
,因为在动态函数库使用时,会查找
/usr/lib/lib
目录下的动态函数库,而此时我们生成的库不在里边。

1.最简单的方法就是把
libstr_out.so
拉到
/usr/lib

/lib
中去。

(第三步
)

gcc main.c -o main -lstr_out

2. export LD_LIBRARY_PATH=$(pwd)

(第三步
)

gcc  main.c - o  main  
-L.  
-lstr_out

3.在
bashrc

profile
文件里用
LD_LIBRARY_PATH
定义,然后用
source
加载。

4.还可以在
/etc/ld.so.conf
文件里加入我们生成的库的目录,然后
/sbin/ldconfig

/etc/ld.so.conf是非常重要的一个目录,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从
/usr/lib  /lib
中读取的

,为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig.此执行程序存放在/sbin目录下.ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为
/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.

另外还有个文件需要了解/etc/ld.so.cache,
里面保存了常用的动态函数库,且会先把他们加载到内存中,因为内存的访问速度远远大于硬盘的访问速度,这样可以提高软件加载动态函数库的速度了。

  注意:默认情况下使用-l选项将搜索动态链接库(.so),没有对应.so文件时将使用.a文件进行静态编译。

linux动态链接库和静态链接库的更多相关文章

  1. Linux 动态链接库包含静态链接库的方法

    今天老司机们在讨论一个编译问题  A是一个静态库  C是一个动态库  B是运行程序,能不能将A打包到C 然后B只需要链接C 就可以了. 这个问题我以前在出来zlib库版本冲突的时候有点印象,所以写了个 ...

  2. Linux下动态链接库和静态链接库

    第一部分:编译过程 先了解一下linux下C代码的编译过程,C代码的编译,一般分成四个阶段,包括:预编译,编译,汇编和链接,这四个阶段的分工是 预处理过程,负责头文件展开,宏替换,条件编译的选择,删除 ...

  3. [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结

    来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...

  4. Qt 共享库(动态链接库)和静态链接库的创建及调用

    前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...

  5. GCC 编译使用动态链接库和静态链接库

    1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...

  6. 【转】gcc 编译使用动态链接库和静态链接库

    1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...

  7. GCC编译过程与动态链接库和静态链接库

    1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...

  8. C# - *.dll vs *.lib (动态链接库 vs 静态链接库)

    静态库 库(Library)就是一段编译好的二进制代码,加上头文件就可以使用. 静态链接库(Windows 下的*.lib, Linux & Mac 下的 .a).之所以叫做静态,是因为静态库 ...

  9. 利用GCC编译器生成动态链接库和静态链接库

    转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...

随机推荐

  1. .NET WebSockets 核心原理初体验

    上个月我写了<.NET gRPC核心功能初体验>, 里面使用gRPC双向流做了一个打乒乓球的Demo, 实时双向这两个标签是不是很熟悉,对, WebSockets也可以做实时双向通信. 本 ...

  2. Mysql 添加 create_time, update_time 创建时间 更新时间 自动更新

    # 添加 创建 更新 时间字段 ALTER TABLE `表名` ADD COLUMN `create_time`  datetime NOT NULL DEFAULT CURRENT_TIMESTA ...

  3. ASP.NET Core扩展库之Http请求模拟

    如今,完全独立的业务应用几乎不存在,不管是在企业内部微服务之间的调用,还是与外部第三方服务的调用,Http的API交互是常见的场景,这些实际情况给我们的开发带来了比较大的挑战,一是第三方服务可能会牵制 ...

  4. SpringBoot的旅游项目——day01(学习记录附赠源码)

    前言 学完SpringBoot的项目,Github地址,欢迎start,一起学习! 第一天 一.技术选型 基于SpringBoot+VUE的前后端分离的仿照马蜂窝的项目. 后端选用的技术为: Spri ...

  5. 漫画 | 公司测试因提Bug不规范,锒铛入狱~

    互联网人罪状系列 1.上班第一天,前端把后端告上县衙,还列了 5 宗罪 2. 程序员状告产品经理八大罪状 (上) 3.程序员状告产品经理八大罪状(下) 开发人员与测试人员的关系,就如同程序员与产品经理 ...

  6. 1.4.19- HTML标签之注释标签

    有的时候我们输入的代码,让你别人看,别人不知道你的思路,可能就看不懂,或者或一段时间自己就看不懂了,这个时候我们需要对代码进行注释,解释我们的代码什么意思: <!DOCTYPE html> ...

  7. Spring Security极简入门三部曲(中篇)

    目录 Spring Security极简入门三部曲(中篇) 验证流程 Authentication接口 过滤器链 AuthenticationProvider接口: demo时刻 代码讲解 小结 Sp ...

  8. hdu4415 不错的想法题

    题意: 一个人他有一定的血,有一些怪物,他去杀怪物,有的怪物杀死他后还可以在不费自己血的情况下任意杀死一些怪物,问你他最多杀死多少怪物,在最多杀怪前提下最好用多少血,(大体题意是这样). 思路: 首先 ...

  9. Linux提权

    讲Linux提权之前,我们先看看与Linux有关的一些知识: 我们常说的Linux系统,指的是Linux内核与各种常用软件的集合产品,全球大约有数百款的Linux系统版本,每个系统版本都有自己的特性和 ...

  10. Win64 驱动内核编程-34.对抗与枚举MiniFilter

    对抗与枚举MiniFilter MiniFilter 是目前杀毒软件用来实现"文件系统自我保护"和"文件实时监控"的方法. 由于 MiniFilter 模型简单 ...