Linux共享库的创建

来源:互联网 发布:复杂网络社区发现 编辑:程序博客网 时间:2024/05/16 19:19

库是程序员必须的工具,它是已经编译过的代码。库通常提供通用的功能,例如链表和二叉树等数据结构,或者特定的功能,例如MySQL等数据库服务器访问接口。

         多数大型软件项目有多个部件组成,这些部件有可能在其它项目中用到,或者你只是想分离多个部件以便组织。当你有一个可重用或者逻辑上独立的函数集合,建立一个库使你不用总是复制代码到现在的项目然后重新编译,而且可以保持不同的模块的分离,修改其中一个不会影响其他模块。只要一个库被写好且测试过,就可以安全地重用。

         建立静态库是相当简单的,这里只讲如何建立共享库(动态库)。

         在开始之前,先看看从源代码到可执行程序这个过程中发生什么:

         1、C语言预处理:这个阶段,任何以#开头,例如#define和#include的行都会被处理,也就是宏替换和文件包含。

         2、编译:将预处理后的源代码转换成汇编代码,然后在转换成机器代码。

         3、链接:将objectfiles和库链接生成可执行程序。对于静态库,链接器把库本身放到最终的可执行程序中;而对于共享库,只是把对库的引用放到里面。

         4、装入:当我们执行程序的时候,检查程序对共享库的引用,将动态库映射到程序中。

第3和第4步是共享库比较神奇却也让人困惑的地方。

foo.h:

1 #ifndef foo_h__2 #define foo_h__3 extern void foo(void);4 #endif  // foo_h__

foo.c:

#include <stdio.h>void foo(void){    puts("Hello, I'm a shared library");}

main.c:

复制代码
#include <stdio.h>#include "foo.h"int main(void){    puts("This is a shared library test...");    foo();    return 0;}
复制代码

foo.h定义了我们的库的接口,一个函数foo(),foo.c是函数实现的地方。

本例子在路径 /home/username/foo

Step 1:编译不依赖于位置的代码

将库的源代码编译成位置无关的代码

$ gcc -c -Wall -Werror -fpic foo.c

Step 2: 由目标文件(object file)生成共享库

将库的名称定为 libfoo.so:

gcc -shared -o libfoo.so foo.o

Step 3: 链接共享库

先编译 main.c然后链接 libfoo最终生成程序“test.”-lfoo选项是用来寻找libfoo.so的。 GCC 假定所有库以lib开头,以.so或者.a结尾(.so是代表共享库,.a代表归档或者静态链接库)。

$ gcc -Wall -o test main.c -lfoo/usr/bin/ld: cannot find -lfoocollect2: ld returned 1 exit status

告诉GCC去哪里找共享库

–L选项,在此例中,共享库在当前目录,也就是/home/username/foo

$ gcc -L/home/username/foo -Wall -o test main.c -lfoo

Step 4: 使共享库在程序运行时能用上。

$ ./test./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

因为没有将共享库libfoo.so放在标准目录,所以要给装入器(loader)点帮助。有几个选择:可以用环境变量LD_LIBRARY_PATH,或者rpath。先看看LD_LIBRARY_PATH

Using LD_LIBRARY_PATH

$ echo $LD_LIBRARY_PATH

这个变量中什么也没有,我们将工作目录加到LD_LIBRARY_PATH中。

$ LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH$ ./test./test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

虽然正在LD_LIBRARY_PATH这个目录中,但是没有export它。在Linux,如果没有export那些对环境变量的改变,它们的改变不会被子进程继承,所以装入器(loader)和test程序没有继承这些改变。好在,很容易解决这个问题:

$ export LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH$ ./testThis is a shared library test...Hello, I'm a shared library

Good, it worked! LD_LIBRARY_PATH 用来测试共享库很方便,尤其是当我们没有系统管理员权限的时候。然而,exportLD_LIBRARY_PATH意味着有可能导致其他用到LD_LIBRARY_PATH的程序出问题。

Using rpath

现在试试rpath(首先清空LD_LIBRARY_PATH,以确保是rpath找到共享库)。rpath,也就是运行路径(run path),是在可执行程序中嵌入共享库位置的一种方式,而不是依赖于默认的位置或者环境变量。在链接的阶段,用“-Wl,-rpath=/home/username/foo” 选项,-WL给定链接器一些选项,这些选项以逗号分隔。

$ unset LD_LIBRARY_PATH$ gcc -L/home/username/foo -Wl,-rpath=/home/username/foo -Wall -o test main.c -lfoo$ ./testThis is a shared library test...Hello, I'm a shared library

rpath很好用,因为每个程序可以设定独立的共享库位置,而不会像LD_LIBRARY_PATH那样影响其他程序。不过,rpath缺乏灵活性,它要求共享库安装到特定的路径,在系统配置时不灵活。

Using ldconfig to modify ld.so

如果想安装我们的库让任何系统登录用户可以使用,需要管理员权限,理由如下:首先,要把库放到标准位置,可能是/usr/lib/usr/local/lib,普通用户没有写入权限;其次,要修改ld.so配置文件和缓存。以管理员登陆,执行以下命令:

$ cp /home/username/foo/libfoo.so /usr/lib$ chmod 0755 /usr/lib/libfoo.so

现在,库文件在标准路径下,有着可以被任何人读取的权限。要告诉装入器它是可用的,于是更新缓存:

$ ldconfig

上面的命令会创造一个到共享库的链接,更新缓存。检测以下:

$ ldconfig -p | grep foolibfoo.so (libc6) => /usr/lib/libfoo.so

可见我们的库已经安装好了。在用它之前,先清理LD_LIBRARY_PATH,以防万一:

$ unset LD_LIBRARY_PATH

重新链接我们的可执行程序,不需要–L选项,因为我们的库已经放在默认的位置,且不需要rpath选项:

$ gcc -Wall -o test main.c -lfoo

ldd命令,看看test是否使用了我们的库:

$ ldd test | grep foolibfoo.so => /usr/lib/libfoo.so (0x00a42000)

然后运行:

$ ./testThis is a shared library test...Hello, I'm a shared library
链接:http://www.cnblogs.com/wongzawing/archive/2013/02/19/2917792.html
0 0
原创粉丝点击