Linux动态库与静态库的创建与使用

  在程序设计实现中,有时需要使用库对一些公用函数、数据结构进行封装,这样做可以使得整个工程更加灵活,增强可维护性和可扩展性;同时,也可以仅提供头文件API,将数据结构保护起来,在多人协同开发的任务中避免别人不按照自己提供的接口对数据进行访问、操作,造成一些意想不到的运行时才会发生错误。扯远了,今天学习了Linux下的静态库与动态库的创建与使用,在此记录。

  在Linux系统中,静态库,称作archive(归档文件),以.a为后缀,类似于Window下的.LIB库,在程序编译链接时,会将静态库中的内容一并添加至生成的可执行文件中。动态库,称作shared library(共享库),以.so为后缀(shared object),同样类似于Window下的.DLL库,程序编译时同样需要进行连接,与静态库不同的是,程序运行时需要动态库的支持,如果找不到相应的动态库,程序运行会报错。下面介绍具体的操作。

 

1.静态库

编写一个简单的库源文件foo.c

#include <stdio.h>
#include "foo.h"

void foo_print(void)
{  
    printf("foo_print called\n");  
}

头文件foo.h中声明接口

#ifndef __FOO_H__
#define __FOO_H__

void foo_print(void);

#endif /*__FOO_H__*/

$ gcc -c foo.c

-c选项代表只进行编译(compile)不进行连接,此时当前路径下会出现一个foo.o

$ ar crv libfoo.a foo.o

使用ar命令后,会生成一个libfoo.a的文件,这就是我们需要的静态库文件了

 

编写一个test.c用于测试,在主函数中调用foo.h中声明的接口

#include "foo.h"

int main(void)
{
    foo_print();
    return 0;  
}

使用命令编译

$ gcc -o test test.c -L. -lfoo

此时便生成了可执行文件test。在此需要说明,使用ar命令生成静态库文件时,必须使用libXXX.a的格式,否则在编译可执行文件时会提示"cannot find lXXX",这应该是因为gcc编译连接库文件时,使用字符串匹配文件名的方式查找库文件(猜测)。编译使用 -L. 选项说明连接库的查找路径为当前路径。

 

2.动态库

仍然使用上面的几个源程序,生成动态库需要以下操作。

$ gcc -c -fPIC foo.c

这里-fPIC代表编译时生成位置无关的代码(Position Independet Code),关于-fPIC分析请看gcc编译参数-fPIC的一些问题

$ gcc -shared -o libfoo.so foo.o

这样就生成了我们需要的动态库文件libfoo.so,接下来编译主程序。

$ gcc -o test test.c -L. -lfoo

生成test可执行文件后,也许执行时会出现错误提升"error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory",我们使用ldd命令查看test的连接信息。

$ ldd test

libfoo.so => not found

原来是运行的时候没有找到动态库的位置,为了解决这个问题,我们可以将.so文件放入默认的搜索路径中,或者可以设置环境变量LD_LIBRARY_PATH。

$ export LD_LIBRARY_PATH=.

这样程序执行时,会先在设置的LD_LIBRARY_PATH路径下查找库文件,再到默认的路径中搜索。

还有一种办法,将路径写入可执行文件中:

$ gcc -o test test.c -L. -lfoo -Wl,-rpath=.

-Wl 选项代表向链接器传递参数,这里传递的参数为rpath,即Runtime Path,由于将路径写如可执行程序,每当路径发生改变时,需要重新进行编译。 

 

  在编译可执行程序时还需注意,当对静态库或动态库进行链接时,如果路径下同时包含同名的库,如foo.a foo.so,那么链接时会默认使用动态库进行链接,在这种情况下,可以使用 -static 选项显式地对静态库进行链接。    

  静态库和动态库在编各有优势,静态库可以使得程序在运行时对库没有依赖,不需要动态加载库,也就意味着某些情况下执行效率更高。而动态库可以在保持API不变的情况下改变具体实现,方便版本升级,而不必对整个工程进行编译;可以在不同进程执行时,共用动态库在内存中的拷贝,节省系统内存资源。具体的选择还要根据需求来确定。

 

参考

《Linux 程序设计(第4版)》

gcc编译参数-fPIC的一些问题:http://www.cnblogs.com/vamei/archive/2013/04/04/2998850.html

posted on 2016-03-20 21:26  陈狗蛋儿  阅读(292)  评论(0编辑  收藏  举报

导航