linux 静态链接 动态链接库,Linux环境下编写静态和动态链接库

在实际的项目开发过程中,我们会经常碰见上下文中重复率较高的代码(函数或者功能模块等)。这样就会是整个程序代码显得十分臃肿,维护起来困难,而且可扩展性不强。为此,我们将重复性强的代码独立出来,并编译为特定的文件,让主程序是需要使用的地方调用,这种文件就成为动态链接库文件和静态链接库文件。有了这些文件能使项目中通用代码模块化,和主程序代码解耦;同时也使通用代码的复用性高,开发高效。

程序调用静态链接库,主要是主程序在编译时期就把库文件的代码拷贝加载到编译后的目标文件,类似于宏定义,这样导致编译后的文件会膨胀,可执行文件不需要外部的调用,运行时间相对较少;而程序调用动态链接库则是在程序中保留库文件名和函数名,在运行时根据库文件和函数名去加载库所需模块,这样编译后的文件空间变化不大,但是运行时间较长。总之,静态链接库是以空间换时间,增加可执行程序代码量,减少运行时间;动态链接库则是以时间换空间,减少可执行程序代码量,增加部分运行时间。

如何编写静态链接库

静态连接库一般以.a结尾,假设用重用一个简单的求和函数,函数输入一个正整数,求出正整数到1之间的所有正整数之和,并生成一个sum.a的静态链接库并在主程序中调用。

1.       编写头文件(sum.h),实现文件(sum.c)和调用主程序(test.c)。

//sum.h

#ifndef _SUM_H

#define _SUM_H

int sum(int n);

#endif

// sum.c

#include “sum.h”

int sum(int n)

{

if(n<1)

return 0;

else

return n+sum(n-1);

}

//test.c

#include

#include “sum.h”

int main(void)

{

printf(“%d\n”,sum(10));

return 0;

}

2.       将sum.h和sum.c放入自己定义的库文件目录slibdir,并编译复用代码。

gcc –c –g – fPIC sum.c –o sum.o

注释:-fPIC指通过这个选项来生成与位置无关的代码,可以在任何地址被连接和装载;-c指只编译而不连接原程序;-g是可调试选项。

3.       将用ar命令归档,将复用代码归档为静态连接库,格式为ar –rc。 再次提醒,注意,链接库文件名一定要以lib打头, .a(静态库)或者.so(动态库)为后缀。

ar –rc libsum.asum.o

4.       编译主文件,调用静态链接库。

gcc –g –c –I slibdir test.c –o test.o  (注释:-I slibdir 为指定test.c调用头文件的目录)

gcc –g –L slibdir test.o –o test –lsum (注释:-L slibdir 为指定静态链接库文件目录,-lsum就会在slibdir目录中寻找 libsum.a的静态链接库文件)

如何编写动态链接库

动态链接库的使用相对于静态链接库来说稍微复杂。通常生成的动态链接库是以 libName.so形式命名,其中Name是自己定义的名称, so也即shared object的意思。

1.      生成动态链接库。

同样以求和函数sum复用代码作为动态链接库的内容,并编写头文件sum.h和实现内容文件sum.cpp(这次要生成c++动态链接库),并将这两个文件放入dlibdir的目录中。编译生成动态链接库文件。

g++ -g –shared –fPICsum.cpp –o libsum.so   (注释:-shared 表明共享选项,-fPIC与编译静态链接库一样)

2.主程序链接动态链接库。

2.1  动态链接库隐式调用

动态链接库隐式调用过程就像调用静态连接库一样。编译主文件:

g++ -c -g – Idlibdir test.cpp –o test.o

g++ -g test.o –otest –L dlibdir –lsum

生成 test可执行文件,但是执行 ./test 后发现报错,信息如下:

./test: errorwhile loading shared libraries: libsum.so: can not open shared object file: Nosuch file or directory.

前面讲过动态链接库是在程序运行是加载,所以要加载动态链接库必须告诉其目录,这样才能加载成功。上面出错正是因为没有主程序告诉自定义的链接库目录。解决办法有以下几种:

(1)            将libsum.so直接copy到默认的动态的链接库目录(通过 ldconfig –v 查看系统的目录),比如复制到/usr/lib目录下,在./test就成功了。

(2)            在系统默认的库目录下建立软或硬链接,链接到dlibdir目录下的libsum.so。

ln -s `pwd`/libsum.so /usr/lib (``是反单引号)。

(3)            系统所有的动态链接库配置文件都在 /etc/ld.so.conf配置文件中,只要在该配置文件中添加dlibdir 目录(另起一行,不需要添加include),在重新 ldconfig 就可以,同样也可以通过命令行 ldconfig –v 来查看是否添加成功。

(4)            利用动态链接库管理命令ldconfig,强制其搜索指定目录,并更新缓存文件,便于动态装入.  ldconfig `pwd` 。

上述四种解决办法中(1)-(3)可以永久解决问题,但是(4)种只是临时性解决,如果在 ldconfig 之后就不行了,因为修改了/etc/ld.so.cache文件内容。

2.2  动态链接库显示调用

显示调用动态链接库,顾名思义就是要在主程序中显示调用库函数,要管理动态链接库的相关操作。

动态链接库操作相关操作的头文件为 dlfcn.h (/usr/include目录下),主要有以下几个系统函数:

(1)打开动态链接库文件函数:extern void*dlopen(const char *file, int mode) ;file 为动态链接库的文件名;mode为打开的模式,主要有两种模式:①RTLD_NOW:将共享库中的所有函数加载到内存, ②RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数。如果打开成功则返回不为空。

(2)检查执行操作后状态函数:extern char *dlerror(void); 检查操作状态,如果成功则返回空指针。

(3)获取动态链接库中函数或全局变量地址函数:extern void *dlsym(void*handle, const char *funname); handle为动态链接库打开后的句柄,funname 为调用动态链接库的函数符号名。

显示调用的主程序不同于隐式调用的主程序,显示调用主程序test.cpp 需要显示调用动态链接库中的函数和全局变量。假设主程序要实现隐式调用同样的功能,代码如下:

/test.cpp 测试动态库显式调用的程式

#include      //用于动态库管理的系统头文件

#include

#include "sum.h"    //要把函数的头文件包含进来,否则编译时会报错

int main(void)

{

int (*pTest)(int);  //声明对应的函数的函数指针

void *pdlHandle =dlopen("libtest.so", RTLD_LAZY);  //加载动态库

if(pdlHandle == NULL )   {      //错误处理

printf("Failed load library\n");

return -1;

}

char* pErr = dlerror();  //检查状态

if(pErr != NULL)

{

printf("%s\n", pErr);

dlclose(pdlHandle);

return -1;

}

pTest =(int(*)(int))dlsym(pdlHandle,"sum");   //获取函数的地址,记住指针类型转换,不能获取重载函数的地址(只根据函数名获取地址)

pErr = dlerror();

if(pErr != NULL)

{

printf("%s\n", pErr);

dlclose(pdlHandle);

return -1;

}

std::cout<

dlclose(pdlHandle); //程式结束时关闭动态库

return 0;

}

整个获取库函数的流程和读取流、ASCII文件相似。编译主程序:

g++ -I dlibtest.cpp –o test –ldl; (使用-ldl选项指明生成的对象模块需要使用共享库注意 –ldl 编译选项一定要放在目标文件后面,如果放在目标文件前面,编译会报错:undefined reference to ‘dlopen’)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值