1静态库和动态库概述

库是一种软件组件技术,库里面封装了数据和函数。库的使用可以使程序模块化。库有两种:静态库和动态库Windows系统包括静态链接库(.lib文件)和动态链接库(.dll文件)。Linux通常把库文件存放在/usr/lib或/lib目录下。Linux库文件名由:前缀lib、库名和后缀3部分组成,其中动态链接库以.so作为后缀,静态链接库通常以.a作为后缀

何为静态库和动态库?

静态库(Static library, Statically-linked library, LIB)或称静态链接库,是一个外部函数与变量的集合体。静态库的文件内容,通常包含一堆程序员自定的变量与函数,在编译期间由编译器与连接器将它集成至应用程序内,并制作成目标文件以及可以独立运作的可执行文件。而这个可执行文件与编译可执行文件的程序,都是一种程序的静态创建(static build)。其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。即静态库中的指令全部被直接包含在最终生成的可执行文件中。

动态库(Dynamic library, Dynamic-link library, DLL)或称动态链接库,是微软公司在微软视窗操作系统中实现共享函数库概念的一种实现方式。动态链接库可被多个程序同时使用。所谓动态链接,就是把一些经常会共用的代码(静态链接的OBJ程序库)制作成DLL档,当程序有需求时函数才进行链接。透过动态链接方式,存储器浪费的情形将可大幅降低。静态链接库则是直接链接到可执行文件。

一个程序编译成可执行的步骤:

《C语言杂记》静态库和动态库(Linux版)_静态库

静态库和动态库的区别在链接阶段如何处理库,如果将库链接到目标代码中则是静态库,而将库链接载入推迟到程序运行的时期则是动态库,可以实现进程之间的资源共享。





2 Linux创建和使用静态库

前面已经介绍了静态库的概念,下面我们通过一个实例来看静态库的使用。

2.1生成静态库

1)这里准备了两个库的源码st1 、st2用它们来制作库libmytest.a,如下


$ ls -l


《C语言杂记》静态库和动态库(Linux版)_动态链接库_02


$ cat st1.c


#include <stdio.h>
void print1()
{
printf("Hello!I am st1!\n ");
}


$ cat st2.c


#include <stdio.h>
void print2()
{
printf("Hello!I am st2!\n");
}


$ cat main.c


#include <stdio.h>
int main(int argc, const char *argv[])
{
print1();
print2();
return 0;
}

2)生成libmytest.a文件

创建静态库用ar命令,它将很多.o换成.a


$ gcc -c st1.c st2.c
$ ar crs libmytest.a st1.o st2.o
$ ls -l


《C语言杂记》静态库和动态库(Linux版)_动态库_03


$ file libmytest.a


《C语言杂记》静态库和动态库(Linux版)_动态库_04

静态库文件libmytest.a已经生成,用file命令查看其属性,发现它确实是归档压缩文件。用ar -t libmytest.a可以查看一个静态库包含了那些obj文件:


$ ar -t libmytest.a


《C语言杂记》静态库和动态库(Linux版)_静态库_05

2.2使用静态库

1.直接使用


$gcc -o test main.c libmytest.a


2.双L链接法

$gcc -o test main.c -lmytest -L.(库所在目录,.表示当前目录)

3.单L链接法(需要配置环境变量LIBRARY_PATH,把库放在所在目录配置)


$gcc -o test main.c -lmytest


前面我们已经写好了main.c,现在测试一下


$ gcc -o test main.c -L. -lmytest
$ ls -l


《C语言杂记》静态库和动态库(Linux版)_动态链接库_06


$ ./test


《C语言杂记》静态库和动态库(Linux版)_动态链接库_07

这里gcc的参数-L是告诉编译器库文件的路径是当前目录,-l是告诉编译器要使用的库的名字叫mytest。



2.3静态库总结

1.在一个头文件中声明静态库所导出的函数。

2.在一个源文件中实现静态库所导出的函数。

3.编译源文件,生成可执行代码。

4.将可执行代码所在的目标文件加入到某个静态库中,并将静态库拷贝到系统默认的存放库文件的目录下。

下面通过一个例子来说明:

源文件:mylib.c

#include <stdio.h>
void welcome(void)
{
printf("welcome to libmylib\n");
}

1>编译mylib.c生成目标文件:


$gcc -o mylib.o -c mylib.c


2>将目标文件加入到静态库中:


$ar -rcs libmylib.a mylib.o


【注】库文件名以lib开头,以.a结尾。

3>将静态库copy到Linux的库目录(/usr/lib或者/lib)下:(也可以不拷贝,注意配置环境变量)


$sudo cp libmylib.a /usr/lib/libmylib.a //管理员身份


编写调用库函数的测试程序test.c:

#include <stdio.h>
int main(void)
{
printf("create and use library:\n");
welcome();
return 0;
}

4>使用静态库编译:


$gcc -o test test.c -lmylib


这里注意,编译时无需带上前缀和后缀。

5>运行可执行程序test:


$./test


《C语言杂记》静态库和动态库(Linux版)_动态链接库_08

在Linux下,可以使用ar命令来创建和修改静态库。

