了解动态库和静态库之前,先了解动态库和静态库。
编译过程可以划分为四个阶段:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)以及链接(Linking)。下面的四步内容不必深究,知道这么回事就行。
预处理主要做下面的几个操作:
(1)宏的处理
可以看下面的链接。
C++宏的作用-CSDN博客
(2)添加行号信息、文件名标识,便于调试
(3)删除注释
等等,这步完成之后,生成.i文件。
编译主要做下面的操作:
(1)语法分析,查看是否有语法错误
(2)生成汇编代码
等等,这步完成生成.s文件。
事实上,这一步骤最为消耗系统资源和时间。
汇编主要做下面的操作:
(1)将汇编指令翻译成机器指令,也就是二进制文件
等等,生成.o文件
链接主要做下面的操作:
(1)合并各个文件
(2)地址回填
以hello.c源文件为例:
(1)只执行预处理,输出hello.i
gcc -E hello.c
(2)只执行预处理、编译,输出hello.s
gcc -S hello.i
这步消耗时间,系统资源最大。
-S只执行预处理、编译。
(3)只进行汇编,输出hello.o,即目标文件。
gcc -c hello.s
-c只进行预处理、编译、汇编
(4)只进行链接,输出hello.out,即可执行程序。
gcc test.o
(5)一步到位,并且-o是将文件名改为后面参数的名字
gcc hello.c -o hello
(6)-I(大写的i)指定头文件路径
如果头文件和源文件不在同一级目录下,则需要加头文件的路径。
(7)-Wall,显示更多警告信息。
库是一个二进制可执行的文件。库需要加载到内存中使用。
库的作用有:
1.库是已经写好的,成熟的,可以复用的功能代码,我们写的很多代码都是依赖于基础库。
2.提高代码移植效率,可以不用移植源码,直接移植库即可。
静态库在程序编译时会被连接到目标代码中,把库直接加载到程序中,程序运行时将不再需要该静态库。每有一个可执行文件就需要一个静态库的载入。
动态库在程序编译时并不会被连接到目标代码中,在链接的时候,它只是保留接口,将动态库与程序代码独立,在程序运行时才被载入,因此在程序运行时还需要动态库存在。动态库可以在程序间共享,因此又称共享库。
因此,静态库相较动态库速度较快,但内存要求较高。动态相较速度较慢,但内存需求低。
例如,下面是我staticFile文件夹下的文件。
//add.c
int add(int value1,int value2)
{
return value1+value2;
}
//minus.c
int minus(int value1,int value2)
{
return value1-value2;
}
查看如下:
将add.c和minus.c两个文件编译,成为目标文件。运行下面的命令:
gcc -c add.c -o add.o
gcc -c minus.c -o minus.o
查看如下:
Linux的静态库文件格式为:lib+库名+.a。
运行下面的命令:
ar rcs libmymath.a add.o minus.o
查看如下:
假如有一个源文件使用咱们制作的静态库。该源文件如下:
#include
int main()
{
int value1=8;
int value2=4;
printf("value1+value2=%d\n",value1+value2);
printf("value1-value2=%d\n",value1-value2);
return 0;
}
输入下面的命令:
gcc test.c libmymath.a -o test
得到了咱们的可执行程序test:
运行:
而且test生成后,我们可以将libmymath.a删除,test照常运行。
此时运行下面的命令:
gcc test.c libmymath.a -o test -Wall
可能会出现下面的警告:
至于说为什么是可能呢,因为我的没警告 ,上面的图是我从别人那q来的:
但为了防止警告,还得加下面的内容:
再创建一个头文件,实际上这个头文件是库的配套产品,制作库的同时需要制作头文件,在使用时加上头文件,另外再输入gcc test.c libmymath.a -o test命令,完成最终的程序。
头文件如下:
#ifndef _MYMATH_H_
#define _MYMATH_H_
int add(int,int);
int minus(int,int);
#endif
程序源文件改为:
#include
#include"mymath.h"//多加了这一行
int main()
{
int value1=8;
int value2=4;
printf("value1+value2=%d\n",value1+value2);
printf("value1-value2=%d\n",value1-value2);
return 0;
}
然后再编译执行,结果:
因为动态库是运行时加载到内存的,因此动态库的地址不固定。为了生成与位置无关的代码,我们需要再编译时加上-fPIC。现文件夹下有下面的内容:
输入下面的命令:
gcc -c add.c -o add.o -fPIC
gcc -c minus.c -o minus.o -fPIC
结果如下:
Linux动态库的格式:lib+库名+.so
输入下面的命令:
gcc -shared -o libmymath.so add.c minus.c
因为动态库是运行时链接的,所以需要运行时指定动态库所在目录位置。因此,Linux中以设置环境变量来解决该问题。
临时方法:
export LD_LIBRARY_PATH=动态库路径
永久方法:
修改~/.bashrc文件,加入上面的语句。
gcc的可选项-l(小写的L),指定库名。-L,指定库文件路径。
注意库名是lib后面,.so之前的内容,这里是mymath。
输入下面的命令:
gcc test.c -o test -l mymath -L ./ -I ./
输入./test运行: