Linux之静态库与动态库20160706
所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。.so文件是共享库文件(动态链接)。动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息),仅当应用程序被装入内存开始运行时,在操作系统的管理下,才在应用程序与相应的.so之间建立链接关系。
.a文件是多个.o文件的组合。.o文件就是对象文件,里面包含的内容就是01这样的机器可执行的指令,当程序要执行时还需要进行链接(link).链接就是把多个.o文件链成一个可执行文件。
关于库生成的问题
我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
(1)静态库
简单地说,静态库是一个目标文件的简单集合。因此,首先要解决目标文件。
第一步:将各函数代码所在的源文件编译成目录文件。
例如,对于myfunc.c, myproc.c
gcc -c myfunc.c myproc.c
将得到myfunc.o和myproc.o。
第二步:由ar(archive,归档的意思)把多个目标文件集合起来。
$ar -r libmyjob.a myfunc.o myproc.o
通常,静态库的命名方式应遵守libXXXXX.a格式。应用程序在使用静态库的时候,通常只需要把命名中的XXXXX部分传递给gcc即可。例如:
$gcc –o mywork –lmyjob …
意为让gcc(实际上是gcc调用ld)去连接一个名字为libmyjob.a(或者libmyjob.so)的库。如果库的命名不遵循libXXXXX.a的格式就找不到相应文件。
例子:创建静态库
hello.h为该函数库的头文件。hello.c是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出"
hello XXX!"。main.c为测试库文件的主程序,在主程序中调用了公用函数hello。
程序1:
//hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif
程序2:
//hello.c
#include <stdio.h>
void hello(const char *name)
{
printf("hello %s! \n",name);
}
程序3:
//main.c
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
实现步骤:
第一步:必须将源程序hello.c通过gcc先编译成.o文件,生成hello.o(静态库/动态库,都是由.o文件创建的);
第二步:由.o文件创建静态库,生成libmyhello.a(静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a)创建静态库用ar命令;
第三步:在程序中使用静态库;(只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件)
第四步:删除静态库文件,程序照常运行,静态库中的公用函数hello已经连接到目标文件main中了。
运行:
[root@localhost moduletest]# ls
hello.c hello.h main.c
[root@localhost moduletest]# gcc -c hello.c
[root@localhost moduletest]# ls
hello.c hello.h hello.o main.c
[root@localhost moduletest]# ar crv libmyhello.a hello.o
a - hello.o
[root@localhost moduletest]# ls
hello.c hello.h hello.o libmyhello.a main.c
[root@localhost moduletest]# gcc main.c libmyhello.a -o main
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]# rm -f libmyhello.a
[root@localhost moduletest]# ls
hello.c hello.h hello.o main main.c
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]#
(2)共享库
共享库的构造复杂一些,通常是一个ELF格式的文件。可以有三种方法生成:
$ld -G
$gcc -shared
$libtool
用ld最复杂,用gcc -share就简单的多,但是-share并非在任何平台都可以使用。GNU提供了一个更好的工具libtool,专门用来在各种平台上生成各种库。
用gcc的-shared参数:
gcc –shared –o libmyjob.so myjob.o
这样,就通过myjob.o生成了共享库文件libmyjob.so。
特别地,在CYGWIN环境下,仍需要输出符合Windows命名的共享库(动态库),即libXXXXX.dll。如:
gcc –shared –o libmyjob.dll myjob.o
例子:创建动态库(延用上面的程序1,2,3)
实现步骤:
第五步:由.o文件创建动态库文件(命令:gcc -shared -fPCI -o libmyhello.so hello.o);
第六步:在程序中使用动态库;(在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示错误信息而终止程序运行。要将文件libmyhello.so复制到目录/usr/lib中)
运行:
[root@localhost moduletest]# ls
hello.c hello.h hello.o main.c
[root@localhost moduletest]# gcc -shared -fPIC -o libmyhello.so hello.o
[root@localhost moduletest]# ls
hello.c hello.h hello.o libmyhello.so main.c
[root@localhost moduletest]# gcc main.c libmyhello.so -o main
[root@localhost moduletest]# ls
hello.c hello.h hello.o libmyhello.so main main.c
[root@localhost moduletest]# ./main
./main: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory
[root@localhost moduletest]# mv libmyhello.so /usr/lib
可以:
[root@localhost moduletest]# ls
hello.c hello.h hello.o main main.c
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]#
或者:
[root@localhost moduletest]# rm -f main
[root@localhost moduletest]# ls
hello.c hello.h hello.o main.c
[root@localhost moduletest]# gcc -Wall -g main.c -lmyhello -o main
[root@localhost moduletest]# ls
hello.c hello.h hello.o main main.c
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]#
注意:
当静态库和动态库同名时, gcc命令将优先使用动态库。
(3)库生成以后的配置
如果要把自己开发的库文件安装到操作系统中,需要有管理员权限:
(a) 把库文件复制到适当的目录:
可以把自己开发的动态连接库放到/usr/local/lib(或者/usr/lib),或放到其他目录,但不论放在那里,都必须与LIBRARY_PATH的值、LD_LIBRARY_PATH的值相一致。
(b) 修改相关的系统配置文件:
修改/etc/ld.so.conf,然后利用/sbin/ldconfig来完成。
Note:
编译参数解析
最主要的是GCC命令行的一个选项:
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
l -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
l -L.:表示要连接的库在当前目录中
l -ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
l LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
l 当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。
调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。
Linux之静态库与动态库20160706的更多相关文章
- 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平台下都大量存在着库 ...
- [转]Linux下用gcc/g++生成静态库和动态库(Z)
Linux下用gcc/g++生成静态库和动态库(Z) 2012-07-24 16:45:10| 分类: linux | 标签:链接库 linux g++ gcc |举报|字号 订阅 ...
- Linux 静态库和动态库 使用说明
Linux下程序运行中,有两种库,静态库和动态库. 静态库:名字一般为libxxx.a,编译时会整合到可执行程序中,优点是运行时不需要外部函数库支持,缺点是编译后程序较大,一旦静态库改 ...
- 在Linux中创建静态库和动态库
我们通常把一些公用函数制作成函数库,供其它程序使用. 函数库分为静态库和动态库两种. 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库. 动态库在程序编译时并不会被连接到目标代码中 ...
- 详细讲解 关于Linux静态库和动态库的分析
基本概念 库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀. 例如:libhello.so libhello.a 为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: ...
- linux下的共享库(动态库)和静态库
1.什么是库在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于windows和linux的本质不同,因此二者库的二进制是不 ...
- linux中C的静态库和动态库分析
从开始学C语言写第一个"hello world"历程到现在,我依然困惑于到底这个程序完整的执行流程是什么样的.不过,现在我正在尝试一点一点的揭开它的面纱.现在,我尝试分析linux ...
随机推荐
- HDU-4055:Number String
链接:HDU-4055:Number String 题意:给你一个字符串s,s[i] = 'D'表示排列中a[i] > a[i+1],s[i] = 'I'表示排列中a[i] < a[i+1 ...
- 大O算法
大O计法:根据执行次数计算#sum = (1+n)*n/2://执行了一次,即为O(1)#for(i=0;i<n;i++);//执行了n次,即为O(n)#算法的时间复杂度:T(n) = O(f( ...
- JS对字符串编码的几种方式
函数 描述 encodeURI() 把字符串编码为 URI encodeURIComponent() 把字符串编码为 URI 组件 escape() 对字符串进行编码 上面是查询来自w3school的 ...
- 虹软2.0版本离线人脸识别C#类库分享
目前只封装了人脸检测部分的类库,供大家交流学习,肯定有问题,希望大家在阅读使用的时候及时反馈,谢谢!使用虹软技术开发完成 戳这里下载SDKgithub:https://github.com/dayAn ...
- 关于kv的jch分片存储
确定节点同步一致 节点启动之后,先获取本地的addrbook里面的节点信息 根据获取的addrbook里面的节点信息进行校验(向addrbook里面的节点发送hash消息确认,如果都一样,则可以广播数 ...
- 如何选择合适的Qt5版本?
注意:这里讨论的是在不编译Qt源码的情况下,推荐下载的官方编译版本. 支持XP SP3以及之后的Windows版本:推荐 Qt5.6 或 Qt5.9,这两个版本是LTS版本(即长期支持版本),Bug较 ...
- 由A到D中间可不止“B、C”
在电子信息系统的学习中,我们或许早就被告知现实世界是模拟的,而数字化的模拟世界则越来越展现更多的风采.但是所谓的数字和模拟只是相对的而已,你可以把模拟量当做无穷数字量的组合,也可以把数字量当做具有不同 ...
- 【Alpha】阶段第一次Scrum Meeting
[Alpha]阶段第一次Scrum Meeting 工作情况 团队成员 今日已完成任务 明日待完成任务 刘峻辰 后端接口开发 测试接口,修正bug 赵智源 撰写测试方案书 部署实际任务和编写测试样例 ...
- DS06--图
一.学习总结 1.图的思维导图 2.图学习体会 深度优先遍历与广度优先遍历 不同点:广度优先搜索,适用于所有情况下的搜索,但是深度优先搜索不一定能适用于所有情况下的搜索.因为由于一个有解的问题树可能含 ...
- Maven实现项目构建直接部署Web项目到Tomcat
Maven实现项目构建直接部署Web项目到Tomcat配置如下: 1.Tomcat的用户及权限配置:在conf目录下,找到tomcat-users.xml,添加manager权限的用户. <ro ...