What is the purpose of .PHONY in a makefile?
在makefile中,
有人能简单地给我解释一下吗?
默认情况下,makefile目标是"文件目标"——它们用于从其他文件构建文件。make假定其目标是一个文件,这使得编写makefiles相对容易:
1 2 | foo: bar create_one_from_the_other foo bar |
但是,有时您希望makefile运行不代表文件系统中物理文件的命令。这方面的好例子是"干净"和"全部"的共同目标。很可能情况并非如此,但您的主目录中可能有一个名为
这些特殊目标称为虚假目标,您可以明确地告诉他们,使他们与文件无关,例如:
1 2 3 | .PHONY: clean clean: rm -rf *.o |
现在,即使您有一个名为
在make方面,虚假目标只是一个总是过时的目标,因此每当您询问
假设您有一个
但是,如果您使
通常,makefile中不生成与目标名称同名的输出文件的所有目标都应该是假的。这通常包括
注意:make工具读取makefile并检查规则中":"符号两侧文件的修改时间戳。
例子在目录"test"中,存在以下文件:
1 2 | prerit@vvdn105:~/test$ ls hello hello.c makefile |
在makefile中,规则定义如下:
1 2 | hello:hello.c cc hello.c -o hello |
现在假设文件"hello"是包含一些数据的文本文件,这些数据是在"hello.c"文件之后创建的。所以"hello"的修改(或创建)时间戳将比"hello.c"更新。因此,当我们从命令行调用"make hello"时,它将打印为:
1 | make: `hello' is up to date. |
现在访问"hello.c"文件并在其中放置一些空白,这不会影响代码语法或逻辑,然后保存并退出。现在hello.c的修改时间戳比hello更新。现在,如果调用"make hello",它将执行以下命令:
1 | cc hello.c -o hello |
文件"hello"(文本文件)将被一个新的二进制文件"hello"(上述编译命令的结果)覆盖。
如果在makefile中使用.phony,如下所示:
1 2 3 4 | .PHONY:hello hello:hello.c cc hello.c -o hello |
然后调用"make hello",它将忽略pwd中名为"hello"的文件,并每次执行该命令。
现在假设makefile中没有目标的依赖项:
1 2 | hello: cc hello.c -o hello |
并且"hello"文件已经存在于pwd"test"中,那么"make hello"将始终显示为:
1 | make: `hello' is up to date. |
1 | .PHONY: install |
- 表示"安装"一词不代表此文件中的文件名生成文件;
- 表示makefile与名为"install"的文件无关在同一个目录中。
它是不是文件名的生成目标。
最好的解释是GNU制作手册本身:4.6虚假目标部分。
When it is time to consider a .PHONY target, make will run its recipe
unconditionally, regardless of whether a file with that name exists or
what its last-modification time is.
您也可能对make的标准目标感兴趣,如
还有一个重要的棘手的处理方法就是"假"—当一个物理目标依赖于另一个物理目标的假目标时:
目标1->Phony_转发器1->Phony_转发器2->Target2
如果更新了target2,那么应该认为target1相对于target1过时,所以应该重新构建target1。它确实是这样工作的。
棘手的部分是,当target2对target1不过时-在这种情况下,你应该期待target1不应该被重建。
这令人惊讶地不起作用,因为:不管怎样,假目标都是运行的(就像假目标通常那样),这意味着假目标被认为是更新的。因为这个目标1被认为是对虚假目标的过时。
考虑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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,但由于这种依赖性,它总是得到重建。如果您将
我经常用它们告诉默认目标不要开火。
1 2 3 4 5 6 7 8 9 10 11 | superclean: clean andsomethingelse blah: superclean clean: @echo clean %: @echo catcher $@ .PHONY: superclean |
没有假身份,
我们不必担心告诉你让
然而,
请注意,我们根本不说关于
输出如下所示:
1 2 3 4 5 6 7 8 9 10 11 | $ make clean clean $ make superclean clean catcher andsomethingelse $ make blah clean catcher andsomethingelse catcher blah |