我有一个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失败的步骤?
答案 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
如果由于某种原因无法做到这一点,您将必须:
step2
)传递到另一个(run
),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