Gnu make:运行shell命令并使用退出代码设置全局变量

问题描述

我有一个复杂的脚本c.sh,用于测试机器make某些环境正在运行。应该使用bash运行它。它会打印一些有用的信息,以供stdoutstderr使用。如果满足某些特殊条件,则c.sh存在,退出代码为1,否则为0。如果出现问题,则可能会出现其他退出代码。根据退出代码,我要执行不同的配方。

all:
    # test using c.sh

everything-OK: # prerequisites
    # *recurse* on this if c.sh exits with zero
    # e.g. "$(MAKE) everything-OK" in all if ...

something-went-wrong: # prerequisites
    # *recurse* on this if c.sh exists with anything else

我找到了this有用的答案,但并没有太大帮助。由于我似乎无法使递归工作或取决于退出代码的if开关。刚开始使用$(.SHELLSTATUS)看起来很有希望,但是该解决方案不会立即从脚本中重定向stdout

替代解决方案可能看起来像这样:

EVERYTHING_OK = 0 # 0: false,1: true

all:
    # test using c.sh
    # set EVERYTHING_OK depending on exit code
    $(MAKE) second-stage

ifeq (1,EVERYTHING_OK)
second-stage: # prerequisites
    # ...
else
second-stage: # prerequisites
    # ...
endif

(我喜欢这个,因为我可以将if条件放在宏中)

解决方法

如果您只对脚本的退出状态感兴趣,则最简单的方法可能是将其捕获到make变量中,并在make条件或目标名称中使用它。目标名称示例:

C_EXIT_STATUS := $(shell ./c.sh &> /dev/null; echo $$?)

.PHONY: all everithing-%

all: everything-$(C_EXIT_STATUS)

everything-0:
    @echo "all right"

everything-%:
    @echo "not all right ($*)"

然后,如果./c.sh以状态0退出:

$ make all
all right

如果退出状态为7:

$ make all
not all right (7)

带有条件的示例:

C_EXIT_STATUS := $(shell ./c.sh &> /dev/null; echo $$?)

.PHONY: all

ifeq ($(C_EXIT_STATUS),0)
all:
    @echo "all right"
else
all:
    @echo "not all right ($(C_EXIT_STATUS))"
endif

最后但并非最不重要的一点,正如您自己建议的那样,递归make也是一种选择:

.PHONY: all

ifeq ($(C_EXIT_STATUS),)
all:
    s=0; ./c.sh &> /dev/null || s=$$?; \
    $(MAKE) C_EXIT_STATUS=$$s
else ifeq ($(C_EXIT_STATUS),0)
all:
    @echo "all right"
else
all:
    @echo "not all right ($(C_EXIT_STATUS))"
endif