linux下有两种库:动态库和静态库(共享库)

二者的不同点在于代码被载入的时刻不同。

静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。

动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。

不同的应用程序如果调用相同的库,那么在内存中只需要有一份该动态库(共享库)的实例。

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

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在

一  静态库

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

静态库的代码在编译时链接到应用程序中,因此编译时库文件必须存在,并且需要通过“-L”参数传递给编译器,应用程序在开始执行时,库函数代码将随程序一起调入进程内存段直到进程结束,其执行过程不需要原静态库存在。

在UNIX中,使用ar命令创建或者操作静态库

ar     archivefile objfile

archivefile:archivefile是静态库的名称

objfile:objfile是已.o为扩展名的中间目标文件名,可以多个并列

参数        意义

-r            将objfile文件插入静态库尾或者替换静态库中同名文件

-x            从静态库文件中抽取文件objfile

-t             打印静态库的成员文件列表

-d            从静态库中删除文件objfile

-s           重置静态库文件索引

-v            创建文件冗余信息

-c            创建静态库文件

example:

/****************** hello.h **************/void hello(void);
/****************** hello.cpp **************/#include<iostream>
#include"hello.h"
using namespace std;
void hello(void)
{cout <<"Hello "<<endl;
}
/****************** main.cpp **************/#include"hello.h"int main(int argc,char *argv[])
{hello();return 0;
}

1.编译成静态库

无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。

hc@linux-v07j:~/weiming/tt> g++ -o hello.o -c hello.cpp

hc@linux-v07j:~/weiming/tt> ar cqs libHello.a hello.o

hc@linux-v07j:~/weiming/tt> ls
hello.cpp  hello.h  hello.o  libHello.a  main.cpp

2.链接

hc@linux-v07j:~/weiming/tt> g++ main.cpp libHello.a -o Out1  (g++ -o aOut main.cpp ./libHello.a 或者 g++ -o aOut main.cpp  -L./ -lHello)

hc@linux-v07j:~/weiming/tt> ls
hello.cpp  hello.h  hello.o  libHello.a  main.cpp  Out1

hc@linux-v07j:~/weiming/tt> ldd Out1
        linux-gate.so.1 =>  (0xffffe000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e36000)
        libm.so.6 => /lib/libm.so.6 (0xb7e11000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7e06000)
        libc.so.6 => /lib/libc.so.6 (0xb7ce3000)
        /lib/ld-linux.so.2 (0xb7f1b000)

二: 动态库

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

不同的UNIX系统,链接动态库方法,实现细节不一样

编译PIC型.o中间文件的方法一般是采用C语言编译器的-KPIC或者-fpic选项,有的UNIX版本C语言编译器默认带上了PIC标准.创建最终动态库的方法一般采用C语言编译器的-G或者-shared选项,或者直接使用工具ld创建。

最主要的是GCC命令行的一个选项:
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-L.:表示要连接的库在当前目录中
-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
 当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。

这里分别将源文件d1.c和d2.c编译为动态库d1.so和d2.so.

/************ d1.h***************/
void print();
/***************  d1.cpp *******************/#include <iostream>
#include "d1.h"
using namespace std
int p = 1;
void print(){cout<< p <<endl;}
/************ d2.h***************/
void print();
/***************  d2.cpp *******************/
#include <iostream>
#include "d2.h"
using namespace std;int p = 2;
void print()
{cout<< p <<endl;
}

LINUX和其他gcc编译器

g++ -fpic -c d1.cpp d2.cpp     /* 编译为.o为扩展名的中间目标文件d1.o,d2.o*/

g++ -shared -o libd1.so d1.o    /*根据中间目标文件d1.o创建动态库文件d1.so*/

g++ -shared -o libd2.so d2.o    /*根据中间目标文件d2.o创建动态库文件d2.so*/

或者直接一步到位

g++ -O -fpic -shared -o libd1.so d1.cpp

g++ -O -fpic -shared -o libd2.so d2.cpp

某些版本的gcc上也可以使用-G替换-shared选项

调用动态库

隐身调用动态库

/**************  main.cpp *********************/void print(); //或者用#include"d1.h"(#include"d2.h")替换
int main(int argc,char *argv[])
{print();
}

#cp ./libd1.so libd.so (cp ./libd2.so libd.so )

# g++ -o dOut main.cpp ./libd.so (或者g++ -o dOut main.cpp -L./ -ld)

hc@linux-v07j:~/weiming/tt/dd> ldd dOut
        linux-gate.so.1 =>  (0xffffe000)
        libd.so => ./libd.so (0xb7f0f000)  //这个动态库文件比静态编译多的
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e2b000)
        libm.so.6 => /lib/libm.so.6 (0xb7e06000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7dfa000)
        libc.so.6 => /lib/libc.so.6 (0xb7cd8000)
        /lib/ld-linux.so.2 (0xb7f12000)

在上例中,动态库libd.so与执行程序在同一目录下,如果将libd.so移走再执行程序,程序将不能正常执行。

当需要载入动态库代码时,UNIX会按照某种路径查找动态库

通知UNIX系统动态库的正确位置有如下两种方法.,

1)带编译路径

#g++ -o dOut main.cpp ./libd.so (或者g++ -o dOut main.cpp -L./ -ld)

当执行程序时,程序会自动在当前路径下操作动态库libd.so

2)更改环境变量

#LD_LIBPARY_PATH=./

#export LD_LIBPARY_PATH

不同的UNIX所依赖的动态库查找路径环境变量名称各不相同

UNIX版本              动态库查找路径环境变量

AIX                 LIB_PATH

LINUX           LD_LIBPARY_PATH

HP_UNIX      PAHT

SCO UNIX     LD_LIBPARY_PAHT

动态链接库取代静态库的好处之一就是可以随时升级库的内容。

