构建linux程序库和使用linux程序库

上传人:kms****20 文档编号:40981545 上传时间:2018-05-27 格式:DOC 页数:19 大小:46.50KB
返回 下载 相关 举报
构建linux程序库和使用linux程序库_第1页
第1页 / 共19页
构建linux程序库和使用linux程序库_第2页
第2页 / 共19页
构建linux程序库和使用linux程序库_第3页
第3页 / 共19页
构建linux程序库和使用linux程序库_第4页
第4页 / 共19页
构建linux程序库和使用linux程序库_第5页
第5页 / 共19页
点击查看更多>>
资源描述

《构建linux程序库和使用linux程序库》由会员分享,可在线阅读,更多相关《构建linux程序库和使用linux程序库(19页珍藏版)》请在金锄头文库上搜索。

1、构建构建 LinuxLinux 程序库和使用程序库和使用 LinuxLinux 程序库程序库【转载】构建 Linux 程序库和使用 Linux 程序库 2008-09-10 15:59 在本文里,我们将探索与 Linux 的程序库有关的知识。首先,我们考察静态库的基本知识,并介绍如何使用 ar 命令来建立静态库。然后,我们将学习共享库方面的知识,并讲述可以动态加载的共享库的有关内容。一、什么是程序库通俗的讲,一个程序库就是目标程序文件的一个集合。如果某些目标文件提供了解决一个特定问题的所需功能,我们就可以把这些目标文件归并为一个程序库,从而让应用开发者更易于访问这些目标文件,省得到处去找。对于

2、静态库,我们可以用实用程序 ar 来建立。当应用程序开发人员利用程序库进行程序的编译和连接时,程序库中为应用程序所需的那些元件就会集成到最终生成的的可执行程序中。之后,因为程序库已经融入应用程序的映像之中,成为它密不可分的一部分了,所以对应用程序来说,已经没什么外部的程序库可言了。共享程序库(或者动态程序库)也会连接到一个应用程序的映像上,不过需要两个不同的步骤。第一步发生在构建应用程序之时,链接程序检查是否在应用程序或者程序库内部找到了构建应用程序所需的全部符号(函数名或变量名) 。第二步发生在运行时,动态加载器把所需的共享库载入内存,然后动态地把它链接到应用程序的映像之中。注意,这里与静态

3、程序库不同,这次并没有把共享程序库中的所需元件放入应用程序的映像之中。很明显,这样生成的应用程序映像较小,因为共享程序库和应用程序的映像是相互独立的,如下图所示。图 1 静态库示意图图 2 动态库示意图虽然共享库能够节约内存,但是这是有代价的必须在运行时解析程序库。很明显,要想弄清需要哪些库,然后寻找这些库并将其载入内存肯定是需要一定时间的。本文中,我们会建立两个程序库,一个静态库和一个动态库,并以各自的方式应用于程序之中,以此亲身体验两者之间的区别。二、静态库的创建和使用相对于动态链接库,静态库要简单一些,它被静态的链接到应用程序的映像之中。这意味着,映像一旦建好,外部程序库的有无对映像的执

4、行将毫无影响,因为所需的部分已经放进程序二进制映像了。下面我们来演示如何用一组源文件来构造一个程序库。我们建立的程序库是用来封装 GNU/Linux 的随机函数的,这样我们的库就可以对外提供随机数生成器了。现在看一下我们的程序库为应用程序提供的接口(API) ,我们将其放在头文件 randapi.h 中,如下所示:/randapi.h,我们的程序库的接口#ifndef _RAND_API_H#define _RAND_API_Hextern void initRand( void );extern float getSRand( void );extern int getRand( int m

5、ax );#endif /* _RAND_API_H */我们的应用程序接口由三个函数构成,第一个函数是initrand() ,这是一个初始化函数,它的任务是为使用程序库做好必要的准备,在调用所有其他随机函数之前,必须首先调用这个初始化函数。第二个函数 getSRand()的作用是随机返回一个浮点数,其值介于 0.0 到 1.0 之间。最后一个函数是 getRand(x) ,它返回一个随机整数,其值介于 0 到(x1)之间。在文件 initrand.c 中,放的是初始化函数 initrand()的实现代码,这个函数使用当前时间作为种子值来初始化随机数生成程序。代码如下所示:/initrand.

6、c,初始化函数 initrand()的源代码#include #include /initRand()用于初始化随机数生成器void initRand()time_t seed;seed = time(NULL);srand( seed );return;文件 randapi.c 是我们最后一个实现 API 的文件,它也提供了一个随机数函数,源代码如下所示:/randapi.c,随机数函数的 API 实现#include /getSRand()返回一个介于 0.01.0 之间的浮点数float getSRand()float randvalue;randvalue = (float)rand(

7、) / (float)RAND_MAX);return randvalue;/getRand()返回一个介于 0(max-1)之间的整数int getRand( int max )int randvalue;randvalue = (int)(float)max * rand() / (RAND_MAX+1.0);return randvalue;这就是我们的 API 了,注意,initapi.c 和 randapi.c 的函数原型都放在了同一个头文件中,即 randapi.h.当然,我们完全可以在单个文件中来实现这些功能,但是为了示范程序库的建立,我们故意将它们放到不同的文件中。现在,我们在

