linux下生成静态库和动态库

转自:https://blog.csdn.net/ddreaming/article/details/53096411


一、动态库、静态库简介

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:

静态库.a(win 系统下是lib)和动态库.so(win 系统下是.dll)。所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:



静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库






静态库特点总结:

静态库对函数库的链接是放在编译时期完成的。

程序在运行时与函数库再无瓜葛,移植方便。

-浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在


动态库特点总结:

动态库把对一些库函数的链接载入推迟到程序运行的时期。

可以实现进程之间的资源共享。(因此动态库也称为共享库)

将一些程序升级变得简单。

甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。


文主要通过举例来说明在 Linux 中如何创建静态库和动态库,以及使用它们。

[ps:在windows平台和linux平台下都大量存在着库。由于windowslinux的平台不(主要是编译器、汇编器和连接器的不同),因此二者库的二进制是不兼容的。本文仅限于介绍 linux 下的库。]


二、用gcc生成静态和动态链接库的示例

首先,本文主要通过举例来说明在 Linux 中如何创建静态库和动态库,以及使用它们。为了便于阐述,我们先准备下测试代码:hello.h、hello.c、main.c(我将这三个代码放在一个名为‘静态链接’的文件夹中)。如下所示

hello.h

  1. #ifndef HELLO_H  
  2. #define HELLO_H  
  3. void hello(const char* name);  
  4. #endif  

hello.c

  1. #include <stdio.h>  
  2. void hello(const char* name){  
  3.     printf("hello %s! \n",name);  
  4. }  
main.c
  1. #include "hello.h"  
  2. int main(){  
  3. hello("everyone");  
  4. return 0;  
  5. }  

注意:这个时候,hello.c 是无法通过gcc –o 编译,这个道理非常简单,hello.c 是一个没有main函数的.c程序,因此不够成一个完整的程序,如果使用gcc –o编译并连接它,gcc 将报错。

(ps:gcc -o 与gcc -c 的区别。gcc–o  是将.c源文件编译成为一个可执行的二进制代码,这包括调用作为 GCC 内的一部分真正的 C 编译器( ccl ),以及调用GNU C编译器的输出中实际可执行代码的外部 GNU 汇编器和连接器工具。g -c是使用GNU汇编器将源文件转化为目标代码之后就结束,在这种情况下连接器并没有被执行,所以输出的目标文件不会包含作为 Linux 程序在被装载和执行时所必须的包含信息,但它可以在以后被连接到一个程序)

其实,我们的问题就是,如何让main.c中能使用hello这个函数。这时候我们有三种思路:

1、通过编译多个源文件,直接将目标代码合成一个.o 文件。

2、 通过创建静态链接libmyhello.a ,使得 main 函数调用 hello 函数时可调用静态链接库。

3、 通过创建动态链接库libmyhello.so ,使得 main 函数调用 hello 函数时可调用静态链接库


下面分别进行演示。

1.通过编译多个源文件,直接将目标代码合成一个.o 文件.首先利用gcc -c指令将hello.c和main.c编译生成hello.o和main.o文件,再用gcc -o指令将hello.o和main.o文件生成一个可执行文件hello。具体如下图所示:



2.通过创建静态链接库libmyhello.a ,使得main函数调用hello函数时可调用静态链接库。

下面我们先来看看如何创建静态库,以及使用它。Linux静态库命名规范,必须是"lib[your_library_name].a"lib为前缀,中间

是静态库名,扩展名为.a例如:我们将创建的静态库名为 myhello ,静态库文件名就是 libmyhello.a。在创建和使用静态库时,

需要注意这点。Linux创建静态库分为两步:

第一步:将代码文件编译成目标文件。即将hello.c文件编译成hello.o文件,使用指令是:gcc -c hello.c

第二步:利用ar工具将目标文件hello.o打包成静态库文件.a(注意命名规则,我的静态库文件名为:libmyhello.a)

具体如下图所示:

现在我们已经生成了静态库文件libmyhello.a了,下面就是怎么使用它。Linux下使用静态库,只需要在编译的时候,指定静态库的

搜索路径(-L选项)、指定静态库名(不需要lib前缀和.a后缀,-l选项)。