当动态库被接口完全相同的库文件取代后,可执行程序能迅速的切换到新动态库中代码,省去了编译的麻烦。

例如将libd2.so换成libd.so

显示调用动态库

显示调用动态库,编译时无需库文件,执行时动态可存储于任意位置,库里共享对象必须先申请后使用,不同动态库版本,只要其共享对象接口相同,就可以直接动态加载。

//打开动态库
#include<dlfcn.h>
void *dlopen(const char * pathname,int mode);//获取动态库对象地址
include<dlfcn.h>
void *dlsym(void *handle,const char *name);//错误检测
include<dlfcn.h>
char *dlerror(vid);//关闭动态库
include<dlfcn.h>
int dlclose(void * handle);

动态库的加载或多或少会占用一定的系统资源,比如内存等。因此当不需要或者一段时间内不需要共享动态库时就要卸载之。函数dlclose关闭参数handle所指向的动态库,卸载其所占的内存等资源,此调用后参数handle无效。

实际上,由于动态库可能同时被多个进程共享,当一个进程指向dlclose时,资源并不马上被卸载,只有当全部进程都宣布关闭动态库后,操作系统才开始回收动态库资源。

总结:

编译静态库时先使用-c选项,再利用ar工具产生.编译动态库的方式依不同版本的UNXI而定。隐式调用动态库与静态库的用法相一致,而显示调用动态库则需要借助动态加载共享库函数族。

隐式调用动态库和静态库使用方法一致,使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?

通过测试可以发现,当静态库和动态库同名时, gcc命令将优先使用动态库.为了确保使用的是静态库, 编译时可以加上 -static  选项,因此多第三方程序为了确保在没有相应动态库时运行正常,喜欢在编译最后应用程序时加入-static

Linux下动态库(.so)和静态库(.a)相关推荐

  1. PHP编译为静态库,Linux下将Tinyxml编译为静态库

    转载请注明来源:Linux下将Tinyxml编译为静态库 一个应用需要在linux服务器上运行,不能保证每个服务器都有应用依赖的库,又懒得每个服务器都去安装下,也不太现实,于是就将应用所用到的库全部编 ...

  2. linux 中如何将文件粘贴到usr下的lib内,学会在Linux下GCC生成和使用静态库和动态库...

    一.基本概念1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主 ...

  3. Linux下Gcc生成和使用静态库和动态库详解

    参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...

  4. Linux下GCC生成和使用静态库和动态库详解(二)

    2.1准备好测试代码hello.h.hello.c和main.c: hello.h(见程序1)为该函数库的头文件. hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏 ...

  5. Linux下Gcc生成和使用静态库和动态库详解(转)

    一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...

  6. [转]Linux下g++编译与使用静态库(.a)和动态库(.os) (+修正与解释)

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库 ...

  7. g++ 编译mysql动态库_Linux下g++编译以及使用静态库和动态库的方法详解

    下面小编就为大家带来一篇Linux下g++编译与使用静态库和动态库的方法.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 在windows环境下,我们通常在IDE如VS的 ...

  8. PHP编译为静态库,makefile生成静态库和动态库

    库是一种软件组件技术,库里面封装了数据和函数. 库的使用可以使程序模块化. Windows系统包括静态链接库(.lib文件)和动态链接库(.dll文件). Linux通常把库文件存放在/usr/lib ...

  9. gcc g++ Linux下动态库_静态库

    关于Unix静态库和动态库的分析 基本概念 库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀. 例如:libhello.so libhello.a 为了在同一系统中使用不同版本的库,可以在 ...

最新文章

  1. WP7多国语言支持 from:http://blog.csdn.net/lee353086/article/details/6260676
  2. 不可不读的绝对英文经典
  3. mysql 查询空字符串 设置默认值_MySQL默认值选型是空,还是 NULL-爱可生
  4. centos 7.0防火墙导致vagrant端口映射失败
  5. 路由重发分之RIP-OSPF
  6. WordPress 安装插件导致 HTTP 500 内部服务器错误的问题
  7. 动辄几个亿的东半球最强饭局:大佬们都吃了啥?
  8. android客户端日志,更新日志 - BugHD Android 客户端上线
  9. 清明,我怀念那个回不去的故乡了
  10. farcry5服务器不稳定,孤岛惊魂5玩起来很卡怎么办 远哭5游戏卡顿解决办法
  11. 配置计算机能不能关机,详细教你电脑自动关机怎么设置
  12. 为什么我坚定看好分布式存储
  13. 《数学史概论》读后感
  14. 一个3D摄像机的设计与实现
  15. 服装行业如何用手持PDA盘点?
  16. java邮件发送代码_用java代码发送邮件(优化版)
  17. 以 VS Code为例,看大型开源项目是如何应用软件工程的?
  18. nRF52832不使用外部32.768K晶振,使用内部晶振
  19. 2021011206贾天乐实验五
  20. Could not initialize class ru.yandex.clickhouse.ClickHouseUtil

热门文章

  1. mysql my.cnf 配置_MySQL——my.cnf参数设置说明
  2. OpenCV中直方图的计算和绘制
  3. pytorch分布式训练(一):torch.nn.DataParallel
  4. 数据库 | OMIM (在线人类孟德尔遗传)数据库简介
  5. STAR直接就可以输出readsCount,为什么还需要featurecounts?
  6. 机器学习算法-随机森林之决策树R 代码从头暴力实现(3)
  7. 癌症精准医疗上市公司泛生子基因 - 内推(名额有限)
  8. 信息学奥赛一本通 1080:余数相同问题 2022.1.29 AC
  9. TypeError: __init__() got an unexpected keyword argument ‘任意数‘的原因及解决办法
  10. python线程通信 消息传递_Python并发编程之线程消息通信机制/任务协调(四)