这些在linux下man ar一下就可以得到参数,这里说明几个常用的

d:从库中删除成员文件。

r:在库中加入成员文件,若存在,则替换。

c:创建一个库。

s:无论ar命令是否修改了库内容,都强制重新生成库符号表。

其他的命令用时再man。

【注】gcc -static 文件.c [-o 文件]//全部使用静态库的方法





3 Linux创建和使用动态库

动态库的基本概念

1.动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。

2.动态链接库的名称有别名(soname), 真名(realname)和链接名(linker name)。别名由一个前缀lib,然后是库的名字,再加上一个后缀“.so”构成(“libxxx.so”)。真名是动态链接库真实名称,一般总是在别名的基础加上一个小版本号,发布版本等构成。除此之外,还有一个链接名,即程序链接时使用的库的名字。

3.在动态链接库安装的时候,总是复制文件到某个目录下,然后用一个软连接生成别名,在库文件进行更新的时候,仅仅更新软链接即可。

下面我们通过一个实例来学习如何生成动态库和使用动态库。

3.1生成动态库

1)当前文件夹下有下面四个文件


$ ls -l


《C语言杂记》静态库和动态库(Linux版)_动态库_09

文件内容分别为:


$ cat mylib.h


#ifndef _MYLIB_H_
#define _MYLIB_H_
#include <stdio.h>
void print1();
void print2();
#endif


$ cat dy1.c


#include "mylib.h"
void print1()
{
printf("My first shared lib!\n");
}


$ cat dy2.c


#include "mylib.h" 
void print2()
{
printf("My second shared lib!\n");
}


$ cat main.c


#include "mylib.h"  

int main(int argc, char *argv[])
{
print1();
print2();
return 0;
}

2)这里我们将dy1.c与dy2.c用来创建动态库


$ gcc -fPIC -Wall -c dy1.c dy2.c
$ gcc -shared -o libtest.so dy1.o dy2.o


这里 -fPIC 创建与地址无关的编译程序,-shared指定生成动态链接库。

我们也可以一步到位


$ gcc -o libtest.so -fPIC -shared dy1.c dy2.c


我们可以看到下面已经生成了一个libtest.so


$ ls -l


《C语言杂记》静态库和动态库(Linux版)_动态链接库_10

3.2使用动态链接库

在编译程序时,使用动态链接库和静态库是一致的,使用”-l库名”的方式,在生成可执行文件的时候会链接库文件。使用如下命令:


$ gcc -o test main.c -L. -ltest
$ ls -l


《C语言杂记》静态库和动态库(Linux版)_动态库_11

这里 -L 指定动态链接库的路劲,-ldtest链接库函数test 。-ltest是动态库的调用规则。Linux系统下的动态库命名方式是lib*.so,而在链接时表示位-l*,*是自己命名的库名。

我们可以看到这里已经生成了test可执行文件,我们可以执行一下:

$ ./test

《C语言杂记》静态库和动态库(Linux版)_动态库_12

可以发现发生了错误,这是因为程序运行时没有找到动态链接库造成的。程序编译时链接动态库和运行时使用动态链接库的概念是不同的,在运行时,程序链接的动态链接库需要在系统目录下才行。

这就到了动态库的路径问题,有三种方法:

1)把库拷贝到/usr/lib和/lib目录下:


$ sudo cp libtest.so /lib


【注】这里要超级用户权限sudo

我们看一下执行结果:


$ ./test


《C语言杂记》静态库和动态库(Linux版)_动态链接库_13

这里执行结果正确。

2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径


$ export LD_LIBRARY_PATH=​​pwd​​:$LD_LIBRARY_PATH


我们可以看到:libtest.so 的路径已经存在


$ ldd test


《C语言杂记》静态库和动态库(Linux版)_动态链接库_14

我们可以看一下结果:


$ ./test


《C语言杂记》静态库和动态库(Linux版)_动态库_15

也能得到正确结果。

3)添加/etc/ld.so.conf.d/*.conf文件。把库所在的路径加到文件末尾,并执行ldconfig刷新。


$ cd /etc/ld.so.conf.d/
$ ls


《C语言杂记》静态库和动态库(Linux版)_动态库_16


$ sudo vi my.conf
$ cat my.conf


/home/bruceou/demo/libtest.so

在/etc/ld.so.conf.d/下建立my.conf 里面只有一句/home/bruceou/demo/libtest.so即libtest.so的路径,然后执行ldconfig刷新即可。



3.3动态库总结

1.编译动态库

方法一:

命令:gcc -fPIC -Wall -c < filename>.c

命令:gcc -shared -o lib< name>.so < filename>.o

方法二:

命令:gcc < file1>.c < file2>.c < filen>.c -fPIC -shared -o lib< name>.so

2.安装路径

命令:cp lib< name>.so /usr/lib/lib< name>.so//管理员身份

3.动态库的链接

命令:gcc -o < preject_name> < tag_name>.c -L. -l< name>

或者:命令:gcc < tag_name>.c -L. -l< name> -o < preject_name>

4.运行可执行程序


 

欢迎订阅我的微信公众号

《C语言杂记》静态库和动态库(Linux版)_动态库_17