静态库和动态库的制作
程序
// 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
#include
#include "add.h"
int main(int argc, char *argv[])
{
printf("1 + 2 = %d\n", add(1, 2));
return 0;
}
动态库的制作和使用
# 编译共享库
gcc add.c -fPIC -shared -o libadd.so # -fPIC:生成位置无关目标代码,适用于动态连接;
# -shared:生成一个共享库文件;
# 编译和运行
gcc -Wl,-rpath=`pwd` main.c -L. -ladd -o app # pwd代表当前路径
# "-L ."代表链接阶段在当前目录下查找库
# -Wl,-rpath代表运行时,在哪里找库。
./app
输出:
1 + 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
参考:C/C++编译以及静态库和动态库的制作和使用
可见,静态库和动态库都是通过-L和-l指定路径的。
在静态库制作的过程中使用到了gcc -c,我们可以通过链接明白它的含义。
补充
公用函数库的程序文件add.c程序文件是源代码,对任何程序员是可见的,没有安全性可言,但是,在实际开发中,出于技术保密或其它方面考虑,开发者并不希望提供公用函数库的源代码。
C/C++提供了一个可以保证代码安全性的方法,把公共的程序文件编译成库文件,库文件是一种可执行代码的二进制形式,可以与其它的源程序一起编译,也可以被操作系统载入内存执行。
库文件分为静态库与动态库。
区别:
静态库源代码修改后,静态库需要重新编译,程序也要重新编译。
动态库源代码修改后,只需要编译动态库文件即可,程序不需要重新编译。
如果在动态库文件和静态库文件同时存在,优先使用动态库编译。
静态库文件名的命名方式是“libxxx.a”,库名前加”lib”,后缀用”.a”,“xxx”为静态库名。
与静态库类似,前缀相同,为“lib”,后缀变为“.so” “xxx”为动态库名。
我们可以看到在编译的时候需要使用-L和-l指明动态库的位置,运行时需要使用-Wl,-rpath指明动态库的位置。这是因为:
动态库在编译的时候只做语法检查, 并没有被编译进目标代码,当程序执行到动态库中的函数时才调用该函数库里的代码。
动态函数库并没有整合进程序,所以程序的运行环境必须提供动态库路径。优点是,如果所使用的动态库发生更新改变,程序不需要重新编译,所以动态库升级比较方便。
如果在动态库文件和静态库文件同时存在,优先使用动态库编译。
参考:C/C++编译以及静态库和动态库的制作和使用
-fPIC选项
通常在linux下用gcc编译动态库时都会加上一个-fPIC选项来生成位置无关代码。但是如果你的静态库可能会被动态库使用,那么静态库编译的时候就也需要-fPIC选项。
原理分析
众所周知,静态库其实是一系列.o文件的打包,将.o文件制作成静态库的过程是不会发生链接的。
所以链接静态库就约等于将静态库解包后的.o文件一个一个全部链接。
-fPIC选项的生效阶段在编译阶段,使用-fPIC选项编译的.o文件会生成位置无关的代码
如果一个动态库需要链接一个静态库,那么就相当于动态库去链接一系列的.o文件,而编译动态库所需的.o文件时一般是推荐使用-fPIC编译选项的。
参考:链接
具体的-fPIC是什么原理可以参考:动态库基本原理和使用方法,-fPIC选项的来龙去脉。-fPIC大概的原理就是:编译时构造全局偏移表(Global Offset Table, GOT),运行时通过GOT中存储的偏移值访问指令和数据。