linux静态库与共享库(二)

原文地址:

http://blog.csdn.net/hmalloc/article/details/8463325



6 库的使用

下面来写个程序测试一下前面两个库文件,代码如下:

  1. /* say.c */  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4.   
  5. void say_something(const char *str);  
  6.   
  7. int main(int argc, char **argv)  
  8. {  
  9.     say_something(argv[1]);  
  10.     exit(0);  
  11. }  

下图中显示了生成的两个库文件:

 

静态库的使用

执行如下命令编译链接:

[plain]  view plain copy print ?
  1. gcc –c say.c –o say.o  
  2. gcc –o say say.o libsay.a  
这将生成可执行文件say,./say加参数即可运行。这就是静态库,它只在链接时需要。

静态库使用很简单,但有一点需要注意,就是——链接顺序。如果你按如下顺序链接:

[plain]  view plain copy print ?
  1. gcc -o say libsay.a say.o  
将得到这样的错误提示:

[plain]  view plain copy print ?
  1. say.o: In function `main':  
  2. say.c:(.text+0x15): undefined reference to `say_something'  
  3. collect2: ld returned 1 exit status  
这是初学者经常碰到的问题,尤其当项目比较庞大库文件较多时。因为链接器(ld)按输入库顺序链接,libsay.a先输入,然后它发现say_something并未被使用,所以并不会链接,所以会报这样的错误。库文件的链接顺序尤为重要,其基本原则就是越独立越底层的库应尽量靠后放。

共享库的使用

共享库的使用有多种方法,我总结了五种,下面一一道来。

我们生成的共享库文件为 libsay.so.1.0.0,为了链接方便,我们用如下命令创建两个符号链接:
[plain]  view plain copy print ?
  1. ln -s libsay.so.1.0.0 libsay.so.1  
  2. ln -s libsay.so.1 libsay.so  
创建后如图所示:

方法一:

[plain]  view plain copy print ?
  1. gcc say.c –o sayso –L. –Wl,-rpath=. –lsay   

方法一用-L指定链接时搜索路径而用-rpath指定运行时搜索路径,编译后生成可执行文件sayso,可直接运行。
为了验证生成的sayso文件的依赖性,可用ldd(查看可执行文件的共享库依赖性)命令查看一下,如图所示:


我们还可以用 readelf 命令查看 rpath 即运行时路径:


在接下来的几种方法中我们同样可以用这两个命令查看依赖性。

方法二:

[plain]  view plain copy print ?
  1. export LD_LIBRARY_PATH=`pwd`  
  2. gcc –L. say.c –o sayso2 –lsay  

方法二首先设置环境变量LD_LIBRARY_PATH为当前目录(小技巧,用`pwd`代替),因为共享库文件在当前目录下,这样运行可执行文件后也能找到该库文件。

方法三:

将共享库文件libsay.so.1.0.0复制到/usr/lib下,并创建 libsay.so libsay.so.1等符号链接(创建符号链接前面有提到),然后运行如下命令:
[plain]  view plain copy print ?
  1. gcc say.c –o sayso3 –lsay  
从以上命令看到少了–L选项,因为/usr/lib是系统默认搜索路径,所以不必指定,但LD_LIBRARY_PATH对-l无效,所以方法二中依然需要–L选项。
为了验证方法三是可行的,我们可以把LD_LIBRARY_PATH重新置为空:
[plain]  view plain copy print ?
  1. export LD_LIBRARY_PATH=  
然后再运行./sayso3发现运行正常,下图中显示了这种差异,由此也看出LD_LIBRARY_PATH的优先级别高于/usr/lib。


将/usr/lib中刚刚copy的文件删除,来试验一下方法四,这个时候运行./sayso3应该提示找不到库文件。

方法四:

接下来我们要用到一个文件——/etc/ld.so.conf(笔者的系统是ubuntu 10.04),这个文件记录了一些共享库搜索路径(或者完整的共享库名),查看其内容不难发现其用法,我们可以将我们的共享库所在路径添加到这里来,要使添加的路径有效,我们还必须以root权限执行ldconfig命令,该命令会根据ld.so.conf文件,在/etc目录下生成ld.so.cache文件,ld.so.cache文件才是系统运行时搜索库的关键。
cat ld.so.conf文件发现其内容如下:
include /etc/ld.so.conf.d/*.conf
所以我们只要在/etc/ld.so.conf.d目录下创建相应的conf文件即可。cd到该目录,用root权限创建 libsay.conf 文件,将共享库文件所在路径添加到该文件中保存,执行ldconfig。然后我们运行./sayso3,发现又能运行了。

方法五:

接下来是终极方法,也是非常有用有意思的方法!
方法五要用到系统库dl(专门服务于共享库加载),该库提供了以下几个函数:
dlopen: 将共享库载入内存,返回一个句柄
dlsym: 返回函数地址
dlclose: 从共享库中释放当前程序
dlerror: 返回出错字符串,如果没有则为空
dl库用法示例:
  1. /* saydl.c */  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <dlfcn.h>  
  5.   
  6. int main(int argc, char **argv)  
  7. {  
  8.     void (*say)(const char *);  
  9.     char *error;  
  10.     void *handle;  
  11.   
  12.     handle = dlopen("libsay.so", RTLD_LAZY);  
  13.     if (error = dlerror()) {  
  14.         printf("%s\n", error);  
  15.         exit(1);  
  16.     }  
  17.   
  18.     say = dlsym(handle, "say_something");  
  19.     if (error = dlerror()) {  
  20.         printf("%s\n", error);  
  21.         exit(1);  
  22.     }  
  23.   
  24.     say("hello, world!\n");  
  25.   
  26.     dlclose(handle);  
  27.     exit(0);  
  28. }  
编译这段代码:

[plain]  view plain copy print ?
  1. gcc saydl.c -o saydl -ldl  
可以看到,在这里根本不需要指定 libsay.so 库相关路径,因为程序运行时通过dlopen动态加。虽然如此,程序运行还是会按照运行时库搜索优先级搜索的,除非dlopen采用了绝对路径。看到这个方法相信你会很惊讶,不要惊讶,请深入体会,这个方法很有价值。

7 总结

好了,如果你能从头到尾将这篇文章看完,并亲自动手实践,我相信你对于库的使用及相关问题应该游刃有余了,也说明你有足够的求知欲。从这里我们也可以看出linux高深的技术,这同时也是一种艺术,大神们为linux所做的工作令人叹服!

我查阅了大量资料以撰写该文章,请相信我这篇文章对你有用!这些看似烦琐细腻的技术,已给我带来极大的乐趣与帮助!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值