Makefile 中 .PHONY 的用途是什么?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
默认情况下,Makefile 目标是“文件目标”——它们用于从其他文件构建文件。 Make 假定其目标是一个文件,这使得编写 Makefile 相对容易:
但是,有时,您希望 Makefile 运行不代表文件系统中的物理文件的命令。很好的例子是共同目标“干净”和“全部”。情况可能并非如此,但您的主目录中可能可能有一个名为
clean
的文件。在这种情况下,Make 会感到困惑,因为默认情况下,clean
目标将与此文件关联,并且 Make 仅当该文件在以下方面似乎不是最新时才运行它:它的依赖项。这些特殊目标称为假目标,您可以明确告诉 Make 它们与文件无关,例如:
现在,即使您确实有文件,
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:
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 theclean
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.:
Now
make clean
will run as expected even if you do have a file namedclean
.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 commonmake
targets that are often phony are:all
,install
,clean
,distclean
,TAGS
,info
,check
.See also: GNU make manual: Phony Targets
假设您有
install
目标,这在 makefile 中非常常见。如果您不使用.PHONY
,并且名为install
的文件与Makefile位于同一目录中,则make install< /code> 将什么都不做。这是因为 Make 将规则解释为“执行某某配方以创建名为
install
的文件”。由于该文件已经存在,并且其依赖项没有更改,因此不会执行任何操作。但是,如果您将
install
目标设置为 PHONY,它将告诉 make 工具该目标是虚构的,并且 make 不应期望它创建实际文件。因此,它不会检查install
文件是否存在,这意味着:a) 如果文件确实存在,则其行为不会改变,b) 额外的stat()
不会被改变叫。通常,Makefile 中不生成与目标名称同名的输出文件的所有目标都应该是 PHONY。这通常包括
all
、install
、clean
、distclean
等。Let's assume you have
install
target, which is a very common in makefiles. If you do not use.PHONY
, and a file namedinstall
exists in the same directory as the Makefile, thenmake install
will do nothing. This is because Make interprets the rule to mean "execute such-and-such recipe to create the file namedinstall
". 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 theinstall
file exists, meaning: a) its behavior will not be altered if the file does exist and b) extrastat()
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.注意:make 工具读取makefile 并检查规则中':' 符号两侧的文件的修改时间戳。
示例
在目录“test”中存在以下文件:
在 makefile 中,规则定义如下:
现在假设文件“hello”是包含一些数据的文本文件,该文件是在“hello.c”文件之后创建的。因此“hello”的修改(或创建)时间戳将比“hello.c”的更新。因此,当我们从命令行调用“make hello”时,它将打印为:
现在访问“hello.c”文件并在其中添加一些空格,这不会影响代码语法或逻辑,然后保存并退出。现在 hello.c 的修改时间戳比 'hello' 的修改时间戳更新。现在,如果您调用“make hello”,它将执行以下命令:
并且文件“hello”(文本文件)将被新的二进制文件“hello”(上述编译命令的结果)覆盖。
如果我们在 makefile 中使用 .PHONY,如下所示:
然后调用“make hello”,它将忽略 pwd“test”中存在的任何文件并每次执行该命令。
现在假设“hello”目标没有声明依赖项:
并且“hello”文件已存在于 pwd“test”中,那么“make hello”将始终显示为:
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:
In makefile a rule is defined as follows:
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:
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:
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:
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:
and 'hello' file is already present in the pwd 'test', then 'make hello' will always show as:
生成文件;
在同一目录中。
Makefile;
in the same directory.
它是一个构建目标,而不是文件名。
It is a build target that is not a filename.
特殊目标
.PHONY:
允许声明虚假目标,以便make
不会将它们检查为实际文件名:即使此类文件仍然存在,它也会一直工作。您可以在
Makefile
中放置多个.PHONY:
:还有另一种声明虚假目标的方法:只需放置
::
而无需先决条件:< code>:: 有其他特殊含义,请参见此处,但如果没有先决条件,它总是执行配方,即使目标已经存在,从而充当虚假目标。
The special target
.PHONY:
allows to declare phony targets, so thatmake
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 yourMakefile
:There is another way to declare phony targets : simply put
::
without prerequisites :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.最好的解释是 GNU make 手册本身:4.6 Phony Targets 部分< /a>.
.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.You may also be interested in make's Standard Targets such as
all
andclean
.“.PHONY”还有一个重要的棘手问题 - 当一个物理目标依赖于另一个物理目标的虚假目标时:
TARGET1 -> TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
您可能只是希望,如果您更新了 TARGET2,那么 TARGET1 应被视为相对于 TARGET1 而言已过时,因此应重建 TARGET1。 它确实是这样工作的。
棘手的部分是 TARGET2 对于 TARGET1 不是 过时的 - 在这种情况下,您应该期望 TARGET1 不应该被重建。
令人惊讶的是,这不起作用,因为:虚假目标无论如何都会运行(就像虚假目标通常所做的那样),这意味着虚假目标被视为已更新。因此,TARGET1 对于虚假目标来说被认为是过时的。
考虑一下:
您可以尝试一下:
您可以看到 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:
You can play around with this:
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
fromfilefwd
tofile
, nowfileall
does not get rebuilt every time, but only when any of dependent targets is stale against it as a file.因此,假设运行 make 的目录中有一个名为“clean”的文件。现在让我们以下面的 Makefile 为例:
现在,当您运行“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:
Now when you run "make clean" you will get following output:
but if you add ".PHONY: clean" to the Makefile and run "make clean" you will see the following output:
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).
我经常用它们来告诉默认目标不要开火。
如果没有 PHONY,
make superclean
将触发clean
、andsomethingelse
和catcher superclean
;但对于 PHONY,make superclean
不会触发catcher superclean
。我们不必担心告诉 make
clean
目标是假的,因为它并不完全是假的。虽然它永远不会生成干净的文件,但它有要触发的命令,因此 make 会认为它是最终目标。然而,superclean 目标确实是假的,因此 make 会尝试将其与为 superclean 目标提供 deps 的任何其他内容堆叠在一起 - 这包括其他 superclean< /code> 目标和
%
目标。请注意,我们根本没有说任何有关
andsomethingelse
或blah
的内容,因此它们显然去了捕手。输出看起来像这样:
I often use them to tell the default target not to fire.
Without PHONY,
make superclean
would fireclean
,andsomethingelse
, andcatcher superclean
; but with PHONY,make superclean
won't fire thecatcher 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 thesuperclean
target — this includes othersuperclean
targets and the%
target.Note that we don't say anything at all about
andsomethingelse
orblah
, so they clearly go to the catcher.The output looks something like this:
这样
,即使工作区中有
clean
file,您仍然可以在代码中执行clean
目标In
so that you can still execute the
clean
target in the code even if you haveclean
file within the workspace