Linux使用静态库和动态库
2016-05-08 16:28
417 查看
Linux使用静态库和动态库
(一)库的概念
库是可以复用的代码,在一些大的项目中常常会用到库。本质上说:库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
一般说库是说两种:
静态库:linux下.a文件、windows下.lib文件
动态库:linux下.so文件、windows下.dll文件
最近花了一些时间把linux下编译、链接等研究了一下,作为一个菜鸟记录并分享一蛤。
(二)静态库与动态库
程序的编译运行要经过以下步骤:1.源文件(.h .cpp等)
2.预编译
3.编译
4.汇编(.o文件)
5.链接
6.运行
在上述过程中,静态库是在链接阶段,将汇编生成的目标文件.o与引用到的库一起打包到可执行文件中,此种链接方式被称为静态链接。静态库其实一组目标文件(.o/.obj)的集合,即很多目标文件经过压缩打包后形成的一个文件,有一个说法称为:Archive即归档合并到一起。静态库在链接过程中被一起打包到可执行文件中,因此程序在运行时与函数库再无瓜葛,移植起来就很方便,但也因为这个原因会浪费空间资源,因为所有相关的目标文件与牵涉到的函数库都会被链接成一个可执行文件,如果10个100个可执行文件使用同一个静态库,就会造成大大的浪费;并且由于静态库是需要链接进入应用程序的,因此一旦对静态库进行修改,就需要对整个程序重新编译。
与静态库不同,动态库不会被链接打包到目标代码中,而是在程序运行时才被载入。这样就解决了静态库浪费空间的缺点,动态库把对一些库函数的链接载入推迟到程序运行的时期,在内存中只存在一份拷贝,这样可以实现进程之间的资源共享。
在linux和windows下静态库和动态库的概念以及使用方法有所不同,之后会慢慢学习分享。
(三)Linux下使用静态库
首先知道一个概念,也就是.h头文件,静态库.a文件的关系:.h头文件是编译时必须的,声明函数接口,编译时通过引用.h文件找到函数声明。
.a文件是linux下静态库文件的后缀,通常以libxxxx.a的形式出现,在链接时必不可少。
下面编写一个简单的四则运算库:
首先是声明部分:
//StaticMath.h #pragma once class StaticMath { public: StaticMath(void); ~StaticMath(void); static double add(double a,double b); static double sub(double a,double b); static double mul(double a,double b); static double div(double a,double b); void print(); };
接着编写对应的.cpp文件实现上述接口声明:
//StaticMath.cpp #include "StaticMath.h" double StaticMath::add(double a,double b) { return a+b; }
由于静态库是目标文件的集合,那么我们现在需要对上述文件进行预编译->编译->汇编步骤,生成对应的.o文件,通过
g++ --help命令知道参数
-c的描述是:
因此执行命令:
g++ -c StaticMath.cpp
将代码文件编译汇编成目标文件StaticMath.o
然后,使用ar工具将目标文件打包成.a形式的静态库文件,这里的ar实际上可以理解为Archive的简写:
ar -crv libstaticmath.a StaticMath.o
如此生成静态库文件libstaticmath.a。
PS:在以前做过的嵌入式项目里面,静态库的生成和使用大多通过一些自动化工具例如autogen、cmake等,一直没有搞懂其真正的原理,这下也算学习了一蛤。
最后编写测试代码使用静态库
//test.cpp #include <iostream> #include "StaticMath.h" int main() { double a=1.2; double b=2.4; std::cout << "a+b="<<StaticMath::add(a,b)<<std::endl; return 0; }
因为在链接的过程中要使用静态库,这里编译的时候需要加入静态库所在目录和静态库的名字来作为编译选项,否则会出现问题:
g++ -o test test.cpp -L ./ -lstaticmath
最后可执行文件test正常执行:
(四)Linux下使用动态库
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。同样的首先编写库文件。
声明:
//DynamicMath.h #pragma once class DynamicMath { public: DynamicMath(); ~DynamicMath(); static double add(double a,double b); static double sub(double a,double b); static double mul(double a,double b); static double div(double a,double b); };
实现:
//DynamicMath.cpp #include "DynamicMath.h" double DynamicMath::add(double a,double b) { return a+b; }
生成动态库libxxxx.so
g++ DynamicMath.cpp -fPIC -shared -o libdynamicmath.so
-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。
-shared指定生成动态链接库。
使用动态库,测试代码:
//test.cpp #include <iostream> #include "DynamicMath.h" int main() { double a=1.2; double b=2.4; std::cout << "a+b =" << DynamicMath::add(a,b)<<std::endl; return 0; }
跟静态库使用类似,编译测试文件并加上合适的编译选项,生成可执行文件,并且通过
ldd命令查看应用程序依赖的动态库及其相关信息:
最后动态库的使用有一个需要注意的地方:
动态库是在运行时加载,这时候需要一个动态载入器(dynamic linker/loader),来得知动态库的绝对路径。
对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。
什么意思呢?就是首先有一堆配置文件可以配置动态载入库搜索动态库的路径,ld会在这些路径中去寻找依赖的动态库,这样就有两个解决办法:
1. 修改配置文件(/etc/ld.so.conf)添加我们创建的动态库的目录
2. 将我们创建的动态库(.so)拷贝到默认的动态库目录下/lib或者/usr/lib
关于上述第1点,我们可以这样做,在终端
添加动态库目录 echo /home/zhangxiao/learnlib/dynamiclib/ >> /etc/ld.so.conf 配置生效 ldconfig
关于上述第2点,直接将生成动态库拷贝到/usr/lib目录下即可。
参考:
http://www.cnblogs.com/skynet/p/3372855.htmlhttp://blog.csdn.net/yusiguyuan/article/details/12649737
相关文章推荐
- centos6.4 安装PXC5.6
- 在Linux环境下安装和配置phpmyadmin
- centos6.7、centos6.5下yum方式搭建lnmp环境,php5.4/mysql5.5
- CentOS 7的yum 安装mysql
- 6个关于dd命令备份Linux系统的例子
- Linux自动备份压缩MySQL数据库的实用方法
- CentOS6.5安装RHive
- linux epoll 简单demo
- Linux设备驱动(3)常用的宏、结构体、数据类型、函数等
- CentOS7安装小小输入法
- CentOS6.5安装RHBase
- 将centos 7改造为LINUX桌面系统
- linux非常实用的查找错误命令
- Linux根文件系统制作
- Linux mysql设置表名不区分大小写,设置编码
- Linux mysql设置表名不区分大小写,设置编码
- 2016年学习Linux决心书(老男孩教育在线课程班第二期)
- VirtualBox + CentOS 使用 NAT + Host-Only 方式联网
- 我的archlinux中安装的关于xfce4的软件
- Linux CentOS6系统环境安装VNC可视化