Makefile 中 .PHONY 的用途是什么?

.PHONY在Makefile中用于标记那些不代表实际文件的目标。这样,即便同名文件存在,make也会执行目标对应的命令,常用于all、install、clean等任务,确保它们总能得到执行,不受文件系统状态影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问:

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

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

答1:

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

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

foo: bar
  create_one_from_the_other foo bar

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

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

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

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

就 Make 而言,虚假目标只是一个始终过期的目标,因此无论何时询问 make <phony_target>,它都会运行,与文件系统的状态无关。一些常见的 make 目标通常是虚假的:all、install、clean、distclean、TAGS、info、check。

@eSKay:“为什么叫‘假’?” ——因为它不是一个真正的目标。也就是说,目标名称不是由该目标的命令生成的文件。

@Lazer:我不知道您是否以英语为母语。我不是。假这个词并不意味着它听起来的样子。 en.wiktionary.org/wiki/phony 说:欺诈;伪造的;具有误导性的外观。

这个答案并不完全完整——尽管它可能会在链接的教程中得到解决。 .PHONY 强制构建 Makefile 中的标签/文件,如果它是您的目标的拓扑排序的一部分。也就是说,如果您有一个设置为假的“cleanup:”标签,并且您的安装标签定义为 cleanup 作为先决条件 - 即“install:cleanup”,那么当 Makefile 尝试构建时,将始终运行 cleanup '安装'。这对于您总是希望采取的步骤(无论它们是否成功)很有用 - 它会忽略时间戳并强制执行。

请注意,只要您没有与任务同名的文件,就不需要使用 .PHONY。无论如何,该任务将始终执行,并且 Makefile 将更具可读性。

“虚假目标只是一个总是过时的目标” - 很好的解释!

答2:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

假设您有 install 目标,这在 makefile 中很常见。如果您不使用 .PHONY,并且名为 install 的文件与 Makefile 存在于同一目录中,那么 make install 将什么都不做。这是因为 Make 将规则解释为“执行某某配方以创建名为 install 的文件”。由于文件已经存在,并且它的依赖关系没有改变,所以什么都不会做。

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

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

@PineappleUndertheSea 接受的答案已从最初的无价值水平显着改善,现在和这个一样好。我必须查看它的修订历史才能理解您的评论。

这似乎有点毫无意义,因为我的代码库中永远不会有名为“安装”之类的文件。大多数文件都会有文件扩展名,而没有文件扩展名的文件通常都是大写的,比如“README”。再说一次,如果你有一个名为 'install' 而不是 'install.sh' 的 bash 脚本,那么你会遇到麻烦。

@JasonTu 这不一定是真的。 Bash 脚本约定要求您省略“程序”的 .sh 或 .bash 扩展,这些“程序”就像它们具有主函数一样运行,并保留为您包含的库添加扩展 (source mylib.sh)。事实上,我之所以遇到这个 SO 问题,是因为我在与 Makefile 相同的目录中有一个名为 install 的脚本

@Kyle 是的,我不确定我过去的自我是什么意思。这些天我一直在使用 .PHONY...

@JasonTu 这里的解决方案很简单:建造一台时间机器并“替换”过去的自己。我建议您随身携带一把铲子,这样没人会意识到您是 .PHONY 版本。

答3:

huntsbot.com – 高效赚钱,自由工作

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

例子

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

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.

这不仅使我运行的命令变得有意义,而且最终使整个 make 变得有意义,一切都与文件有关!谢谢你的回答。

下面是一个简单的规则:```target: dependencies ... commands ... ```Ref: gnu.org/software/make

答4:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

.PHONY: install

表示“安装”一词不代表此 Makefile 中的文件名;

表示 Makefile 与同一目录中名为“install”的文件无关。

答5:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

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

答6:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

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

.PHONY 是 make 的 Special Built-in Target Names 之一。还有其他您可能感兴趣的目标,因此值得浏览这些参考资料。

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

您可能还对 make 的 Standard Targets 感兴趣,例如 all 和 clean。

答7:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

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

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

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

还有另一种声明虚假目标的方法:只需将 :: 放在没有先决条件的情况下:

all :: prog1 prog2

...

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

:: 有其他特殊含义,请参阅 here,但没有先决条件,它总是执行配方,即使目标已经存在,因此充当假目标。

你确定这就是“::”的意思吗?在 doc of "::" 中,根本没有提到 .PHONY,并且“::”也用于非假目标。

事实上,只有在没有先决条件的情况下使用 :: 时才暗示 phony,请参阅上面 gnu make 文档中的链接。

没用。看到 stat("target" 和 makefile "target ::" 行的 strace 输出。唯一的 .PHONY: 目标工作。GNU Make 4.1 为 x86_64-pc-linux-gnu 构建

答8:

huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!

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

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

你可以玩这个:

首先做’make prepare’来准备“源文件”

通过触摸特定文件以查看它们的更新来解决这个问题

您可以看到 fileall 通过虚假目标间接依赖于 file1 - 但由于这种依赖关系,它总是会被重建。如果您将 fileall 中的依赖关系从 filefwd 更改为 file,现在 fileall 不会每次都重建,但只有当任何依赖目标作为文件过时时才会重建。

Linux 内核 Makefile 不使用多个 .PHONY 目标。他们广泛使用多行变量 PHONY(如 PHONY += target1 target2),makefile 的最后一行是:.PHONY: $(PHONY)

那条评论是要关注什么?

答9:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

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

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

如果没有 PHONY,make superclean 将触发 clean、andsomethingelse 和 catcher superclean;但是对于 PHONY,make superclean 不会触发 catcher superclean。

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

但是,superclean 目标确实是假的,因此 make 会尝试将它与任何其他为 superclean 目标提供 deps 的东西叠加在一起——这包括其他 superclean 目标和 % 目标。

请注意,我们根本没有说任何关于 andsomethingelse 或 blah 的内容,因此它们显然是针对捕手的。

输出看起来像这样:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah

原文链接:https://www.huntsbot.com/qa/YlPe/what-is-the-purpose-of-phony-in-a-makefile?lang=zh_CN&from=csdn

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值