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

时间:2018-07-30 08:24:17

标签: 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:
    echo temp = "step3"

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

我用$(error ...)命令强迫这个小例子在步骤2中失败。 我的问题是我想在每个步骤中设置变量temp。但是我不知道该怎么做。

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

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

1 个答案:

答案 0 :(得分:2)

注意:您不应在食谱中使用make。请改用$(MAKE)。在GNU make manual中有很多很好的原因。

使变量和外壳变量不同。当您写时:

temp = "start"

它是make语法,temp是一个make变量。当您写时:

step1:
    temp = "step1"

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

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

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

$ 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. 将失败信息从一个子生成调用(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