How Makefile works

Bash

在 C 编程中,经常会用到 Makefile 来对源代码进行编译。一个简单的 Makefile 如下:

out: input.c
  $(CC) input.c -o out -Wall -Wextra -std=c99

这里,第一行的 out: input.c 表示 make 应该根据输入 input.c 来产出 out 这个文件。

第二行的 $(CC) 会由 make 替换成本机的 cc 程序(即 c compiler);后面跟着的是 cc 编译会用到的参数,包括输入源文件 input.c,输出文件 out,编译输出所有的 Warning(-WallWarning all-WextraWarning extra),同时指定使用 C99 标准来编译 C 代码(和 ANSI C 相比,C99 允许在函数的任意位置定义变量,而不是必须在顶部)。

运行 make 命令,程序会查找当前目录下的 Makefile 函数,读取其中的配置,根据输入输出的要求,查找文件,然后再选择编译。

第一次编译,程序会用 input.c 编译出一个 out 文件来。

input.c 没有修改的情况下,如果再运行一次 make 命令,会得到如下的输出:

make: `out` is update to date.

这里,make 程序并没有通过任何外部文件的方式记录编译的情况。判断是否需要编译完全依赖于系统默认的文件功能,即简单的比较 input.cout 两个文件的最后修改时间。如果 out 的最后修改时间比 input.c 要晚,就认为 out 是最新的,不再重复编译;如果 input.c 的最后修改时间晚于 out 的时间,或是 out 压根就不存在,那么 make 就会执行 Makefile 中配置的编译命令。

可以通过以下方式欺骗 Makefile 来检查这一行为:

  1. 修改一下 input.c 并保存
  2. 删除 out 文件,然后用 touch 命令创建一个空的 out 文件。因为是先修改,再创建,所以 out 的创建时间会晚于 input.c
  3. 尝试执行 make 命令,会发现提示 out 已经是最新的,并没有执行真正的编译命令(尽管这里 out 并不是通过 make 编译出来的)