在理解链接(Linking)这一编译过程中的步骤之前,有必要了解编译器的整体工作流程。编译器通常经历以下几个阶段:
-
预处理(Preprocessing):处理源代码文件中的预处理指令,如
#include
指令,它们通常涉及插入头文件的内容。 -
编译(Compilation):将预处理后的源代码转换为汇编代码,然后进一步转换为机器码,生成对象文件(
.o
或.obj
文件)。 -
链接(Linking):最后一步是链接,这一步将编译生成的一个或多个对象文件与库文件合并,生成可执行文件。
静态链接(Static Linking)
-
定义:静态链接是在链接阶段将所有必需的库函数的代码直接拷贝到最终的可执行文件中。这意味着程序在运行时不需要外部的库文件,因为所有必需的代码都已经包含在内。
-
文件类型:在 Unix/Linux 系统上,静态库通常有
.a
(Archive)后缀;在 Windows 系统上,通常是.lib
。 -
优缺点:静态链接的可执行文件通常较大,因为包含了所有必需的库代码,但它们不依赖于外部库文件,可以在没有这些库文件的系统上运行。
动态链接(Dynamic Linking)
-
定义:动态链接不是将库函数的代码拷贝到可执行文件中,而是在程序运行时从共享库(动态链接库)中加载所需的函数。这意味着可执行文件在运行时依赖于外部的库文件。
-
文件类型:在 Unix/Linux 系统上,动态库文件通常有
.so
(Shared Object)后缀;在 Windows 上,它们是.dll
(Dynamic Link Library)文件。 -
优缺点:动态链接的可执行文件通常较小,因为它们不包含整个库的代码。动态链接还允许多个程序共享内存中同一份库代码,节省空间。但这也意味着运行程序时必须确保相应的库文件可用和兼容。
通过 make
实现编译和链接
在使用 make
管理构建过程时,Makefile
文件中会指定如何编译源代码并将其链接成最终的可执行文件。例如:
all: programprogram: main.o libmath.agcc -o program main.o -L. -lmathmain.o: main.cgcc -c main.clibmath.a: math.oar rcs libmath.a math.omath.o: math.cgcc -c math.c
在上面的 Makefile
中,main.o
是主程序的编译产物,libmath.a
是一个静态库文件。链接步骤中,gcc
编译器用 -L
指定库文件路径,用 -l
指定要链接的库。这个例子展示了静态链接的过程。对于动态链接,过程类似,但涉及的是 .so
或 .dll
文件而非 .a
或 .lib
文件。