原因一:避免Makefile检查时间戳
前置知识:makefile在依赖文件没有改变时不会执行编译命令
bash
#第一次执行,OK
[root@VM-16-14-centos ~]# make
g++ -E main.cc -o main.i
g++ -S main.i -o main.s
g++ -c main.s -o main.o
g++ main.o -o main
#第二次执行,源文件没有被修改,为了效率make不会执行编译
[root@VM-16-14-centos ~]# make
make: `main' is up to date.
当目录中存在名为clean
的文件时,若未声明.PHONY
,make clean
会检查该文件的时间戳。由于clean
目标通常没有依赖文件,Make会认为该目标已是最新状态,从而跳过命令执行。
makefile
# 未声明.PHONY时,若存在clean文件:
$ touch clean
$ make clean
make: 'clean' is up to date. # 命令未执行
.PHONY
声明后,无论文件是否存在,make clean
都会执行其命令。例如:
makefile
.PHONY: clean
clean:
rm -f *.o main
即使存在clean
文件,也会强制删除目标文件。
情况 | 未声明.PHONY |
声明.PHONY 后 |
---|---|---|
目录中存在clean 文件 |
命令被跳过 | 命令强制执行 |
无clean 文件 |
命令正常执行 | 命令正常执行 |
原因二:优化性能(次要)
在Makefile中,.PHONY
目标通过跳过隐含规则搜索来提升性能,其原理和优化效果可分为以下四个层面:
场景 | 未声明.PHONY |
声明.PHONY 后 |
---|---|---|
目标文件已存在 | 检查时间戳(约0.5ms) | 直接执行命令(0ms) |
多级依赖链 | 递归检查所有依赖 | 仅执行命令不检查依赖 |
并行编译(make -j ) |
可能因规则搜索阻塞线程 | 减少线程竞争 |
- 必须声明为
.PHONY
的目标 :clean
、install
等不生成文件的操作- 入口目标如
all
(避免与all
文件冲突)
- 不应声明的情况 :
- 实际需要生成文件的目标(如
main.o
),否则会重复编译,降低效率
- 实际需要生成文件的目标(如