4. 多规则 Makefile

本节课我们讲解多规则 Makefile 的编写。

上节课使用 gcc -o hello hello.c 命令将 hello .c 编译成 hello 文件看似编译过程是这样的:

+---------+                     +-------+
| hello.c | ------------------> | hello |
+---------+                     +-------+

而实际编辑过程中会生成目标文件 hello.o,也就是说命令 gcc -o hello hello.c 实际是由 gcc -o hello.o -c hello.cgcc -o hello hello.o 两条命令组合而成。

实际编译过程如下图所示:

+---------+     +---------+     +-------+
| hello.c | --> | hello.o | --> | hello |
+---------+     +---------+     +-------+

我们改写 Makefile 文件如下:

hello : hello.o
    gcc -o hello hello.o

hello.o : hello.c
    gcc -o hello.o -c hello.c

上述 Makefile 文件中有两个规则,其中规则 hello : hello.o 通过 hello.o 生成 hello;而规则 hello.o : hello.c 则是通过 hello.c 生成 hello.o。在执行 make 命令时,实际执行的是第一个规则。但第一个规则发现没有 hello.o 这个文件,则 make 会再以 hello.o 作为目标来执行第二个规则 hello.o : hello.c

Makefile 为了生成目标,通常会形成了一个依赖树。这个树中的任何一个文件更新。都会执行对应的规则来生成新的目标。而对于不需要更新的目标则不会执行对应的规则

执行结果如下:

weimingze@mzstudio:~$ ls
Makefile    hello.c
weimingze@mzstudio:~$ make
gcc -o hello.o -c hello.c
gcc -o hello hello.o
weimingze@mzstudio:~$ ls
Makefile    hello       hello.c     hello.o
weimingze@mzstudio:~$ make
make: “hello”已是最新。

可见 执行 make 后,会生成 hello.ohello 这两个文件,两个规则都执行了。

在 使用 Makefile 时,并不是所有的规则都一定会执行。而只有需要更新的目标对应的规则才会执行。如 现在我们使用 rm hello 命令删除最终的目标文件 hello 而保留 hello.o。再次 make 则只会调用 规则 hello : hello.o ,而不会执行规则 hello.o : hello.c。这样可以避免没有必要的更新以节省 make 执行的时间。如:

weimingze@mzstudio:~$ rm hello
weimingze@mzstudio:~$ ls
Makefile  hello.c  hello.o
weimingze@mzstudio:~$ make
gcc -o hello hello.o
weimingze@mzstudio:~$ ls
Makefile  hello  hello.c  hello.o

生成指定的目标

默认 make 命令会 执行 Makefile 中的第一个规则。我们也可以使用 make 目标文件 的方式来指定执行的第一个规则,如上述程序中我们使用 rm 命令删除 hellohello.o 两个文件,然后只使用 make hello.o 命令来生成 hello.ohello 则不会生成。

执行结果如下:

weimingze@mzstudio:~$ rm hello hello.o
weimingze@mzstudio:~$ ls
Makefile  hello.c
weimingze@mzstudio:~$ make hello.o
gcc -o hello.o -c hello.c
weimingze@mzstudio:~$ ls
Makefile  hello.c  hello.o

通过上述执行结果。可见使用 make 目标文件 的方式可以将 Makefile 中的任意规则当成第一执行规则

实验:

将上述 Makefile 的两个规则上下颠倒,改写如下:

hello.o : hello.c
    gcc -o hello.o -c hello.c

hello : hello.o
    gcc -o hello hello.o

使用 make 命令执行的结果是怎样的?如何才能够生成最终的可执行文件 hello 呢?尝试使用命令来验证你的想法。