第一种情况:避免命令与目录下的文件名重复
实际上这个情况很少发生,但网上大部分博客也仅介绍了这一种情况。这里以如下Makefile简单介绍一下:
clean:
rm -f *.o temp
如果当前目录下没有名为“clean”的文件,则rm指令会被执行。如果有的话,由于clean没有依赖文件,所以目标被认为是最新的而不去执行rm指令。
在Makefile中加入伪目标声明可防止这种情况发生
.PHONY : clean
第二种情况:make的并行和递归执行过程中
先看一个例子
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
如上用循环到所有子目录下执行make指令,有以下问题:
1.如果其中一个make指令执行失败(代码格式错误等),它不会停下来,而会继续执行其它目录的make指令,这样很难定位出错的位置。
2.没有用到make对目录的并行处理功能,而是按顺序执行。
- 并行处理功能:如果两个目标有依赖关系,如a依赖于b,则执行顺序一定是先生成b再生成a。而不过没有依赖关系的话,不同目标是可以并行生成的。而上面的Makefile在循环中顺序执行一样会失去并行性。
而有了PHONY后,可以解决这些问题,修改Makefile如下:
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
#在并行Makefile中需要注意目录处理的顺序
foo: baz #没有命令行,限制子目录的make顺序,即先生成baz才能生成foo
当一个目标文件的依赖包含伪目标时,每一次在执行这个规则时伪目标所定义的命令都会被执行。所以subdirs: $(SUBDIRS)
代表$(SUBDIRS)
下定义的命令$(MAKE) -C $@
每次都会无条件地被执行。
而伪目标不在任何目标文件的依赖中时,只能通过make来主动执行,如上面的make clean
。
- Linux内核源码的
/scripts/Makefile.build
中就有这种伪目标出现:各个子目录并行递归生成其目录的.o文件,最终通过顶层目录的.o生成内核文件。
第三种情况:生成多个应用程序
在Makefile中第一个目标即最后要生成的文件,如果想在一个目录下创建多个可执行程序,可以用伪目标“all
”作为第一个目标。
#sample Makefile
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
make prog1/prog2/prog3
可以单独生成其中一个可执行程序