Linux makefile:在每个recipie中重新分配变量以存储步骤名称

Linux makefile:在每个recipie中重新分配变量以存储步骤名称,linux,makefile,gnu-make,Linux,Makefile,Gnu Make,我有一个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:

我有一个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错误(找不到temp)


如何设置变量以便打印出makefile失败的步骤?

注意:您不应该在食谱中使用
make
。改用
$(MAKE)
。这有几个很好的理由,你可以在下面的文章中找到

Make变量和shell变量是不同的。当你写作时:

temp = "start"
step1:
    temp = "step1"
它是make语法,
temp
是make变量。当你写作时:

temp = "start"
step1:
    temp = "step1"
temp
是一个shell变量,您会得到一个语法错误,因为shell变量赋值为
temp=“step1”
(在
=
周围没有空格)

但这并不是全部。配方的每一行都由一个单独的shell运行(除非makefile中出现特殊目标),不同的配方不能由同一个shell实例运行(不管
.ONESHELL
)。因此,您不能期望
run\u failed
规则的配方访问与
step2
配方的一行指定的shell变量相同的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
如果由于任何原因,这是不可能的,您必须:

  • 将失败信息从一个配方(
    step2
    )传递到另一个配方(
    run
  • 将故障信息从一个子生成调用(
    run all
    )传递到另一个子生成调用(
    run\u 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
    

    感谢您提供的信息,这是有意义的+1。但它不完全符合我的要求。。。我真的想要一个持久的“状态”,这样我就可以在最后将相关的最终状态打印到文件中。我猜这可能是不可能的?(也就是说,不能在配方中设置make变量?你可以在配方中设置make变量,但由于你不掌握配方的运行顺序(更不用说make可以并行运行),这将没有什么帮助。我建议你编辑你的问题,并从清楚地解释你真正想要什么开始?例如。“我希望完全保持沉默,只在最后打印出失败的配方(如果有)?我相信我可以使用依赖项强制订购。我仍然希望知道如何在配方中重新分配变量,如果(如您所述)你能做到吗?-我暂时还是用我的问题标题,因为我还是很想知道怎么做:)很抱歉坚持,但您想做的事情可能可以用更简单的方法来完成。在配方中混合make语句和shell语句非常笨拙且容易出错。此外,使用您的解决方案,您还必须确保在配方中设置的make变量传递给子make。实际上,它将在
    make ru中设置n_all
    和在
    make run_中使用失败
    。无论如何,您已经收到警告,如果您坚持,可以在配方中用于分配make变量的make函数是。谢谢,我真的很注意您的警告…但我仍然真的很想知道如何做到这一点。然后我可能会重新考虑:)。因此我正在尝试使用eval将步骤1中的行设置为
    $(eval temp=“step1”)
    ,然后我在下一行回显temp,它将打印
    step1
    ,但是在最后一步(错误步骤)中,它仍然打印
    步骤开始时失败的
    。。因此,看起来该变量没有保留在生成文件中:((或者我做错了)