转自:http://blog.chinaunix.net/uid-26833883-id-3219335.html

一、什么是库

 
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux的本质不同,因此二者库的二进制是不兼容的。
 
Linux操作系统支持的函数库分为静态库和动态库,动态库又称共享库。Linux系统有几个重要的目录存放相应的函数库,如/lib    /usr/lib。
 
二、静态函数库、动态函数库
 
A.  这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进可执行文件了。当然这也会称为它的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译,而且体积也较大。
 
B.这类库德名字一般是libxxx.so,动态库又称共享库;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。而且如果多个应用程序都要使用同一函数库,动态库就非常适合,可以减少应用程序的体积。
 
注意:不管是静态函数库还是动态函数库,都是由*.o目标文件生成。
 
三、函数库的创建
 
A.静态函数库的创建
 
ar -cr  libname.a   test1.o  test2.o
 
ar:静态函数库创建的命令
-c :create的意思
-r :replace的意思,表示当前插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误信息,并不替换其他同名的模块。默认的情况下,新的成员增加在库德结尾处。
 
B.动态函数库的创建
 
gcc -shared  -fpic  -o libname.so  test1.c test2.c
 
-fpic:产生代码位置无关代码

-shared :生成共享库
 
四、静态库和动态库的使用 
 
案例:
 
add.c
 #include <stdio.h>

 int add(int a,int b)
{
return a + b;
}

sub.c

 #include <stdio.h>

 int sub(int a,int b)
{
return a - b;
}
 
head.h
 #ifndef  _HEAD_H_
#define _HEAD_H_ extern int add(int a,int b);
extern int sub(int a,int b); #endif
 
main.c
 #include <stdio.h>
#include <stdlib.h>
#include "head.h" int main(int argc,char *argv[])
{
int a,b; if(argc < )
{
fprintf(stderr,"Usage : %s argv[1] argv[2].\n",argv[]);
return -;
} a = atoi(argv[]);
b = atoi(argv[]); printf("a + b = %d\n",add(a,b));
printf("a - b = %d\n",sub(a,b)); return ;
}
生成静态库

生成动态库:

使用生成的生成的库:

其中
-L 指定函数库查找的位置,注意L后面还有'.',表示在当前目录下查找
-l则指定函数库名,其中的lib和.a(.so)省略。
 
注意:-L是指定查找位置,-l指定需要操作的库名。
 
从上面的运行结果中,我们可以看到:
 
A.当动态库和静态库同时存在的时候,gcc默认使用的是动态库。如果强制使用静态库则需要加-static选项支持。
B.动态库生成的可执行文件,test1不能正常的运行。
C.链接静态库的可执行程序明显比链接动态库的可执行文件大。
 
五、让链接动态库的可执行程序正常运行。
 
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路劲。此时就需要系统动态载入器(dynamic  linker/loader)。
 
对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的DT_RPATH段---环境变量LD_LIBRARY_PATH、/etc/ld.so.cache文件列表、/usr/lib、/lib目录找到库文件后将其载入内存。
 
A.一种最直接的方法,就是把生成的动态库拷贝到/usr/lib或/lib中去。

B.使用LD_LIBRARY_PATH环境变量,这个环境变量在ubuntu操作系统中默认没有,需要手动添加

C.动态在安装在其他目录下,如果想操作系统能找到它,可以通过一下步骤
 
<1>新建并编辑/etc/ld.so.conf.d/my.conf文件,加入库所在目录的路径
<2>执行ldconfig命令更新ld.so.cache文件

此时,在执行链接动态库的可执行文件则可以正常运行。
 
六、查看库中的符号
 
A.nm命令可以打印出库中涉及到的所有符号。库既可以是静态库也可以是动态的。
 
常见的三种符号:
<1>在库中被调用,但没有在库中定义(表明需要其他库支持),用U表示
<2>在库中定义的函数,用T表示
<3>“弱态”符号,他们虽然在库中被定义,但是可能被其他库中同名的符号覆盖,用W表示。

B.ldd命令可以查看一个可执行程序依赖的共享库

七、动态加载库
 
用gcc -shared生成的我们称为动态库(共享库),其中动态库在运行的过程中有两种方式
 
A.动态链接
 
这种方式下,可执行程序只是做一个动态的链接,当需要用到动态库中的函数时,有加载器隐士的加载。
 
B.动态加载
 
这种方式下,在可执行程序的内部,我们可以用dlopen()这样的函数,手动进行加载,dlsym()函数找到我们想要调用函数的入口地址,然后进行调用。这种方式,在写插件程序中得到广泛应用。
 
相关的API:

<1>dlopen()打开一个新的动态库,并把它装入内存。该函数主要用来记载库中的符号,这些符号在编译的时候是不知道的。
 
dlopen()函数需要两个参数:一个文件名和一个标志。
 
A.文件名是我们之前接触过的动态库的名字,如果它是一个绝对路径,如:/home/cyg/worddir/libname.so,此时dlopen直接到指定的路径下打开动态库。
如果没有指定路径,仅仅指定了一个动态库的名字,此时dlopen将它先后搜索elf文件的DT_RPATH段、环境变量LD_LIBRARY_PATH、/etc/ld.so.cache文件列表、/lib、/usr/lib目录找到库文件后将其载入内存。
 

B.标志指明是否立刻计算库的依赖性。

常常一个库中还依赖别的库,就是这个函数实现的时候,调用了别的库函数。不是在这个库中实现的函数我们称为位定义的符号。

 
如果将标志 设置为RTLD_NOW的话,则会在dlopen函数返回前,将这些未定义的符号解析出来。如果设置为RTLD_LAZY,则会在需要的时候才会去解析。
 
