【问题标题】:stop on error when target of makefile rule is a foreach function当 makefile 规则的目标是 foreach 函数时停止错误
【发布时间】:2012-06-30 13:39:57
【问题描述】:

我有一个makefile,它定义了几个目标是foreach 函数的规则。

$(foreach var,$(list), $($(var)_stuff) $($(var)_more_stuff)):
    @echo Building $@ from $^...
    $(CC) $(FLAGS) ...

有没有办法让make在遇到错误时退出而不遍历整个列表。

【问题讨论】:

  • make 不会在第一个错误时退出,除非您通过了-k 命令行选项?
  • 显然不是这样。 forloop 继续。我不确定这种格式甚至是“规则”。但它有效
  • 我……不知道该说什么。您能否给我们一个最小的完整示例,以便我们可以看到 $($(var)_stuff) 应该做什么?或许可以解释一下您预见到的错误类型?
  • 它非常复杂,应该与问题无关。 $(CC) 使用从 foreach 文本扩展的选项编译文件。只有当其中一个编译失败时,它才会继续。它不会自动停止 I THINK 因为没有列出依赖项。我正在寻找一种方法让它停止。
  • 第一行应该做什么?您是否希望 foreach 语句扩展为目标列表?

标签: makefile gnu-make


【解决方案1】:

在执行任何条规则之前,foreach 已被完全评估和替换。因此,这种行为应该与您在不使用foreach 的情况下对规则进行硬编码一样。换句话说,它与问题没有直接关系。

对于您所看到的内容只有几种可能的解释,主要在手册here 中进行了描述:

  • 您正在使用 -k--keep-going 运行 Make
  • 您正在使用 -i--ignore-errors 运行 Make
  • 您的目标被定义为特殊 .IGNORE 目标的先决条件
  • 您的食谱以- 开头
  • 您的配方实际上并未返回非零退出状态

【讨论】:

  • 从我能找到的所有文档来看,你是对的。但我没有使用-k 或-keepgoing,-I 或--Ignore-errors。 make 文件中的任何地方都没有 .IGNORE。没有一个食谱以 - 它们都以 c:/ghs/ppc424/ccppc 开头。我终于想出了如何检查退出状态。它是 1。所以我很松散
  • 我将尝试创建一个更简单的示例,我可以将整个代码发布到。
  • @8bitwide:酷。如果您创建一个更简单的示例,如果我能发现任何新内容,我会很乐意更新我的答案。
【解决方案2】:

一种解决方法是在失败时“手动”调用exit

例如,假设我们有一个名为 scripts 的目录,其中包含许多我们想要执行的 shell 脚本(文件名以 .sh 结尾)。

然后是这样的变量声明:

LIST_OF_SCRIPTS ?= $(wildcard scripts/*.sh)

将为我们提供这些脚本的列表,以及这样的目标:

run-all-scripts
  @$(foreach scriptfile,$(LIST_OF_SCRIPTS),$(scriptfile);)

将运行所有这些脚本,但正如您所注意到的,无论其中一个脚本是否返回错误代码,foreach 循环都会继续进行。在命令中添加|| exit 将强制子命令在出错时退出,然后 Make 会将其视为失败。

例如,

run-all-scripts
  @$(foreach scriptfile,$(LIST_OF_SCRIPTS),$(scriptfile) || exit;)

会做你想做的(我相信)。

具体来说,使用您的伪代码示例,我认为您想要这样的东西:

$(foreach var,$(list), $($(var)_stuff) $($(var)_more_stuff)):
    @echo Building $@ from $^...
    ($(CC) $(FLAGS) ...) || exit

(我所做的所有更改是将(CC) $(FLAGS) ... 位包装在括号中并附加|| exit 以使其在出错时失败)。

【讨论】:

  • 我刚刚遇到了这个问题,foreach 循环没有因错误而终止,这个解决方案对我有用。 @Oleg 得到了在没有明确检查错误代码的情况下它不会终止的原因。感谢您的解决方案!
  • 谢谢,添加'|| exit' 是我的环境中唯一可行的事情,而且它奏效了。
【解决方案3】:

不确定您的示例,但问题可能出在; - 请查看Makefile : show and execute

dirs = $(shell ls)
clean:
    $(foreach dir,$(dirs),echo $(dir);)

生产:

$ make clean
echo bin; echo install.sh; echo Makefile; echo README.md; echo utils;

所以只检查最后一个命令的退出代码:echo utils

【讨论】:

  • set -e 可能会解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-10
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多