Makefile 中 .PHONY 的用途是什么?

发布于 2024-08-19 11:29:33 字数 183 浏览 2 评论 0原文

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

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

What does .PHONY mean in a Makefile? I have gone through this, but it is too complicated.

Can somebody explain it to me in simple terms?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

热血少△年 2024-08-26 11:29:33

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

foo: bar
  create_one_from_the_other foo bar

但是,有时,您希望 Makefile 运行不代表文件系统中的物理文件的命令。很好的例子是共同目标“干净”和“全部”。情况可能并非如此,但您的主目录中可能可能有一个名为clean的文件。在这种情况下,Make 会感到困惑,因为默认情况下,clean 目标将与此文件关联,并且 Make 仅当该文件在以下方面似乎不是最新时才运行它:它的依赖项。

这些特殊目标称为假目标,您可以明确告诉 Make 它们与文件无关,例如:

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

现在,即使您确实有文件,make clean 也会按预期运行名为clean

就 Make 而言,虚假目标只是一个始终过时的目标,因此每当您询问 make 时,它都会运行,独立于文件系统的状态。一些常见的 make 目标通常是假的:all、install、clean、distclean代码>、<代码>标签、<代码>信息、<代码>检查。

另请参阅:GNU make 手册:假目标

By default, Makefile targets are "file targets" - they are used to build files from other files. Make assumes its target is a file, and this makes writing Makefiles relatively easy:

foo: bar
  create_one_from_the_other foo bar

However, sometimes, you want your Makefile to run commands that do not represent physical files in the file system. Good examples of this are the common targets "clean" and "all". Chances are this isn't the case, but you may potentially have a file named clean in your main directory. In such a case Make will be confused because by default the clean target would be associated with this file and Make will only run it when the file doesn't appear to be up-to-date with regards to its dependencies.

These special targets are called phony and you can explicitly tell Make they're not associated with files, e.g.:

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

Now make clean will run as expected even if you do have a file named clean.

In terms of Make, a phony target is simply a target that is always out-of-date, so whenever you ask make <phony_target>, it will run, independent from the state of the file system. Some common make targets that are often phony are: all, install, clean, distclean, TAGS, info, check.

See also: GNU make manual: Phony Targets

月下伊人醉 2024-08-26 11:29:33

假设您有 install 目标,这在 makefile 中非常常见。如果您使用.PHONY,并且名为install的文件与Makefile位于同一目录中,则make install< /code> 将什么都不做。这是因为 Make 将规则解释为“执行某某配方以创建名为 install 的文件”。由于该文件已经存在,并且其依赖项没有更改,因此不会执行任何操作。

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

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

Let's assume you have install target, which is a very common in makefiles. If you do not use .PHONY, and a file named install exists in the same directory as the Makefile, then make install will do nothing. This is because Make interprets the rule to mean "execute such-and-such recipe to create the file named install". Since the file is already there, and its dependencies didn't change, nothing will be done.

However if you make the install target PHONY, it will tell the make tool that the target is fictional, and that make should not expect it to create the actual file. Hence it will not check whether the install file exists, meaning: a) its behavior will not be altered if the file does exist and b) extra stat() will not be called.

Generally all targets in your Makefile which do not produce an output file with the same name as the target name should be PHONY. This typically includes all, install, clean, distclean, and so on.

怕倦 2024-08-26 11:29:33

注意: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”(文本文件)将被新的二进制文件“hello”(上述编译命令的结果)覆盖。

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

.PHONY:hello

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

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

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

hello:
    cc hello.c -o hello

并且“hello”文件已存在于 pwd“test”中,那么“make hello”将始终显示为:

make: `hello' is up to date.

NOTE: The make tool reads the makefile and checks the modification time-stamps of the files at both the side of ':' symbol in a rule.

Example

In a directory 'test' following files are present:

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

In makefile a rule is defined as follows:

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

Now assume that file 'hello' is a text file containing some data, which was created after 'hello.c' file. So the modification (or creation) time-stamp of 'hello' will be newer than that of the 'hello.c'. So when we will invoke 'make hello' from command line, it will print as:

make: `hello' is up to date.

Now access the 'hello.c' file and put some white spaces in it, which doesn't affect the code syntax or logic then save and quit. Now the modification time-stamp of hello.c is newer than that of the 'hello'. Now if you invoke 'make hello', it will execute the commands as:

cc hello.c -o hello

And the file 'hello' (text file) will be overwritten with a new binary file 'hello' (result of above compilation command).

If we use .PHONY in makefile as follow:

.PHONY:hello

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

and then invoke 'make hello', it will ignore any file present in the pwd 'test' and execute the command every time.

Now suppose, that 'hello' target has no dependencies declared:

hello:
    cc hello.c -o hello

and 'hello' file is already present in the pwd 'test', then 'make hello' will always show as:

