“的顺序”;“仅限订购”;未保存在多线程makefile中的先决条件 让我们考虑一下这个代码> MaFixFix< /C>:< /P> .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 $@

“的顺序”;“仅限订购”;未保存在多线程makefile中的先决条件 让我们考虑一下这个代码> MaFixFix< /C>:< /P> .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 $@,makefile,gnu-make,Makefile,Gnu Make,乍一看,这段代码可能没有意义,但这只是一个简化版本,说明了以下问题: 运行make时,输出与预期一致。首先,执行build规则。它可能会重新生成一些代码,如文件build\u过程所示之后,将触发闪烁规则。只有在配置文件已提前刷新(通过tmp\u config\u file指示)或已提前重建(通过build\u process指示)的情况下,才会将代码闪存到某些设备。如您所见,此生成文件仅在build规则在flash之前进行评估时有效,因为flash取决于build的结果 到目前为止,一切顺利。现

乍一看,这段代码可能没有意义,但这只是一个简化版本,说明了以下问题:

运行
make
时,输出与预期一致。首先,执行
build
规则。它可能会重新生成一些代码,如文件
build\u过程所示之后,将触发
闪烁
规则。只有在配置文件已提前刷新(通过
tmp\u config\u file
指示)或已提前重建(通过
build\u process
指示)的情况下,才会将代码闪存到某些设备。如您所见,此生成文件仅在
build
规则在
flash
之前进行评估时有效,因为
flash
取决于
build
的结果

到目前为止,一切顺利。现在我运行了make-j8,得到了一个
make:**“flash”所需的目标“构建过程”没有规则。停止。
显然,仅订单先决条件的顺序不再保留,make不会等到
构建
完成

这是否意味着只有订单的先决条件只能在单线程的makefile中工作?若然,原因为何?是否可以保持顺序,但以多线程方式执行单个规则

编辑:我知道,您可以通过以下方式强制执行预期行为:

.PHONY: flash_bin
flash_bin: 
  $(MAKE) build; \
  $(MAKE) flash

但我仍然感兴趣的是,为什么order only不能在多线程makefile中可靠地使用

当您并行运行
make
时,这意味着它可以同时调度多个目标的执行。由于目标
build
flash
之间没有定义依赖关系,
make
假设它们可以同时运行。它碰巧在单线程中意外工作,因为
Makefile
创建了一个它没有声明的文件,
flash
依赖于这个意外创建的文件

它甚至不需要多线程来使其失败,只需运行target
flash
,而无需事先运行
build
,例如:

$ make flash
Config flashed
make: *** No rule to make target 'build_process', needed by 'flash'.  Stop.

我认为你应该让
flash
依赖于
build
,或者将target
build
重命名为
build\u-process

我认为真正的问题是你的
flash
目标确实应该依赖于
build
配方的副作用……或者,将
build
目标重命名为
build\u process
(因为它实际生成的是
),并删除
.PHONY
指令。这会稍微改变行为。必须始终执行
build
的配方,以确定代码是否已重建。如果我将
build
目标重命名为
build\u进程
,则只会执行一次。您指出
build
flash
应在
flash\u bin
之前生成。你从来没有告诉make在flash之前也应该编译
build
。而且您没有告诉make是
build
生成
build\u过程的
flash
的先决条件。试着尽可能地消除所有这些非文件目标,并专注于真正的文件。提示:即使是非常大的生成文件集也可以用作先决条件,并且可以使用
$(shell find…
$(通配符…
创建文件列表。如果您在order only dependency(
| build flash
->
| flash build
)中更改生成和闪存的顺序,对于单线程make,您将获得相同的行为。