共计 4199 个字符,预计需要花费 11 分钟才能阅读完成。
导读 | 库是一种软件组件技术,库里面封装了数据和函数。库的使用可以使程序模块化。库有两种:静态库和动态库。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 档,当程序有需求时函数才进行链接。透过动态链接方式,存储器浪费的情形将可大幅降低。静态链接库则是直接链接到可执行文件。
一个程序编译成可执行的步骤:
静态库和动态库的区别在链接阶段如何处理库,如果将库链接到目标代码中则是静态库,而将库链接载入推迟到程序运行的时期则是动态库,可以实现进程之间的资源共享。
前面已经介绍了静态库的概念,下面我们通过一个实例来看静态库的使用。
1)这里准备了两个库的源码 st1、st2 用它们来制作库 libmytest.a,如下
$ ls -l
$ cat st1.c
#includevoid print1()printf("Hello!I am st1!\n");
$ cat st2.c
#includevoid print2()printf("Hello!I am st2!\n");
$ cat main.c
#includeint main(int argc, const char *argv[])print1();print2();return 0;
创建静态库用 ar 命令,它将很多.o 转换成.a
$ gcc -c st1.c st2.c
$ ar crs libmytest.a st1.o st2.o
$ ls -l
$ file libmytest.a
静态库文件 libmytest.a 已经生成,用 file 命令查看其属性,发现它确实是归档压缩文件。用 ar -t libmytest.a 可以查看一个静态库包含了那些 obj 文件:
$ ar -t libmytest.a
直接使用
$gcc -o test main.c libmytest.a
双 L 链接法
$gcc -o test main.c -lmytest
-L.(库所在目录,. 表示当前目录)
单 L 链接法(需要配置环境变量 LIBRARY_PATH,把库放在所在目录配置)
$gcc -o test main.c -lmytest
前面我们已经写好了 main.c,现在测试一下
$ gcc -o test main.c -L. -lmytest
$ ls -l
$ ./test
这里 gcc 的参数 - L 是告诉编译器库文件的路径是当前目录,- l 是告诉编译器要使用的库的名字叫 mytest。
在一个头文件中声明静态库所导出的函数。
在一个源文件中实现静态库所导出的函数。
编译源文件,生成可执行代码。
将可执行代码所在的目标文件加入到某个静态库中,并将静态库拷贝到系统默认的存放库文件的目录下。
下面通过一个例子来说明:
源文件:mylib.c
#includevoid 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:
#includeint main(void)printf("create and use library:\n");welcome();return 0;
4> 使用静态库编译:
$gcc -o test test.c -lmylib
这里注意,编译时无需带上前缀和后缀。
5> 运行可执行程序 test:
$./test
在 Linux 下,可以使用 ar 命令来创建和修改静态库。
这些在 linux 下 man ar 一下就可以得到参数,这里说明几个常用的
其他的命令用时再 man。
【注】gcc -static 文件.c [-o 文件]// 全部使用静态库的方法
动态库的基本概念
动态库的基本概念
1. 动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。
2. 动态链接库的名称有别名(soname), 真名 (realname) 和链接名(linker name)。别名由一个前缀 lib, 然后是库的名字,再加上一个后缀“.so”构成(“libxxx.so”)。真名是动态链接库真实名称,一般总是在别名的基础加上一个小版本号,发布版本等构成。除此之外,还有一个链接名,即程序链接时使用的库的名字。
3. 在动态链接库安装的时候,总是复制文件到某个目录下,然后用一个软连接生成别名,在库文件进行更新的时候,仅仅更新软链接即可。
下面我们通过一个实例来学习如何生成动态库和使用动态库。
1)当前文件夹下有下面四个文件
$ ls -l
文件内容分别为:
$ cat mylib.h
#ifndef _MYLIB_H_#define _MYLIB_H_#includevoid 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
在编译程序时,使用动态链接库和静态库是一致的,使用”- l 库名”的方式,在生成可执行文件的时候会链接库文件。使用如下命令:
$ gcc -o test main.c -L. -ltest
$ ls -l
这里 -L 指定动态链接库的路劲,-ldtest 链接库函数 test。-ltest 是动态库的调用规则。Linux 系统下的动态库命名方式是 lib*.so, 而在链接时表示位 -l*,* 是自己命名的库名。
我们可以看到这里已经生成了 test 可执行文件,我们可以执行一下:
$ ./test
可以发现发生了错误,这是因为程序运行时没有找到动态链接库造成的。程序编译时链接动态库和运行时使用动态链接库的概念是不同的,在运行时,程序链接的动态链接库需要在系统目录下才行。
这就到了动态库的路径问题,有三种方法:
1)把库拷贝到 /usr/lib 和 /lib 目录下:
$ sudo cp libtest.so /lib
【注】这里要超级用户权限 sudo
我们看一下执行结果:
$ ./test
这里执行结果正确。
2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径
$ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
我们可以看到:libtest.so 的路径已经存在
$ ldd test
我们可以看一下结果:
$ ./test
也能得到正确结果。
3)添加 /etc/ld.so.conf.d/*.conf 文件。把库所在的路径加到文件末尾,并执行 ldconfig 刷新。
$ cd /etc/ld.so.conf.d/
$ ls
$ 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 刷新即可。
1. 编译动态库
方法一:
命令:
gcc -fPIC -Wall -c .c
命令:
gcc -shared -o lib.so .o
方法二:
命令:
gcc .c .c .c -fPIC -shared -o lib.so
2. 安装路径
命令:
cp lib.so /usr/lib/lib.so// 管理员身份
3. 动态库的链接
命令:
gcc -o .c -L. -l
或者:
命令:gcc .c -L. -l -o
4. 运行可执行程序