makefile:在每个配方中分配变量来存储步骤名称

makefile: Reassign variable in each recipie to store the step name

我有一个 makefile,它在失败时运行规则。我在下面写了一个小例子:

temp = "start"

run:
    make run_all || make run_failed

run_all: step1
run_all: step2
run_all: step3
run_all: ;

step1:
    echo temp = "step1"

step2:
    echo temp = "step2"
    $(error fail test)

step3:
    echo temp = "step3"

run_failed:
    @echo "failed on step ${temp}"

我使用 $(error ...) 命令强制这个小示例在步骤 2 中失败。 我遇到的问题是我想在每一步都设置可变温度。但是我不知道该怎么做。

如果它在每个步骤中删除 temp = 之前的 "echo",我只会收到 shell 错误(找不到临时文件)。

如何设置我的变量以便打印出生成文件失败的步骤?

注意:您不应在食谱中使用 make。请改用 $(MAKE)。您可以在 GNU make manual.

中找到几个很好的理由

make变量和shell变量不同。当你写:

temp = "start"

是make语法,temp是make变量。当你写:

step1:
    temp = "step1"

temp 是一个 shell 变量,您会收到语法错误,因为 shell 变量赋值是 temp="step1"= 周围没有空格)。

但这还不是全部。配方的每一行都是 运行 由一个单独的 shell (除非特殊目标 .ONESHELL 出现在 makefile 中)并且不同的配方不能 运行 由相同的 shell 实例(不考虑 .ONESHELL)。因此,您不能指望 run_failed 规则的配方能够访问与 step2 配方的一行分配的相同 shell 变量 temp .

无论如何,当 make 在配方上失败时,它会告诉您出了什么问题,包括失败的规则。如果这还不够,最好的选择是为每个食谱配备一条错误消息:

$ cat fail
#!/usr/bin/env bash
exit 1

$ cat Makefile
run: step1 step2 step3

step1 step3:
    @echo "doing $@" || echo "$@ failed"

step2:
    @./fail || echo "$@ failed"

$ make step1
doing step1

$ make run
doing step1
step2 failed
doing step3

如果出于任何原因无法做到这一点,您将不得不:

  1. 将失败信息从一个配方 (step2) 传递到另一个配方 (run),
  2. 将失败信息从一个子 make 调用 (run-all) 传递到另一个 (run_failed)。

所有这一切都将非常困难,除非您使用日志文件并告诉 make 不要 运行 在并行模式下:

$ cat Makefile
.NOTPARALLEL:

FAILED  := failed.txt

run:
    @{ rm -f $(FAILED) && $(MAKE) run_all; } || $(MAKE) run_failed

run_all: step1 step2 step3

step1 step3:
    @echo "doing $@" || { echo "$@ failed" >> $(FAILED) && exit 1; }

step2:
    @./fail || { echo "$@ failed" >> $(FAILED) && exit 1; }

run_failed:
    @cat $(FAILED)

$ make --no-print-directory
doing step1
Makefile:14: recipe for target 'step2' failed
make[1]: *** [step2] Error 1
step2 failed