指令:

 gcc -o hello main.c -L/Users/wangxuewei/Desktop/静态链接 -lmyhello

指令可以这么解释:利益gcc -o指令,将main.c编译成可执行文件hello。其中main.c函数中要使用的函数,存储在静态链接库

libmyhello.a 。"-L/Users/wangxuewei/Desktop/静态链接"是该静态库文件所在地址,"-lmyhello"表示的是要使用的静态库文

件的名字,看起来怪怪的哈,因为它不需要制定前缀lib和后缀.a,所以就变成了myhello,-l则是指令标示符号。

[ps:关于gcc指令中的-l和-L参数问题。-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so(.o),很容易看出,把库文件名的头lib和尾.so/.o去掉就是库名了。放在/lib/usr/lib/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest


进一步可以删除静态函数libmyhello.a,然后运行hello函数,看看其是否真的链接到了目标函数.




3、 通过创建动态链接库libmyhello.so ,使得 main 函数调用 hello 函数时可调用静态链接库

linux动态库的命名规则

动态链接库的名字形式为 libxxx.so,前缀是lib,后缀名为“.so”。

l  针对于实际库文件,每个共享库都有个特殊的名字“soname”。在程序启动后,程序通过这个名字来告诉动态加载器该载入哪个共享库。

l  在文件系统中,soname仅是一个链接到实际动态库的链接。对于动态库而言,每个库实际上都有另一个名字给编译器来用。它是一个指向实际库镜像文件的链接文件(lib+soname+.so)。

创建动态库(.so)可以分为两步:

第一步:生成目标文件,此时要加编译器选项-fPIC。[ps:-fPIC是创建与地质无关的编译程序,是为了能够在多个应用程序间共享]

  1. gcc -fPIC -c hello.c  

第二步:生成动态库,此时要加链接器选项-shared。[ps:-shared是指定生成动态链接库]

  1. gcc -shared -o libmyhello.so hello.o  
以上两步也可以写成一条指令:

  1. gcc -shared -fPCI -o libmyhello.so hello.c  

运行该指令后会生成一个libmyhello.so文件,如下图:


使用动态链接库
引用动态链接库,和静态库一样,在编译时指定动态链接库就好

  1. gcc main.c -L. -lmyhello  
-L.  代表动态库在当前路径下;-l后面跟的是动态链接库的名字( 与静态一样,可以舍去前缀lib和后缀.so

执行该指令后,会生成一个a.out的可执行文件,可以执行下看看:


可以看到,是可以执行的!!但是,在网上看,很多博客说这样是不可以的,因为:库文件在连接(静态库和动态库)和运行(仅限于使用动态库的程序)时被使用,其搜索路径是在系统中进行设置的。一般Linux系统把/lib /usr/lib(也可能是/usr/local/lib)三个目录作为默认的库搜索路径,所以使用这两个目录中的库时不需要进行设置路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到搜索路径之中。但是,我电脑中,当动态库与执行程序在同一目录下时,也可以运行,可能是因为我用的mac吧,暂时没弄清楚。。。不过可以确定,当将动态库libmyhello.so移动到/usr/local/lib时,a.out仍可正常运行。


更一般的,对于处于默认路径之外的库,如何让系统找到它呢?一般有两种方法:

1.将动态库复制到/lib 或 /usr/lib 或 /usr/local/lib中。就像我上面做的一样,将libmyhello.so复制到/usr/local/lib中,这是系统是可以找到的。

2.如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

2.1 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径

2.2 运行ldconfig ,该命令会重建/etc/ld.so.cache文件

[ps:第二种方法我没有试,因为mac系统里好像跟这个不太一样,还在研究中。。。具体可以参考下面几篇文章,解释的比较详细]

参考:
http://www.cppblog.com/deane/archive/2012/08/01/165216.html

http://www.cnblogs.com/skynet/p/3372855.html

http://blog.163.com/hitperson@126/blog/static/130245975201151552938133

http://www.aichengxu.com/view/10712254

猜你喜欢

转载自blog.csdn.net/qq_39584315/article/details/80311454
今日推荐