您的位置:首页 > 运维架构 > Linux

Linux编程简介——静态链接库和动态链接库

2016-01-19 23:26 351 查看
转载自:http://www.cnblogs.com/TianFang/archive/2013/01/18/2866952.html

Linux编程简介——静态链接库

有时我们需要将一组代码编成一个库,从而方便其复用。例如,我们调用的STL和系统函数都是以这种方式提供的。另外,当项目工程较大时,为了使其模块化方便分工,有时也需要将其创建自己的链接库。
链接库按照其链接方式可以分为动态链接库和静态链接库两种,本文主要介绍一下静态链接库的创建方式。
以一个简单的代码为例,这里有两个文件main.c和stack.c,这里打算把stack.c作为一个lib供main.c调用。
    /* stack.c */
    char stack[512];

    int top = -1;

    char pop(void)

    {

        return stack[top--];

    }

    void push(char c)

    {

        stack[++top] = c;

    }

    /* main.c */
    #include <stdio.h>

    char pop();

    void push(char c);

    void main(void)

    {

        push('a');

        push('b');

        printf("%c\n", pop());

    }
要把stack.c编成lib,需要经过如下两个步骤:

通过gcc –c命令将stack.c编成stack.o

通过ar命令将stack.o封装成libstack.a

    gcc -c stack.c

    ar  stack.o
执行完这两条命令后,就可以生成一个libstack.a的文件了,然后再链接的时候直接使用这个.a文件即可以生成执行文件。
    gcc -o run main.c -L. -lstack
这个链接命令并没有什么太多可介绍的,其中-L、-l参数用于指定链接库,在上一篇文章中已经介绍过,这里就不做更多说明了。
上述过程中,用到了条之前没见过的命令ar。ar是archive的缩写,也就是归档的意思,平时我们用得更多的是另一条归档命令tar。ar和tar的功能其实比较类似,但ar命令做了一些额外的处理,它会为被归档的目标文件中的符号建立索引,当和应用程序链接时,建立的这些索引将回收链接过程
ar命令的参数比较多,如果只是创建lib库的话,通常只用到了cr这两个组合参数。该命令是可以接受多个输入文件,统一合并到一个库中。
    ar cr libtest.a first.o second.o third.o
在通过ar创建lib后,可以通过ar -t命令查看该lib里打包了那些.o文件
    tianfang > ar -t libstack.a

    stack.o
此外,还可以通过nm命令来查看符号表等更多信息
    tianfang > nm libstack.a

    stack.o:

    00000000 T pop

    0000001b T push

    00000200 C stack

    00000000 D top
ar和nm的命令参数比较多,更多信息可以参考这篇文章:AR和NM命令的使用
最后,知道了ar只是一个打包的功能后,再回头来看看静态链接的过程,它其实只是把一堆.o文件打包成了一个.a文件,链接的时候仍然是从.a文件里面查找.o文件进行链接,和之前的编译方式并没有什么本质的区别。
http://www.cnblogs.com/TianFang/archive/2013/01/19/2867296.html

Linux编程简介——动态链接库

传统方式下,库函数的链接是在编译器完成的,所有相关对象在编译的时候被整合成一个可执行文件。与此相比,我们也可以把对库函数的链接载入推迟到程序运行的时期,也就是我们所称作的动态链接。
动态链接的优点
除了静态链接库所有的模块化和代码复用外,动态链接库还有如下优点。

可以实现进程之间的库共享:

当多个进程共享一个库时(如stl库和一些系统库是基本上大多数程序都用的),动态链接方式可以只在内存中保留一份副本,节约内存。

升级变得简单:

用户只需要升级动态链接库,而无需重新编译链接其他原有的代码就可以完成整个程序的升级(很多Windows的补丁就是这种方式发布的)。

可以动态载入:
当软件比较大的时候,可以根据需要动态载入/卸载相应的链接库,而无需像静态链接的方式那样必须一次性全部载入

创建动态链接库
创建动态链接库的方式比较简单,以前文静态链接库的例子为例,我们只需要通过gcc -shared指令即可创建一个libstack.so的动态库(静态库一般以.a作为扩展名,动态库一般以.so作为扩展名)。
    gcc -shared -o libstack.so stack.o
在链接阶段使用动态库的方式基本上和静态库一致。
    gcc -o run main.c -L. –lstack
编译玩这个程序后,我们执行后却发现,它报动态链接库找不到的错误提示。
    tianfang > ./run

    ./run: error while loading shared libraries: libstack.so: cannot open shared object file: No such file or directory
我们也可以通过ldd命令查看某程序当前对动态链接库的依赖情况:
    tianfan > ldd run
    linux-gate.so.1 (0xb7707000)
    libstack.so => not found
    libc.so.6 => /lib/libc.so.6 (0xb7546000)
    /lib/ld-linux.so.2 (0xb7708000)
ldd的结果表明了我们生成的libstack.so找不到。因为动态链接库是一个可以共享的文件,因此往往存放在一个公共的位置,在Linux系统中程序查找动态链接库的规则如下:

首先在环境变量LD_LIBRARY_PATH所记录的路径中查找。

然后从缓存文件/etc/ld.so.cache中查找。

如果上述步骤都找不到,则到默认的系统路径中查找,先是/lib然后是/usr/lib。

很明显,这几个路径都不包含当前路径。要解决上述问题,一个简单的方式就是把当前路径加到环境变量中:
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
然后再次用ldd名称测试,发现现在就能找到我们的链接库了。
    tianfan > ldd run
    linux-gate.so.1 (0xb77ce000)
    libstack.so => ./libstack.so (0xb77ca000)
    libc.so.6 => /lib/libc.so.6 (0xb760a000)
    /lib/ld-linux.so.2 (0xb77cf000)
不过,很多大牛并不建议通过修改LD_LIBRARY_PATH这种方式

LD_LIBRARY_PATH is not the answer http://prefetch.net/articles/linkers.badldlibrary.html

Why LD_LIBRARY_PATH is bad     http://xahlee.org/UnixResource_dir/_/ldpath.html

LD_LIBRARY_PATH - just say no     http://blogs.sun.com/rie/date/20040710
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: