make工具的手册页说 -
虚假目标有用性的另一个例子是与make的递归调用相结合(有关更多信息,请参阅make的递归使用)。在这种情况下,makefile通常包含一个变量,该变量列出了要构建的多个子目录。处理此问题的一种方法是使用一个规则,其配方是子目录上的shell循环,如下所示:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
然而,这种方法存在问题。首先,此规则会忽略在子make中检测到的任何错误,因此即使一个目录失败,它也会继续构建其余的目录。这可以通过添加shell命令来记录错误并退出来解决,但是即使使用-k选项调用make也会这样做,这是不幸的。其次,也许更重要的是,你不能利用make并行构建目标的能力(参见并行执行),因为只有一个规则。
通过将子目录声明为虚假目标(您必须这样做,因为子目录显然始终存在;否则它不会被构建)您可以删除这些问题:
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
foo: baz
此处我们还声明,在baz子目录完成之后才能构建foo子目录;在尝试并行构建时,这种关系声明尤为重要。
有人可以解释上面提到的第二个代码如何实现并行执行? 我不明白Phony Targets是如何帮助的?
答案 0 :(得分:1)
让我用简单的语言说出来,你会得到一些想法
如arved
提到的-j2
选项可以告诉make文件运行两个并行线程。
如果两个目标是独立的,则检查目标及其依赖性,然后可以并行构建它们。
让我展开第二个makefile并将其写成简单
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
bar:
$(MAKE) -C bar
baz:
$(MAKE) -C baz
foo: baz
$(MAKE) -C foo
现在看上面的案例
bar和baz依赖于什么,所以它们可以并行构建
foo取决于baz所以它不能与bar或baz平行构建
因此,在上述情况下,您确保make文件使用并行构建文件的能力。
现在拿你提到的第一个make文件
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
所以,如果你没有提到。上面代码的.PHONY目标对你来说很棘手,但是会失去构建并行的能力。
仔细观察。只有一个目标subdirs
运行三个循环。所有三个循环将一个接一个地运行,因此没有并行性。
记住拇指规则。如果目标彼此独立,Make可以使用并行构建,因此它可以构建独立的目标并行而没有任何依赖性问题
答案 1 :(得分:0)
如果你没有将子目录标记为假冒,那将检查名为foo的文件是否存在并立即将目标标记为已完成,因为目录“foo”存在
标记它PHONY确保即使存在文件也始终重建目标。
虽然在示例1中,只能使用一个make进程来顺序构建所有目录,但在示例2中,make -j2将导致bar和baz目标并行构建。
答案 2 :(得分:0)
这个想法是使子目标成为目标,因此make可以并行地“构建”它们。它们之间没有依赖关系,有一个明确的规则是必须要做什么来“构建”它们,make可以同时处理多个。 For
循环将按顺序逐个构建所有内容,迭代后迭代。
Phony只是一种技术性,我们需要它,因为否则make会看到有一些名称为subdir的东西,并且它很久以前被修改过,所以没有必要做。如果有人创建名为all
的文件,则必须将clean
,all
等声明为虚假。
答案 3 :(得分:0)
当目标列出多个先决条件时,可以实现并行:
all: a b c
a: a.c
b: b.c
c: c.c
由于 a , b 和 c 是所有行中列出的先决条件,因此可以并行运行命令。构建先决条件后,可以执行所有规则。所以:
$ make -j3 all
将允许并行构建3个先决条件。
.PHONY:目标声明会阻止:
$ make -t
创建一个零长度目标。