【转】Static library & dynamic library -- linux系统下的静态库与动态库





Static library & dynamic library -- linux系统下的静态库与动态库

写这篇文章主要是由于昨天心心同学问了个关于实现动态库链接的makefile。然后我囧了,没能解答=,=
然后今天把<<Advanced Linux Programming>>看了下,把笔记写下来。。。
难免回有错误,还忘不吝指正:)
    我们知道,几乎所有的程序在运行时都会链接到一个或多个库。比如C语言的printf函数,调用此函数时就会用到c的标准输入输出库;而在GUI下面,会用到对应的图形库;调用数据库时,会用到数据库系统提供的相应的库,等等。
    1.静态库
       静态库(archive / static library)就是一些简单的目标文件整合而成的单个文件。可以暂且把它看作是windows下的.lib文件。当把这个库提供给某个文件作为某个程序的接口(不知道“接口"用在这里恰不恰当,个人理解的)时,链接就会把这个库解压,然后搜寻需要的接口,把它加载到程序中来。
       linux中静态库的后缀是.a,前缀默认为lib。使用ar命令可以把一个或多个目标文件打包成一个文件。基本格式是:
       ar -cr lib*.a opt1.o ...   optn.o

       其中 参数cr表示creat 和 replace ,即创建并替换(这里的替换是指当文件创建成功时,如果有同名文件则替换之)。lib*.a是目标库文件。optx.o 是目标文件列表。
       生成了库文件后,需要该库的程序只需要在编译的时候加载改库即可。
比如定义了一个函数out(char *s);该函数输出对应的串
对应的文件如下:

out.h:
#ifndef OUT_H
#define OUT_H
void out(char *);
#endif

out.c
#include<stdio.h>
#include"out.h"
void out(char *s){
    printf("%s\n",s);
}

main.c
#include"out.h"
int main(int argc,char ** argv){
    int i;
    for(i=1;i<argc;i++){
        out(argv[i]);
    }
}

用如下命令编译:
%gcc -c out.c
%ar -cr libout.a out.o
%gcc -o pig main.c -L. -lout


    最后一个命令中:-L. 表示链接目录是当前目录.-lout 指出链接文件这里是libout.a 其中的lib 和 a 被编译器默认了,可以省略。
那么我们就可以执行这个文件了^_^
%./pig silly pig
静态链接库是将该库直接整合到目标可执行文件中的,也就意味着 当编译链接完成后libout.a已经没有可利用价值了(对于本程序来说)。

    2.动态库
        动态库(shared library/shared object/dynamic link library),就类似windows下的的动态链接库了(.dll)文件。它的执行机理和静态库有点不同。在静态库中,我们的可执行程序完全依赖于程序本身,与其他程序无关(这里假设程序不涉及exec(),pipe之类的操作),而具有动态库链接的程序,则其运行依赖于它所指向的链接。
因为这些lib是在程序运行的时候动态搜索和加载的。当运行时找不到对应的lib时将报错。
        动态库的生成和静态库有所不同,其一般格式为:
%gcc -shared -fPIC -o lib*.so opt1.o .... optn.o
由于动态库是能够被多个程序共享的,所以加了shared参数。-fPIC 表示生成一个PIC文件(pic:position independent code. 位置独立文件???),意思是与文件的位置无关。动态库的默认前缀和后缀是lib 和 .so
        这样,我们在加载的时候用同样的方法
%gcc -c -shared -fPIC out.c
%gcc -o pig libout.so -L. -lout
然后运行~
% ./pig silly pig
娃哈哈
出错了~
找不到对应的入口!
原来
动态库的搜索路径被默认设定为:/lib 和/usr/lib
那么如果我们在其他目录下生成动态库的话,就搜不到这个库了
解决办法有两个:
1.把这个文件移到搜索路径对应的目录下,这个比较简单
2.把当前路径加入到搜索路径里,程序自动搜索:export LD_LIBRARY_PATH=$LD _LIBRARY_PATH:$pwd
这样再进行运行就不会有问题了。
当然,完了之后可以试着把生成的.so文件删除再运行,看结果是什么:)

那么我们的Makefile就很容易写了,对于以上程序
如下:

all:libout.so main.o
    gcc -o pig main.o -L. -lout

clean:
    rm -f *.o
    rm -f *.so
    rm pig

libout.so:out.o
    gcc -shared -fPIC -o libout.so out.o

out.o:out.h
    gcc -shared -fPIC -c out.c

main.o:
    gcc -c main.c

make 后直接运行./pig argv[0] argv[1]...即可:)
补充:
1.原来,以前写程序用到math库的时候要在编译选项后面加-lm,就是这个道理
2.其实一般情况下makefile里的编译就是基于静态库的链接过程,比如这个文件可以如下编译:
all:out.o main.o
    gcc -o pig out.o main.o
clean:
    rm -f *.o
    rm pig
out.o:out.h
    gcc -c out.c
main.o:
    gcc -c main.c
同样就是这个原理~
3.库依赖问题:在链接的时候有可能一个库依赖于另一个库,可用ldd命令查看对应的依赖性

那么我们在编译的时候应该把所有依赖的库列出来

还有一个问题,有时候我们需要更新某个模块,但是又不想重新编译源文件。比如:插件的更新。许多软件的更新都只加入一些新的模块,并不会改变主程序,那么这就要用到dlopen函数了。可以这样打开一个动态链接库:
dlopen ("libtest.so", RTLD_LAZY) ;
这个函数的返回值是对应的库的句柄,我们可以通过dlsym函数将这个句柄传递给对应的函数
假设函数名为"my_function",那么对应的链接可以如下建立:

void* handle = dlopen ("libtest.so", RTLD_LAZY);
void (*test)() = dlsym (handle, "my_function");
(*test)();
dlclose (handle);

这里test是一个函数的指针,用这个方法就实现了动态链接,test就指向了相应的需要的函数。



4.同过对静态和动态库的了解,动态库可以完成静态库的所有功能,似乎动态库比静态库更加优秀,静态库的存在纯粹是多余的,其实不然。
设想我们的程序是一个重要的系统程序,那么如果我们使用动态链接库的话,则会带来很多麻烦,使得系统不稳定且不安全。
比如某用户可以对你的动态库进行修改,那么当系统程序运行时就会出错,甚至导致系统瘫痪。
那么显然,使用静态库则么有这个问题了。

所以,在具体的设计时要选用静态还是动态lib,要根据具体的情况,进行筛选,写出精简,高效,安全的程序。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值