make: `hello' is up to date.
情丝乱 2024-08-26 11:29:33
.PHONY: install
  • 意味着“安装”一词不代表此文件名
    生成文件;
  • 表示 Makefile 与名为“install”的文件无关
    在同一目录中。
.PHONY: install
  • means the word "install" doesn't represent a file name in this
    Makefile;
  • means the Makefile has nothing to do with a file called "install"
    in the same directory.
淑女气质 2024-08-26 11:29:33

它是一个构建目标,而不是文件名。

It is a build target that is not a filename.

半世蒼涼 2024-08-26 11:29:33

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

您可以在 Makefile 中放置多个 .PHONY:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

还有另一种声明虚假目标的方法:只需放置 :: 而无需先决条件:

all :: prog1 prog2

...

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

< code>:: 有其他特殊含义,请参见此处,但如果没有先决条件,它总是执行配方,即使目标已经存在,从而充当虚假目标。

The special target .PHONY: allows to declare phony targets, so that make will not check them as actual file names: it will work all the time even if such files still exist.

You can put several .PHONY: in your Makefile :

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

There is another way to declare phony targets : simply put :: without prerequisites :

all :: prog1 prog2

...

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

The :: has other special meanings, see here, but without prerequisites it always execute the recipes, even if the target already exists, thus acting as a phony target.

紧拥背影 2024-08-26 11:29:33

最好的解释是 GNU make 手册本身:4.6 Phony Targets 部分< /a>.

.PHONY 是 make 的 特殊的内置目标名称。您可能还对其他目标感兴趣,因此值得浏览一下这些参考资料。

当需要考虑 .PHONY 目标时,make 将运行其配方
无条件地,无论具有该名称的文件是否存在或
它的最后修改时间是多少。

您可能还对 make 的 标准目标 感兴趣,例如全部干净

The best explanation is the GNU make manual itself: 4.6 Phony Targets section.

.PHONY is one of make's Special Built-in Target Names. There are other targets that you may be interested in, so it's worth skimming through these references.

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.

You may also be interested in make's Standard Targets such as all and clean.

狼性发作 2024-08-26 11:29:33

“.PHONY”还有一个重要的棘手问题 - 当一个物理目标依赖于另一个物理目标的虚假目标时:

TARGET1 -> TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

您可能只是希望,如果您更新了 TARGET2,那么 TARGET1 应被视为相对于 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

您可以尝试一下:

  • 首先执行“makeprepare”来准备“源文件”,
  • 然后通过触摸特定文件来查看它们的更新

您可以看到 fileall 通过虚假目标间接依赖于 file1 - 但它由于这种依赖性,总是会被重建。如果将 fileall 中的依赖项从 filefwd 更改为 file,现在 fileall 不会每次都重新构建,而是仅当任何依赖目标作为文件对其而言已过时时。

There's also one important tricky treat of ".PHONY" - when a physical target depends on phony target that depends on another physical target:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

You'd simply expect that if you updated TARGET2, then TARGET1 should be considered stale against TARGET1, so TARGET1 should be rebuild. And it really works this way.

The tricky part is when TARGET2 isn't stale against TARGET1 - in which case you should expect that TARGET1 shouldn't be rebuild.

This surprisingly doesn't work because: the phony target was run anyway (as phony targets normally do), which means that the phony target was considered updated. And because of that TARGET1 is considered stale against the phony target.

Consider:

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

You can play around with this:

  • first do 'make prepare' to prepare the "source files"
  • play around with that by touching particular files to see them updated

You can see that fileall depends on file1 indirectly through a phony target - but it always gets rebuilt due to this dependency. If you change the dependency in fileall from filefwd to file, now fileall does not get rebuilt every time, but only when any of dependent targets is stale against it as a file.

薯片软お妹 2024-08-26 11:29:33

因此,假设运行 make 的目录中有一个名为“clean”的文件。现在让我们以下面的 Makefile 为例:

clean:
        rm lol

现在,当您运行“make clean”时,您将得到以下输出:

但是如果您将“.PHONY: clean”添加到 Makefile 并运行“make clean”,您将看到以下输出
输入图像描述这里

发生了什么?
由于目录中存在文件,所以第一次将 clean 视为目标。
但添加 .PHONY 后,make 会忽略该文件(以及时间戳跟踪)并将其解释为正常干净。

现在,这可以应用于许多情况,您希望 make 忽略作为目标给出的参数(当您在该目录中具有相同名称的文件时)。

So, let's say you have a file named "clean" in your directory where the make is run. Now lets take an example of below Makefile:

clean:
        rm lol

Now when you run "make clean" you will get following output:
enter image description here

but if you add ".PHONY: clean" to the Makefile and run "make clean" you will see the following output:
enter image description here

What happened?
make treated clean first time as target since a file is present in the directory.
But after adding .PHONY, the make ignored the file (and also the timestamp tracking) and interpreted it as normal clean.

Now this can be applied to numerous cases where you want your make to ignore the argument given as target (when you have a file with same name in that directory).

没︽人懂的悲伤 2024-08-26 11:29:33

我经常用它们来告诉默认目标不要开火。

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

如果没有 PHONY,make superclean 将触发 cleanandsomethingelsecatcher superclean;但对于 PHONY,make superclean 不会触发 catcher superclean

我们不必担心告诉 make clean 目标是假的,因为它并不完全是假的。虽然它永远不会生成干净的文件,但它有要触发的命令,因此 make 会认为它是最终目标。

然而,superclean 目标确实是假的,因此 make 会尝试将其与为 superclean 目标提供 deps 的任何其他内容堆叠在一起 - 这包括其他 superclean< /code> 目标和 % 目标。

请注意,我们根本没有说任何有关 andsomethingelseblah 的内容,因此它们显然去了捕手。

输出看起来像这样:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah

I often use them to tell the default target not to fire.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Without PHONY, make superclean would fire clean, andsomethingelse, and catcher superclean; but with PHONY, make superclean won't fire the catcher superclean.

We don't have to worry about telling make the clean target is PHONY, because it isn't completely phony. Though it never produces the clean file, it has commands to fire so make will think it's a final target.

However, the superclean target really is phony, so make will try to stack it up with anything else that provides deps for the superclean target — this includes other superclean targets and the % target.

Note that we don't say anything at all about andsomethingelse or blah, so they clearly go to the catcher.

The output looks something like this:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
尾戒 2024-08-26 11:29:33

这样

.PHONY: clean
clean:
        rm *.o temp

,即使工作区中有 clean file,您仍然可以在代码中执行 clean 目标

In

.PHONY: clean
clean:
        rm *.o temp

so that you can still execute the clean target in the code even if you have clean file within the workspace

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文