Makefile中.PHONY的作用是什么
Makefile中.PHONY的作用是什么
技术背景
在Makefile里,默认的目标是“文件目标”,也就是用于从其他文件构建新文件。Make默认其目标是一个文件,这让编写Makefile变得相对容易。不过,有时我们希望Makefile执行的命令并不对应文件系统中的物理文件,像常见的“clean”和“all”目标就是如此。
实现步骤
未使用.PHONY的情况
假设在Makefile里有如下规则:
1 | |
要是当前目录下存在名为clean的文件,当执行make clean时,Make会认为该目标与这个文件关联,只有当文件相对于其依赖项看起来不是最新时,才会执行相应命令。若文件已存在且依赖项未改变,Make就不会执行rm -rf *.o命令。
使用.PHONY的情况
在Makefile中添加.PHONY声明:
1 | |
这样,即便存在名为clean的文件,执行make clean时,Make也会忽略该文件,直接执行rm -rf *.o命令。
核心代码
示例1:基本的.PHONY使用
1 | |
示例2:多个.PHONY目标
1 | |
示例3:使用::声明伪目标
1 | |
最佳实践
一般而言,Makefile中所有不会生成与目标同名输出文件的目标都应声明为伪目标。常见的伪目标有all、install、clean、distclean等。例如:
1 | |
常见问题
伪目标依赖关系的问题
当一个物理目标依赖于伪目标,而伪目标又依赖于另一个物理目标时,可能会出现意外情况。比如:
1 | |
在这个例子中,fileall通过伪目标间接依赖于file1,由于伪目标总是被视为更新过,所以fileall总会被重新构建。若将fileall的依赖从filefwd改为file1,则fileall仅在依赖目标相对于它过期时才会被重新构建。
目标捕获规则的问题
在Makefile中使用目标捕获规则时,伪目标的声明会影响规则的执行。例如:
1 | |
若未声明superclean为伪目标,执行make superclean时,会触发clean、andsomethingelse和catcher superclean;声明后,make superclean就不会触发catcher superclean。