linux的库文件

一、什么是库

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于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

int add(int a,int b)

{

return a + b;

}

sub.c

#include

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

int main(int argc,char *argv[])

{

int a,b;

if(argc < 3)

{

fprintf(stderr,"Usage : %s argv[1] argv[2].\n",argv[0]);

return -1;

}

a = atoi(argv[1]);

b = atoi(argv[2]);

printf("a + b = %d\n",add(a,b));

printf("a - b = %d\n",sub(a,b));

return 0;

}

生成静态库

生成动态库:

使用生成的生成的库:

其中

-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;

}

运行结果:

时间: 2024-11-07 10:24:01

linux的库文件的相关文章

linux下库文件的编程

编程到了一定的时候,总喜欢追求新的东西.将代码尽量模块化就是我的追求之一,原来只是满足于将代码从单文件中分离,通过头文件和实现文件实现模块化,后来发现最好的方法是打包成库文件,使用更加方便.尽管在linux和windows下都有大量的库文件,由于二者的工具不同,加上笔者主要是在linux下编程和教学,因此本文主要介绍Linux下的库文件的制作. 库文件在linux中主要有两种:静态库和动态库(共享库),二者的不同主要有: 1.载入时机不同:静态库是在编译时进行载入到代码中:共享库在运行时载入到代

Linux安装库文件(环境变量和makefile)

CFLAGS 表示用于 C 编译器的选项,CXXFLAGS 表示用于 C++ 编译器的选项.这两个变量实际上涵盖了编译和汇编两个步骤. CFLAGS/CPPFLAGS: 指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include.同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的include目录加入到该变量中来. LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件

Linux C头文件查找与动态库搜索

一.编译程序时,头文件路径搜索 本文介绍在linux中头文件的搜索路径,也就是说你通过include指定的头文件,linux下的gcc编译器它是怎么找到它的呢.在此之前,先了解一个基本概念. 头文件是一种文本文件,使用文本编辑器将代码编写好之后,以扩展名.h保存就行了.头文件中一般放一些重复使用的代码,例如函数声明.变量声明.常数定义.宏的定义等等.当使用#include语句将头文件引用时,相当于将头文件中所有内容,复制到#include处.#include有两种写法形式,分别是: #inclu

Linux静态库和动态库学习总结

一.废话 之前由于工作需要,要封装一个Linux加密解密转换的动态库,这个之前只做过Windows下面的,Linux下面还真没有做过,之后做了整一个晚上才算做好,不过其中也学到了不少东西,包括Linux下的动态库和静态库,MakeFile等等.之前就已经写了一个练习,之后怕又忘了,总结一下备忘,以后也好查. 很大部分内容都是收集的一些东西还有自己学习的体会,有什么错误或者问题请直接提出. 二.关于库的问题 1.库的原则 现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始.尽量不

Linux&mdash;&mdash;C库

1.库的概念 库是一个二进制文件,包含的代码可被程序调用 标准C库.数学库.线程库-- 库有源码,可下载后编译:也可以直接安装二进制包 /lib /usr/lib 2.库的知识 库是事先编译好的,可以复用的代码. 在OS上运行的程序基本上都要使用库.使用库可以提高开发效率. Windows和Linux下库文件的格式不兼容 Linux下包含静态库和共享库 3.静态库特点 编译(链接)时把静态库中相关代码复制到可执行文件中 程序中已包含代码,运行时不再需要静态库 程序运行时无需加载库,运行速度更快

linux下把log4cxx封装成so动态库文件(一)

这是一个经常遇到的问题,在软件开发过程中,需要将某些功能封装成一个独立的模块,这样维护升级也很方便.现在我们就要把开源日志库log4cxx封装成so动态加载库文件. 在上一篇文章<log4cxx日志库RedHat下安装>中,我们已经将log4cxx安装在home/mac/log4cxx/log4cxx下了,那么接下来的操作我们就继续在这个路径下进行. 还是先tree一下/home/mac/log4cxx这个目录吧 log4cxx ---apr ---apr-util ---log4cxx 那再

linux库文件编写入门(笔记)

linux库文件的编写 作者: laomai地址: http://blog.csdn.net/laomai 本文主要参考了如下资料⑴hcj写的"Linux静态/动态链接库的创建和使用"地址 http://fanqiang.chinaunix.net/system/linux/2006-05-08/4126.shtml⑵雨亦奇的文章"LINUX动态链接库高级应用"地址http://www.ccw.com.cn/htm/center/prog/02_3_13_3_2.a

linux内核函数库文件的寻找

linux内核函数的so库文件怎么找呢? 首先还是要产生一个进程的coredump文件的 linux有一个lib-gdb.so库,这个进程的coredump文件中所有load段的最后一个load段中,通过读取二进制文件将最后一个load段读取出来保存lib-gdb.so库文件,这个库文件就是内核函数的库文件. coredump文件头->多个程序头(每一个程序头都会对应一个load段)->通过程序头读取load段

Linux下Qt应用程序的发布(使用LDD命令查看所有依赖的库文件)

最近一直在学习Qt,用Qt写了一个程序,但是不知道怎么发布,网上说的都是在windows下怎么发布Qt应用程序,但是,在windows下Qt应用程序依赖的库文件与linux下的名字不同.于是,我就想到Linux下有没有这么一个命令,能够找到一个可执行文件运行时所依赖的库文件,百度一下,还真的有ldd命令. ldd的作用是打印可执行文件依赖的共享库文件,它是glibc的一部分: [email protected]:~# ldd --helpUsage: ldd [OPTION]... FILE..