8、来看一下使用这些 API 的测试程序,该程序将使用我们的程序库提供的应用编程接口进行工作。这个应用程序通过计算随机数函数返回的的平均值来快速检验 API,因为平均值应该在随机数范围的中间附近。该程序的代码如下所示:/test.c,测试我们的程序库的 API 的应用程序。#include “randapi.h“#define ITERATIONS 1000000Lint main()long i;long isum;float fsum;/*初始化随机数 API*/initRand();/*计算 getRand(10)的返回值的平均数*/isum = 0L;for (i = 0 ; i not

9、foundlibc.so.6 = /lib/tls/libc.so.6 (0x42000000)/lib/ld-linux.so.2 = /lib/ld-linux.so.2 (0x40000000)$ 命令 ldd 能确定出我们的测试程序需要用到哪些共享库。其中libc.so.6 是标准 C 库,ld-linux.so.2 是动态链接器/装载器。注意,这里显示没有发现 libmyrand.so,这是因为虽然该文件存在于应用程序的目录中,但是我们必须显式指出。我们可以通过环境变量 LD_LIBRARY_PATH 来完成此任务。给出我们的共享库的位置之后,再次使用 ldd 命令:$ export

10、 LD_LIBRARY_PATH=./$ ldd testlibmyrand.so = ./libmyrand.so (0x40017000)libc.so.6 = /lib/tls/libc.so.6 (0x42000000)/lib/ld-linux.so.2 = /lib/ld-linux.so.2 (0x40000000)$ 我们显式说明了共享库位于当前目录(。/)之后,再次运行ldd 命令,它现在终于找到所需共享库了。如果我们不这样做就急着执行我们的应用程序的话,将会收到一条错误消息,指出找不到所需的共享库,如下所示:$ ./test./test: error while loadi

11、ng shared libraries: libmyrand.so:cannot find shared object file: No such file or directory.$ 四、动态库的创建和使用我们最后要介绍的是一种动态加载的共享库,或称为动态链接库。它的特点是在应用程序运行过程中,什么时候需要了才装入内存,而不是像共享库那样当应用程序启动时就把程序库装入内存。为此,我们还要像前面那样来构建共享的目标文件,如下所示:$ gcc -fPIC -c initapi.c$ gcc -fPIC -c randapi.c$ gcc -shared initapi.o randapi.o

12、-o libmyrand.so$ su -$ cp libmyrand.so /usr/local/lib$ exit 在这里,我们将我们的共享库放到一个公共位置,即/usr/local/lib 目录。就像我们所看到的那样,静态库和共享库通常跟应用程序的二进制文件放置在同一目录下,与之不同,动态链接库则一般放在/usr/local/lib 目录中。这个库跟原来的共享库在功能上是等价的,只是应用程序使用它们的方式有所区别。需要说明的是,为了把我们的程序库复制到/usr/local/lib 中,需要 root权限。为此,可以首先使用 su 命令变成 root 用户。现在,我们已经重建了自己的共享库

13、,接下来就是我们的测试程序如何动态使用它了。为此,我们必须对测试程序访问 API 的方式做一些修改。然后,我们再来看一下如何构建使用动态链接库的程序。更新后的测试程序代码如下所示:/用于动态链接库的测试程序#include #include #include #include “randapi.h“#define ITERATIONS 1000000Lint main()long i;long isum;float fsum;void *handle;char *err;void (*initRand_d)(void);float (*getSRand_d)(void);int (*getRa

14、nd_d)(int);/打开动态库的句柄handle = dlopen( “/usr/local/lib/libmyrand.so“, RTLD_LAZY );if (handle = (void *)0)fputs( dlerror(), stderr );exit(-1);/检查对 initRand()函数的访问情况initRand_d = dlsym( handle, “initRand“ );err = dlerror();if (err != NULL)fputs( err, stderr );exit(-1);/检测对 getSRand()函数的访问情况getSRand_d = d

15、lsym( handle, “getSRand“ );err = dlerror();if (err != NULL)fputs( err, stderr );exit(-1);/检查 getRand()函数的访问情况getRand_d = dlsym( handle, “getRand“ );err = dlerror();if (err != NULL)fputs( err, stderr );exit(-1);/随机数 API 的初始化(*initRand_d)();/计算 getRand(10)返回值的平均数isum = 0L;for (i = 0 ; i ITERATIONS ; i

16、+)isum += (*getRand_d)(10);printf( “getRand() Average %dn“, (int)(isum / ITERATIONS) );/计算 getSRand()函数返回值的平均数fsum = 0.0;for (i = 0 ; i ITERATIONS ; i+)fsum += (*getSRand_d)();printf( “getSRand() Average %fn“, (fsum / (float)ITERATIONS) );/关闭动态库的句柄dlclose( handle );return;与之前的代码相比,您可能觉得这里的有些费解,但是只要弄懂了 DL API 的工作方式,一切问题就迎刃而解了。我们这里的真实意图是,先使用 dlopen 打开共享目标文件,然后通过 dlsym 让一个局部函数指针指向共享目标文件中的函数。这使得我们可以之后从应用程序中调用该函数。做完这些后,使用 dlclo

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号