返回值:dlopen()函数会返回一个句柄作为dlsym()函数的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。
 
<2>dlerror()
 
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
 
<3>void *dlsym(void *handle,char *symbol);
 
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。
 
如程序代码 :int (*add)(int x,int y);//函数指针
 
handle = dlopen("xxx.so",RTLD_LAZY);//打开共享库
add = dlsym(handle,"add");//获取add函数在共享库的地址
value = add(12,34);//调用add函数
 
<4>int dlclose(void *handle);
dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
 
案例:
#include
#include
#include
#include
 
int test_dl(char *pso,char *pfu)
{
void *handle;
int (*ptest)(int x,int y);
 
if((handle = dlopen(pso,RTLD_LAZY)) == NULL)
{
printf("%s.\n",dlerror());
return -1;
}
 
if((ptest = dlsym(handle,pfu)) == NULL)
{
printf("%s.\n",dlerror());
return -1;
}
 
printf("ptest complete : %d.\n",ptest(12,13));
 
dlclose(handle);
 
return 0;
}
 
int main(int argc,char *argv[])
{
char buf[100];
char *pso,*pfun;
 
printf("Input xxx.so:function_name.\n");
while(1)
{
printf(">");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
 
pso = strdup(strtok(buf,":"));
pfun = strdup(strtok(NULL,":"));
 
test_dl(pso,pfun);
}
 
return 0;
}
 
运行结果:

Linux 静态库 & 动态库的更多相关文章

  1. linux静态与动态库创建及使用实例

    一,gcc基础语法: 基本语法结构:(由以下四部分组成) gcc -o 可执行文件名 依赖文件集(*.c/*.o) 依赖库文件及其头文件集(由-I或-L与-l指明) gcc 依赖文件集(*.c/*.o ...

  2. Linux中的动态库和静态库(.a/.la/.so/.o)

    Linux中的动态库和静态库(.a/.la/.so/.o) Linux中的动态库和静态库(.a/.la/.so/.o) C/C++程序编译的过程 .o文件(目标文件) 创建atoi.o 使用atoi. ...

  3. Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf 动态库的后缀为*.so 静态库的后缀为 libxxx.a ldconfig 目录名

    Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf  动态库的后缀为*.so  静态库的后缀为 libxxx.a   ldconfig   目录名 转载自:http://b ...

  4. Linux系统中“动态库”和“静态库”那点事儿【转】

    转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻. ...

  5. Linux系统中“动态库”和“静态库”那点事儿

    摘自http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在 ...

  6. Linux 静态库&动态库调用

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

  7. Linux中创建和使用静态库&动态库

    库本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行 Linux下库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同. 静态库的代码在 ...

  8. C/C++ 跨平台交叉编译、静态库/动态库编译、MinGW、Cygwin、CodeBlocks使用原理及链接参数选项

    目录 . 引言 . 交叉编译 . Cygwin简介 . 静态库编译及使用 . 动态库编译及使用 . MinGW简介 . CodeBlocks简介 0. 引言 UNIX是一个注册商标,是要满足一大堆条件 ...

  9. 【转】分析Linux和windows动态库

    原文地址:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Lin ...

  10. linux下so动态库一些不为人知的秘密(转)

    linux 下有动态库和静态库,动态库以.so为扩展名,静态库以.a为扩展名.二者都使用广泛.本文主要讲动态库方面知识.基本上每一个linux 程序都至少会有一个动态库,查看某个程序使用了那些动态库, ...

随机推荐

  1. Django-admin导出到表格

    class AdminReport(admin.ModelAdmin): actions = ["saveexecl"] # 自定义的action(导出到excel表格) list ...

  2. C#XML的序列化与反序列化

    要序列化的对象的类: [Serializable]public class Person{private string name;public string Name{get{return name; ...

  3. POJ 1195 Mobile phones (二维树状数组)

    Description Suppose that the fourth generation mobile phone base stations in the Tampere area operat ...

  4. #ZgotmplZ go web 开发 base64 图片显示

    Go Web开发,用Base64作为图片URL时遇到#ZgotmplZ的问题 - 简书 https://www.jianshu.com/p/54fc25da7c4f // var imgBase64 ...

  5. The threads in the thread pool will process the requests on the connections concurrently.

    https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Most of the executor implem ...

  6. 编译和使用bsdiff

    在android开发中,越到后面生成apk文件越来越大,每次用户更新都是全部下载更新,浪费时间和流量,如果能增量更新就不错了,使用bsdiff就是为了生成更新包 bsdiff下载地址:http://w ...

  7. Qtree3

    题目描述 给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白 有两种操作: 0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑) 1 v : 询问1到v的路径上的第一个黑点,若无,输出 ...

  8. meteor ---快速启动meteor和 mongodb 方法--MAC

    c:~ lsg$ cat .bash_profile c:~ lsg$ vim .bash_profile --- 修改这个文件 按i 修改文件 shift+Z+Z 保存修改内容 添加如下代码 exp ...

  9. wait()和notify()

    从https://www.cnblogs.com/toov5/p/9837373.html 可以看到他的打印是一片一片的,这边博客介绍怎么避免掉 使用notify 和 wait的时候 要注意 是在sy ...

  10. 扩散(diffusion)和弥散(dispersion)有什么区别

    作者:谢易正链接:https://www.zhihu.com/question/23914350/answer/177359196来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...