Makefile -- 伪目标

伪目标在Makefile中用于避免与同名文件冲突和提高性能。它们不会创建实际文件,因此每次指定时命令都会执行。通过将目标声明为`.PHONY`的依赖,即使存在同名文件,命令也会执行。伪目标在递归make调用和并行构建中也很有用,可确保子目录构建的正确顺序和并行执行。伪目标可以有依赖,但不应直接依赖于真实文件,否则每次更新文件时都会执行命令。
摘要由CSDN通过智能技术生成

Makefile -- 伪目标


(翻译自 GNU make 4.6 – Phony Targets)

伪目标不是一个真实的文件名。当用 make 显式指定请求时,伪目标仅仅是将要执行的命令的名字。有两个理由去使用伪目标:一是避免和相同的文件名产生冲突;二是提升性能。

如果你写了一条规则(rule),而该规则的命令不会实际创建目标文件,那么 make 每次到达该目标时,其命令总会被执行。例如:

clean:
		rm *.o temp

因为 rm 命令不会创建名为 clean 的文件,也许永远也不存在这样的文件。因此,每次执行 make clean 的时候,rm 命令都会被执行。

上面的例子中,如果 Makefile 同目录下存在名为 clean 的文件,clean 目标的执行将会出现问题。因为没有依赖文件,clean 总是被认为是最新的,所以 clean 的命令永远不会被执行。为了避免这种问题,可以显式的将其声明为伪目标,方法是让它成为特殊目标 .PHONY 的依赖目标,如下所示:

.PHONY: clean
clean:
		rm *.o temp

一旦将 clean 指定为伪目标,无论名为 clean 的文件是否存在,命令总会被执行。

伪目标在串联 make 的递归调用时也非常有用(请参阅 5.7 Recursive Use of make)。在这种情形下,makefile 总会包含一个变量,该变量列出了多个将要被构建的子目录。一种简单的处理方法是定义一个规则,其命令通过循环遍历子目录,如下:

SUBDIRS = foo bar baz

subdirs:
		for dir in $(SUBDIRS); do \
			$(MAKE) -C $$dir; \
		done

然而,这种方法存在很多问题。首先,子目录的构建中, make 检测到的任何错误都会被忽略,也就是说一条命令执行失败时,将会继续构建其余的目录。当然,通过添加 shell 命令可以解决这个问题,但不幸的是,这会使得 make-k 参数失效。此外,更重要的一点是,你将无法利用 make 并行构建(请参阅 5.4 Parallel Execution)的能力,因为只有一条规则。

你可以通过将子目录声明为伪目标(你应当这么做,因为很显然子目录总会存在,否则将不会构建)解决这些问题。

SUBDIRS = foo bar baz

.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

$(SUBDIRS):
		$(MAKE) -C $@
		
foo: baz

这里我们做了这样的声明,baz 子目录完成构建前,foo 子目录不会构建。在并行构建中,这种关系声明非常重要。

对于 .PHONY 目标,隐式规则(请参阅 [10. 隐式规则](#10. 隐式规则))的搜索过程将会被跳过。这就是 .PHONY 能提升性能的原因,甚至你根本就不用关心真实文件是否存在。

伪目标不应当是一个真实目标文件的依赖,如果是,那么每次 make 更新这个文件的时候,伪目标的命令都会被执行。只要伪目标不是一个真实目标的依赖,那么只有伪目标被指定为最终目标时,其命令才会被执行(请参阅 [9.2 通过参数指定最终目标](#9.2 通过参数指定最终目标))。

伪目标也可以有依赖。当一个目录下包含多个程序时,通过一个 ./Makefile 描述所有程序将非常便利。因为 makefile 里面的第一个目标时默认执行的目标,所以通常将命名为 all 的伪目标作为第一个目标,并将所有独立的程序作为其依赖。例如:

all: prog1 prog2 prog3
.PHONY: all

prog1: prog1.o utils.o
		cc -o prog1 prog1.o utils.o
		
prog2: prog2.o
		cc -o prog2 prog2.o
		
prog1: prog1.o sort.o utils.o
		cc -o prog3 prog3.o sort.o utils.o

你可以通过 make 执行者三个程序,或者将他们中的部分指定为 make 参数(如:make prog1 prog3)。伪目标不能继承,也就是说其依赖本身不是伪目标,除非显式指定。

当一个伪目标是另一个伪目标的依赖时,其将成为另一个伪目标的子路径。例如,下面的 make cleanall 将会删除目标文件,差异文件和程序文件。

.PHONY: cleanall cleanobj cleandiff

cleanall: cleanobj cleandiff
		rm program
		
cleanobj:
		rm *.o
		
cleandiff:
		rm *.diff
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值