让我们考虑一下这个
makefile
:
.PHONY: flash_bin
flash_bin: | build flash
CODE_CHANGED=0
.PHONY: build
build:
@echo "Run Build Process"
@if [ ! -f build_process ] || [ $(CODE_CHANGED) -eq 1 ]; then \
touch build_process; \
fi;
flash: tmp_config_file build_process
@echo "Flash to ESP"
@touch flash
tmp_config_file:
@echo "Config flashed"
@touch $@
乍一看,这段代码可能没有意义,但这只是一个简化版本,它说明了以下问题:
运行
make
时,输出符合预期。首先,执行build
规则。它可能会重建一些代码,通过文件build_process
指示。 之后,flash
规则被触发。仅当配置文件已较早刷新(通过 tmp_config_file
指示)或配置文件已较早重建(通过 build_process
指示)时,代码才会刷新到某些设备。正如您所看到的,只有在build
规则在之前flash
求值时,此makefile才有效,因为flash
取决于build
的结果。
到目前为止,一切都很好。现在我运行 make -j8 并得到
make: *** No rule to make target 'build_process', needed by 'flash'. Stop.
显然,仅订单先决条件的顺序不再保留,并且 make 不会等到 build
完成。
这是否意味着仅订单先决条件只能在单线程 makefile 中工作?如果是这样,为什么?是否可以保持顺序,但以多线程方式执行各个规则?
编辑:我知道,你可以通过这种方式强制预期的行为:
.PHONY: flash_bin
flash_bin:
$(MAKE) build; \
$(MAKE) flash
但我仍然感兴趣为什么 order-only 不能在多线程 makefile 中可靠地使用
当你并行运行
make
时,这意味着它可以安排多个目标同时执行。由于目标 build
和 flash
之间没有定义依赖关系,因此 make
假设它们可以同时运行。它碰巧意外地在单线程中工作,因为 Makefile
创建了一个它未声明的文件,并且 flash
依赖于这个意外创建的文件。
它甚至不需要多线程来使其失败,只需运行目标
flash
而无需事先运行build
,例如:
$ make flash
Config flashed
make: *** No rule to make target 'build_process', needed by 'flash'. Stop.
我相信您应该使
flash
依赖于 build
,或者将目标 build
重命名为 build_process
。