静态库和动态库的简介和制作
1.简介
公用函数库的程序文件(.c文件)是源代码,对任何程序员是可见的,没有安全性可言,但是,在实际开发中,出于技术保密或其它方面考虑,开发者并不希望提供公用函数库的源代码。
C/C++提供了一个可以保证代码安全性的方法,把公共的程序文件编译成库文件,库文件是一种可执行代码的二进制形式,可以与其它的源程序一起编译,也可以被操作系统载入内存执行。
库文件分为静态库与动态库,区别如下:
静态库:静态链接库在链接时,编译器会将目标文件和静态库文件组织成一个可执行文件,程序运行时,将全部数据加载到内存。
如果程序体积较大,功能较为复杂,那么加载到内存中的时间就会比较长,最直接的一个例子就是双击打开一个软件,要很久才能看到界面。这是静态链接库的一个弊端。
动态库相比静态库的区别是:静态库是编译时就加载到可执行文件中的,而动态库是在程序运行时完成加载的,所以使用动态库的程序的体积要比使用静态库程序的体积小,并且使用动态库的程序在运行时必须依赖所使用的动态库文件(.so文件),而使用静态库的程序一旦编译好,就不再需要依赖的静态库文件了(.a文件)。
动态库源代码修改后,只需要编译动态库文件即可,程序不需要重新编译。
静态库源代码修改后,静态库需要重新编译,程序也要重新编译。
如果在动态库文件和静态库文件同时存在,优先使用动态库编译。
静态库文件名的命名方式是“libxxx.a”,库名前加”lib”,后缀用”.a”,“xxx”为静态库名。windows也这么命名。
动态库与静态库类似,前缀相同,为“lib”,后缀变为“.so” ,如“libxxx.so”。windows下动态库的后缀为.dll
这篇文章,写得很好,可以看看。
2.静态库和动态库的制作
2.1 程序
// add.h
int add(int i, int j);
// add.c
#include "add.h"
int add(int i, int j)
{
return i + j;
}
// main.c
#include <stdio.h>
#include <stdlib.h>
#include "add.h"
int main(int argc, char *argv[])
{
printf("1 + 2 = %d\n", add(1, 2));
return 0;
}
2.2 动态库的制作和使用
# 编译共享库
gcc add.c -fPIC -shared -o libadd.so # -fPIC:生成位置无关目标代码,适用于动态连接;
# -shared:生成一个共享库文件;
# 编译和运行
gcc -Wl,-rpath=`pwd` main.c -L . -l add -o app # pwd代表当前路径
# "-L ."代表链接阶段在当前目录下查找库
# -Wl,-rpath代表运行时,在哪里找库。
# gcc -Wl,-rpath=`pwd` main.c -L. -ladd -o app # 与gcc -Wl,-rpath=`pwd` main.c -L . -l add -o app 等价
./app
输出:
1 + 2 = 3
我们可以看到在编译的时候需要使用-L和-l指明动态库的位置,运行时还需要使用-Wl,-rpath指明动态库的位置。这是因为:
动态库在编译的时候只做语法检查, 并没有被编译进目标代码,当程序执行到动态库中的函数时才调用该函数库里的代码。
动态函数库并没有整合进程序,所以程序的运行环境必须提供动态库路径。优点是,如果所使用的动态库发生更新改变,程序不需要重新编译,所以动态库升级比较方便。
所以如果在动态库文件和静态库文件同时存在,优先使用动态库编译。
2.3 静态库的制作和使用
gcc -c add.c -o libadd.a # 静态库的制作
静态库的使用:
方法一:
gcc main.c libadd.a -o app # 直接把调用者源代码和静态库文件名一起编译。
./app
方法二:
gcc -L . -l add main.c -o app # 采用L参数指定静态库文件的目录,-l参数指定静态库名。
./app
可见,静态库和动态库都是通过-L和-l指定路径的。
在静态库制作的过程中使用到了gcc -c,我们可以通过链接知道它的含义为:将代码编译成二进制文件。