linux静态库与共享库(二)

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

6 库的使用

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

[cpp]view plaincopyprint?

    /*say.c*/#include<stdio.h>#include<stdlib.h>voidsay_something(constchar*str);intmain(intargc,char**argv){say_something(argv[1]);exit(0);}

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

静态库的使用

执行如下命令编译链接:

[plain]view plaincopyprint?

    gcc–csay.c–osay.ogcc–osaysay.olibsay.a

这将生成可执行文件say,./say加参数即可运行。这就是静态库,它只在链接时需要。

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

[plain]view plaincopyprint?

    gcc-osaylibsay.asay.o

将得到这样的错误提示:[plain]view plaincopyprint?

    say.o:Infunction`main’:say.c:(.text+0x15):undefinedreferenceto`say_something’collect2:ldreturned1exitstatus

这是初学者经常碰到的问题,尤其当项目比较庞大库文件较多时。因为链接器(ld)按输入库顺序链接,libsay.a先输入,然后它发现say_something并未被使用,所以并不会链接,所以会报这样的错误。库文件的链接顺序尤为重要,其基本原则就是越独立越底层的库应尽量靠后放。共享库的使用

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

我们生成的共享库文件为 libsay.so.1.0.0,为了链接方便,我们用如下命令创建两个符号链接:[plain]view plaincopyprint?

    ln-slibsay.so.1.0.0libsay.so.1ln-slibsay.so.1libsay.so

创建后如图所示:

方法一:

[plain]view plaincopyprint?

    gccsay.c–osayso–L.–Wl,-rpath=.–lsay

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

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

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

方法二:

[plain]view plaincopyprint?

    exportLD_LIBRARY_PATH=`pwd`gcc–L.say.c–osayso2–lsay

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

方法三:

将共享库文件libsay.so.1.0.0复制到/usr/lib下,并创建 libsay.so libsay.so.1等符号链接(创建符号链接前面有提到),然后运行如下命令:[plain]view plaincopyprint?

    gccsay.c–osayso3–lsay

从以上命令看到少了–L选项,因为/usr/lib是系统默认搜索路径,所以不必指定,但LD_LIBRARY_PATH对-l无效,所以方法二中依然需要–L选项。为了验证方法三是可行的,我们可以把LD_LIBRARY_PATH重新置为空:[plain]view plaincopyprint?

    exportLD_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库用法示例:[cpp]view plaincopyprint?

    /*saydl.c*/#include<stdio.h>#include<stdlib.h>#include<dlfcn.h>intmain(intargc,char**argv){void(*say)(constchar*);char*error;void*handle;handle=dlopen("libsay.so",RTLD_LAZY);if(error=dlerror()){printf("%s\n",error);exit(1);}say=dlsym(handle,"say_something");if(error=dlerror()){printf("%s\n",error);exit(1);}say("hello,world!\n");dlclose(handle);exit(0);}

编译这段代码:[plain]view plaincopyprint?

    gccsaydl.c-osaydl-ldl

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

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

我查阅了大量资料以撰写该文章,请相信我这篇文章对你有用!这些看似烦琐细腻的技术,已给我带来极大的乐趣与帮助!这种精神使人能在旅行中和大自然更加接近,

linux静态库与共享库(二)

相关文章:

你感兴趣的文章:

标签云: