PHONY在Makefile中是什么意思?我已经经历过了,但这太复杂了。
有人能简单地向我解释一下吗?
PHONY在Makefile中是什么意思?我已经经历过了,但这太复杂了。
有人能简单地向我解释一下吗?
当前回答
最好的解释是GNU make手册本身:4.6 Phony Targets部分。
.PHONY是make的特殊内置目标名称之一。还有其他你可能感兴趣的目标,所以值得浏览一下这些参考文献。
当该考虑.PHONY目标时,make将运行其配方无条件地,无论具有该名称的文件是否存在或它的最后修改时间是什么。
你也可能对make的标准目标感兴趣,比如all和clean。
其他回答
默认情况下,Makefile目标是“文件目标”-它们用于从其他文件构建文件。Make假设其目标是一个文件,这使得编写Makefile相对容易:
foo: bar
create_one_from_the_other foo bar
但是,有时您希望Makefile运行不表示文件系统中物理文件的命令。这方面的好例子是共同目标“干净”和“所有”。可能情况并非如此,但您可能在主目录中有一个名为clean的文件。在这种情况下,Make会感到困惑,因为默认情况下,干净的目标将与此文件相关联,Make只会在文件的依赖关系看起来不是最新时运行它。
这些特殊目标称为假目标,您可以明确告诉Make它们与文件无关,例如:
.PHONY: clean
clean:
rm -rf *.o
现在,即使您有一个名为clean的文件,makeclean也将按预期运行。
就Make而言,虚假目标只是一个总是过时的目标,因此每当您询问Make<phony_target>时,它就会独立于文件系统的状态运行。一些常见的假冒目标是:all、install、clean、distclean、TAGS、info、check。
它是不是文件名的生成目标。
“.PHONY”还有一个重要的棘手之处——当一个物理目标依赖于另一个物理对象的虚假目标时:
目标1->PHONY_FORWARDER1->PHONY-FORWARDER2->TARGET2
您可以简单地预期,如果您更新了TARGET2,那么TARGET1应该被认为是过时的,因此TARGET1应该重新构建。它确实是这样工作的。
棘手的部分是,当TARGET2与TARGET1不过时时——在这种情况下,您应该预计TARGET1不应该重建。
这令人惊讶地不起作用,因为:无论如何都运行了假目标(就像假目标通常所做的那样),这意味着假目标被认为是更新的。正因为如此,TARGET1被认为是过时的,而不是虚假的目标。
考虑:
all: fileall
fileall: file2 filefwd
echo file2 file1 >fileall
file2: file2.src
echo file2.src >file2
file1: file1.src
echo file1.src >file1
echo file1.src >>file1
.PHONY: filefwd
.PHONY: filefwd2
filefwd: filefwd2
filefwd2: file1
@echo "Produced target file1"
prepare:
echo "Some text 1" >> file1.src
echo "Some text 2" >> file2.src
你可以玩这个:
首先做“make prepare”以准备“源文件”通过触摸特定文件来查看它们的更新
您可以看到,fileall通过一个虚假的目标间接依赖于file1,但由于这种依赖性,它总是被重新构建。如果您将fileall中的依赖项从filefwd更改为file,那么现在fileall不会每次都重新生成,而是只有在任何依赖目标作为文件过时时才会重新生成。
假设您有安装目标,这在makefile中很常见。如果不使用.PHONY,并且名为install的文件与Makefile位于同一目录中,那么makeinstall将不会执行任何操作。这是因为Make将规则解释为“执行这样和那样的配方以创建名为install的文件”。由于文件已经存在,并且其依赖关系没有更改,因此将不会执行任何操作。
但是,如果您将安装目标设置为PHONY,它会告诉make工具该目标是虚构的,make不应该期望它创建实际的文件。因此,它不会检查安装文件是否存在,这意味着:a)如果文件确实存在,它的行为不会改变;b)不会调用额外的stat()。
通常,Makefile中的所有目标,如果没有生成与目标名称相同的输出文件,则应为PHONY。这通常包括all、install、clean、distclean等。
特殊目标.PHONY:允许声明虚假目标,这样make就不会将它们作为实际文件名进行检查:即使这样的文件仍然存在,它也会一直工作。
你可以在Makefile中放入几个。PHONY:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
还有另一种方法可以声明虚假目标:只需::无需先决条件:
all :: prog1 prog2
...
clean ::
...
distclean ::
...
::还有其他特殊的含义,请参见这里,但在没有前提条件的情况下,它总是执行食谱,即使目标已经存在,因此充当了一个虚假的目标。