.PHONY
是什么意思?我已经阅读过这篇文章,但是太复杂了。请有人用简单的语言来解释一下吗?默认情况下,Makefile 目标是“文件目标” - 它们用于从其他文件构建文件。Make 假定其目标是一个文件,这使得编写 Makefile 相对容易:
foo: bar
create_one_from_the_other foo bar
然而,有时候你想让Makefile运行的命令不代表文件系统中的实际文件。其中"clean"和"all"是很好的例子。虽然这种情况可能不会发生,但你的主目录下可能会有一个名为clean
的文件。在这种情况下,Make将感到困惑,因为默认情况下clean
目标将被与该文件关联,并且只有当该文件对其依赖项不再具有最新状态时,Make才会运行它。
这些特殊的目标被称为伪目标,你可以明确告诉Make它们不与任何文件相关联,例如:
.PHONY: clean
clean:
rm -rf *.o
现在,即使您有一个名为 clean
的文件,make clean
命令也将按预期运行。
在 Makefile 中,伪目标是指始终过时的目标,因此每当您执行 make <phony_target>
时,它都会独立于文件系统状态而运行。一些常见的伪目标包括: all
、install
、clean
、distclean
、TAGS
、info
、check
。
install
的目标,这在Makefile中非常常见。如果您不使用.PHONY
,并且与Makefile位于同一目录中存在名为install
的文件,则make install
将 无动作。这是因为Make解释该规则为“执行某种配方以创建名为install
的文件”。由于文件已经存在,并且其依赖项没有更改,因此什么也不会发生。install
目标设置为PHONY,则它将告诉make工具该目标是虚构的,并且make不应期望它创建实际文件。因此,它不会检查install
文件是否存在,这意味着:a)如果文件确实存在,其行为不会改变, b)不会调用额外的stat()
。all
、install
、clean
、distclean
等目标。.sh
或 .bash
扩展名,并将添加扩展名保留给你包含的库(source mylib.sh
)。事实上,我能找到这个 Stack Overflow 问题是因为我在与 Makefile 相同的目录中有一个名为 install
的脚本。 - Kyle.PHONY
... - nucleartideprerit@vvdn105:~/test$ ls
hello hello.c makefile
hello:hello.c
cc hello.c -o hello
make: `hello' is up to date.
cc hello.c -o hello
.PHONY:hello
hello:hello.c
cc hello.c -o hello
hello:
cc hello.c -o hello
make: `hello' is up to date.
make
命令变得有意义,一切都与文件有关!感谢您的答案。 - Kzqai目标: 依赖 ...
命令
...
参考:https://www.gnu.org/software/make/ - VicX.PHONY: install
这是一个构建目标(build target),它不是文件名。
特殊的目标.PHONY:
允许声明虚拟目标,这样make
不会将其作为实际文件名进行检查:即使这些文件仍然存在,它也会一直工作。
您可以在Makefile
中放置多个.PHONY:
:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
声明伪目标的另一种方法是:只需在没有先决条件的情况下放置::
即可:
all :: prog1 prog2
...
clean ::
...
distclean ::
...
::
有其他特殊含义,可以在这里查看,但如果没有前提条件,它总是执行配方,即使目标已经存在,因此起到了虚假目标的作用。::
时,才被视为虚假,可参见GNU make文档中上面的链接。 - Edouard Thiel.PHONY
是make的一个特殊内置目标名称之一。你可能会对其他目标感兴趣,所以值得浏览这些参考资料。
你可能还会对make的标准目标如当考虑.PHONY目标时,无论具有该名称的文件是否存在或其最后修改时间如何,make都将无条件地运行其配方。
all
和clean
感兴趣。还有一个重要的“.PHONY”的技巧 - 当一个物理目标依赖于另一个虚拟目标,而这个虚拟目标又依赖于另一个物理目标时:
TARGET1 -> 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
你可以试着玩一下:
你可以看到,文件"fileall"间接地通过一个虚构目标依赖于"file1" - 但由于这种依赖性,它总是会被重新构建。如果你将fileall
中的依赖从filefwd
更改为file
,那么现在fileall
不会每次都被重新构建,而只有在任何依赖目标对其作为文件时过时时才会被重新构建。
我经常使用它们来告诉默认目标不要触发。
superclean: clean andsomethingelse
blah: superclean
clean:
@echo clean
%:
@echo catcher $@
.PHONY: superclean
make superclean
将触发 clean
、andsomethingelse
和 catcher superclean
;但使用了 PHONY,make superclean
就不会触发 catcher superclean
。clean
目标是 PHONY,因为它并非完全虚假。尽管它从未生成 clean 文件,但它有命令可触发,所以 make 会认为它是最终目标。superclean
目标真的是虚假的,因此 make 将尝试将其与为 superclean
目标提供依赖关系的任何其他内容堆叠在一起——这包括其他 superclean
目标和 %
目标。andsomethingelse
或 blah
,因此它们显然进入 catcher。$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah