伪造目标实际上不是文件名。只是当您进行显式请求时要执行的配方的名称。使用伪造目标的原因有两个:避免与同名文件发生冲突,并提高性能。
如果您编写了一条其配方不会创建目标文件的规则,则每次重新制作目标文件时都会执行密码。下面是一个示例:
由于rm命令不会创建名为clean的文件,因此可能永远不会存在该文件。因此,每次您说“ make clean”时,都会执行rm命令。
在此示例中,如果在此目录中创建了名为clean的文件,则clean目标将无法正常工作。由于没有先决条件,因此将始终将clean视为最新的,并且不会执行其配方。为避免此问题,您可以通过使目标成为特殊目标.PHONY(请参阅特殊内置目标名称)的先决条件,将目标明确声明为虚假:
完成此操作后,无论是否存在名为clean的文件,“ make clean”都将运行该配方。
Phony目标也可以与make的递归调用结合使用(请参阅make的递归使用)。在这种情况下,makefile通常包含一个变量,该变量列出了要构建的多个子目录。一种简单的处理方法是用一个在子目录上循环的配方定义一个规则,如下所示:
SUBDIRS = foo bar bazsubdirs:用于$(SUBDIRS)中的目录;做\ $(MAKE)-C $$ dir; \完成
但是,此方法存在问题。首先,此规则将忽略在子制造商中检测到的任何错误,因此即使一个失败,它也将继续构建其余目录。通过添加shell命令来记录错误并退出即可解决此问题,但是即使使用-koption调用make,thenit也会这样做,这是不幸的。其次,也许更重要的是,由于只有一条规则,因此您无法利用make的能力来并行构建目标(请参阅并行执行)。
通过将子目录声明为.PHONY目标(您必须这样做,因为子目录显然始终存在;否则将不会建立),可以消除以下问题:
在这里,我们还声明,直到baz子目录完成后,才能构建foo子目录;尝试并行构建时,这种关系声明特别重要。
对于.PHONY目标,将跳过隐式规则搜索(请参阅隐式规则)。这就是将目标声明为.PHONY有助于提高性能的原因,即使您不必担心实际文件的存在。
虚假目标不应成为真实目标文件的前提;如果是,每次make更新该文件时都会运行其配方。只要伪造目标永远不是真实目标的先决条件,那么只有当伪造目标是指定目标时,才会执行伪造目标配方(请参阅指定目标的参数)。
伪装目标可能有先决条件。当一个目录包含多个程序时,最方便的是在onemakefile ./Makefile中描述所有程序。由于默认情况下重制的目标将是makefile中的第一个目标,因此通常将其设为名为“ all”的假冒目标,并将其作为所有单个程序的先决条件。例如:
全部:prog1 prog2 prog3.PHONY:allprog1:prog1.o utils.o cc -o prog1 prog1.o utils.oprog2:prog2.o cc -o prog2 prog2.oprog3:prog3.o sort.o utils.o cc -o prog3 prog3.o sort.o utils.o
现在,您可以说“ make”来重做所有三个程序,或者指定要重做的程序作为参数(如“ make prog1prog3”中一样)。 语音不是继承的:伪音目标的前提条件本身不是伪音,除非明确声明是假音。 当一个假想目标是另一个假想目标的先决条件时,它充当另一个假想目标的子例程。 例如,这里的“ make cleanall”将删除目标文件,差异文件和文件程序: .PHONY:cleanall cleanobj cleandiffcleanall:cleanobj cleandiff rm程序cleanobj:rm * .ocleandiff:rm * .diff