.PHONY在makefile中的目的是什么?

.PHONY在Makefile中意味着什么? 我已经经历了这个 ,但是太复杂了。

有人可以用简单的语言来解释一下吗?

默认情况下,Makefile目标是“文件目标” – 它们用于从其他文件构build文件。 假设它的目标是一个文件,这使得编写Makefiles相对容易:

 foo: bar create_one_from_the_other foo bar 

但是,有时您希望Makefile运行不代表文件系统中物理文件的命令。 很好的例子是“干净”和“全部”的共同目标。 有可能情况并非如此,但是您的主目录中可能会有一个名为clean的文件。 在这种情况下,Make将会被混淆,因为默认情况下, clean目标将与这个文件相关联,并且Make只会在文件看起来与其依赖关系不是最新的时候才运行。

这些特殊的目标被称为虚假的 ,你可以明确地告诉让他们不与文件关联,例如:

 .PHONY: clean clean: rm -rf *.o 

现在make clean将按预期运行,即使你有一个名为clean的文件。

在Make方面,假目标只是一个总是过时的目标,所以无论何时你问make <phony_target> ,目标都会独立于文件系统的状态运行。 一些常见的伪造目标是: allinstallcleandistcleanTAGSinfocheck

欲了解更多信息,这里有一个很好的教程解释它。

假设你已经install目标,这在makefiles中是非常常见的。 如果您使用.PHONY ,并且名为install的文件与Makefile位于同一目录中,那么make install将不会执行任何操作 。 这是因为Make将规则解释为“执行这样的配方来创build名为install的文件”。 由于该文件已经存在,并且其依赖关系没有改变,所以不会做任何事情。

但是,如果您将install目标PHONY,它会告诉make工具,目标是虚构的,这使得不应该期望它创build实际的文件。 因此,它不会检查install文件是否存在,这意味着:a)如果文件存在,它的行为不会被改变; b)不会调用额外的stat()

一般来说,Makefile中所有不产生与目标名称同名的输出文件的目标应该是PHONY。 这通常包括allinstallcleandistclean等。

 .PHONY: install 
  • 表示“安装”一词在这个Makefile中不代表文件名;
  • 意味着Makefile与在同一个目录下的“install”文件无关。

:make工具读取makefile,并检查规则中':'符号两侧文件的修改时间戳。

在“testing”目录中存在以下文件:

 prerit@vvdn105:~/test$ ls hello hello.c makefile 

在makefile中,一个规则定义如下:

 hello:hello.c cc hello.c -o hello 

现在假定文件“hello”是一个包含一些数据的文本文件,它是在'hello.c'文件之后创build的。 所以'hello'的修改(或创build)时间戳会比'hello.c'更新。 所以当我们从命令行调用“make hello”的时候,它会打印为:

 make: `hello' is up to date. 

现在访问'hello.c'文件并在其中放置一些空格,这不会影响代码语法或逻辑,然后保存并退出。 现在hello.c的修改时间戳比'hello'的更新。 现在,如果您调用“make hello”,它将执行以下命令:

 cc hello.c -o hello 

而文件'hello'(文本文件)将被一个新的二进制文件'hello'(上面的编译命令的结果)覆盖。

如果我们在makefile中使用.PHONY,如下所示:

 .PHONY:hello hello:hello.c cc hello.c -o hello 

然后调用'make hello',它会忽略pwd中存在的任何名为'hello'的文件,并且每次执行该命令。

现在假设makefile中没有目标依赖关系:

 hello: cc hello.c -o hello 

和'hello'文件已经存在于pwd'test'中,那么'make hello'将总是显示为:

 make: `hello' is up to date. 

这是一个不是文件名的构build目标。

最好的解释是GNU make手册本身: 4.6 Phony Targets部分 。

.PHONY是make的特殊内置目标名称之一 。 还有其他的目标,你可能会感兴趣,所以这是值得浏览这些参考。

当考虑一个.PHONY目标的时候,make会无条件地运行它的配方,不pipe这个名字的文件是否存在,或者它的最后修改时间是什么。

你也可能对make的标准目标感兴趣,比如allclean

也有一个重要的棘手的对待“凤凰” – 当一个物理目标取决于假目标依赖于另一个物理目标:

TARGET1 – > PHONY_FORWARDER1 – > PHONY_FORWARDER2 – > TARGET2

如果你更新了TARGET2,那么你应该认为TARGET1应该被认为是针对TARGET1的,所以TARGET1应该被重build。 这真的是这样

棘手的部分是,当TARGET2对TARGET1 没有陈旧时 – 在这种情况下,你应该期望TARGET1不应该被重build。

这令人惊讶地不起作用,因为: 假冒目标是无论如何运行(通常假冒目标) ,这意味着假目标被认为是更新 。 而且因为这个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依赖于文件1通过一个虚假的目标间接的 – 但它总是得到重build,由于这种依赖。 如果您将fileall的依赖关系从filefwdfile ,那么现在fileall都不会重buildfileall ,但只有当依赖目标中的任何一个针对它作为文件陈旧时才会被重build。

Interesting Posts