PHONY在Makefile中是什么意思?我已经经历过了,但这太复杂了。

有人能简单地向我解释一下吗?


当前回答

假设您有安装目标,这在makefile中很常见。如果不使用.PHONY,并且名为install的文件与Makefile位于同一目录中,那么makeinstall将不会执行任何操作。这是因为Make将规则解释为“执行这样和那样的配方以创建名为install的文件”。由于文件已经存在,并且其依赖关系没有更改,因此将不会执行任何操作。

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

通常,Makefile中的所有目标,如果没有生成与目标名称相同的输出文件,则应为PHONY。这通常包括all、install、clean、distclean等。

其他回答

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

实例

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

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

在makefile中,规则定义如下:

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

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

make: `hello' is up to date.

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

cc hello.c -o hello

文件“hello”(文本文件)将被一个新的二进制文件“hell”(上述编译命令的结果)覆盖。

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

.PHONY:hello

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

然后调用“makehello”,它将忽略pwd“test”中存在的任何文件,并每次执行该命令。

现在假设“hello”目标没有声明依赖项:

hello:
    cc hello.c -o hello

如果pwd“test”中已经存在“hello”文件,那么“make hello”将始终显示为:

make: `hello' is up to date.

它是不是文件名的生成目标。

.PHONY: install

表示单词“install”不代表此文件中的文件名生成文件;表示Makefile与名为“install”的文件无关在同一目录中。

特殊目标.PHONY:允许声明虚假目标,这样make就不会将它们作为实际文件名进行检查:即使这样的文件仍然存在,它也会一直工作。

你可以在Makefile中放入几个。PHONY:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

还有另一种方法可以声明虚假目标:只需::无需先决条件:

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

::还有其他特殊的含义,请参见这里,但在没有前提条件的情况下,它总是执行食谱,即使目标已经存在,因此充当了一个虚假的目标。

默认情况下,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。