让我们考虑一下这个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
指示(时,代码才会闪存到某些设备。如您所见,只有在flash
之前评估build
规则时,此生成文件才有效,因为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
但我仍然感兴趣的是,为什么订单不能在多线程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
。