【问题标题】:How can I trap errors and interrupts in GNU make?如何在 GNU make 中捕获错误和中断?
【发布时间】:2009-06-10 07:06:54
【问题描述】:

我想知道是否有办法在 GNU make 中实现 trap,类似于 BASH 中的内置方法?

如果用户按下CTRL-C,或者如果make 本身失败(非零退出),我想调用一个特定的目标或宏。

【问题讨论】:

  • +1 表示有趣的问题,即使你在做什么听起来是个坏主意。

标签: makefile signals gnu-make bash-trap


【解决方案1】:

此时,GNU make 还没有原生支持。

但是有一个可靠的解决方法:

.PHONY: internal-target external-target

external-target:
  bash -c "trap 'trap - SIGINT SIGTERM ERR; <DO CLEANUP HERE>; exit 1' SIGINT SIGTERM ERR; $(MAKE) internal-target"

internal-target:
  echo "doing stuff here"

这会捕获中断、终止和任何非零退出代码。

请注意$(MAKE),以便 cmdline 覆盖并将 make 选项传递给 submake。

在陷阱中:

  • 清除陷阱处理程序(带 -)
  • 进行清理
  • 以非零退出状态退出,因此构建自动化工具会报告失败的构建。

DELETE_ON_ERROR 不适用于目录,因此这是在 mktemp -d 之后清理的关键,例如

用有效的 CMD 替换 &lt;DO CLEANUP HERE&gt;

【讨论】:

  • 除了你的回声中的嵌套引用,这当然是非法的,这似乎不起作用,至少对于我想要完成的事情。一个人应该如何使用它?假设我的 makefile 只有一个具有睡眠和触摸功能的目标,例如 @andrewdotn 示例(忽略 .DELETE_ON_ERROR),您将如何修改它以使用此解决方法?
  • 请查看编辑。回声“在这里做事”将是睡眠/触摸。 DO CLEANUP HERE 类似于,echo you press ctrl-c
【解决方案2】:

@kevinf 答案的简化版本,对于基本情况来说似乎已经足够好了:

run:
    bash -c "trap 'docker-compose down' EXIT; docker-compose up --build"

(这个例子是有原因的:docker-compose up 确实说

什么时候 命令退出,所有容器都停止。

但它不会像docker run --rm 那样rm 停止容器,因此您仍然可以通过docker ps -a 看到它们。)

【讨论】:

  • 当我尝试这个时我仍然看到recipe for target 'run' failed ... make: *** [run] Interrupt,并且make 目标没有运行docker-compose down 命令。 (我有这个答案中描述的确切用例。)
  • 这对我来说确实适用于确保在启动后运行的确切用例。
【解决方案3】:

没有。 GNU make 的信号处理已经有很多不足之处了。在其信号处理程序中,它调用像 printf 这样的函数,这些函数在信号处理程序中调用是不安全的。我已经看到这会导致问题,例如,如果 stderr 被重定向到 stdout.DELETE_ON_ERROR 规则并不总是运行。

例如,在 CentOS 7.4 机器上:

  1. 创建以下Makefile

    .DELETE_ON_ERROR:
    
    foo:
            touch $@
            sleep 10
    
  2. vim中打开并运行:make

  3. 在它休眠时,按 Ctrl-C

Vim/制作打印

Press ENTER or type command to continue
touch foo
sleep 10
^C
shell returned 130

Interrupt: Press ENTER or type command to continue

Make 收到了一个中断信号,但foo 仍然存在。

【讨论】:

  • 你有一些.DELETE_ON_ERROR 不起作用的例子吗?这是 make 实现中的错误吗?
  • @HakanBaba 添加详细信息。
【解决方案4】:

Make 不支持它,但使用 BASH 技巧你可以完成类似的事情。

default: complete

complete: do_mount
        echo "Do something here..."

do_mount:
        mkdir -p "$(MOUNTPOINT)"
        ( while ps -p $$PPID >/dev/null ; do \
                sleep 1 ; \
        done ; \
        unmount "$(MOUNTPOINT)" \
        ) &
        mount "$(MOUNTSOURCE)" "$(MOUNTPOINT)" -o bind

“卸载”将在“制作”完成后运行。如果您尝试清理在构建期间可能发生但在“make”退出时未正常清理的操作,这通常是一个令人满意的解决方案。

【讨论】:

    【解决方案5】:

    没有。据我所知,没有这样的功能。

    【讨论】:

      【解决方案6】:

      make 产生返回码。据我现在记得,它返回 0 表示成功,2 表示失败(请查看文档)。因此,例如,将 make 包装在 shell 脚本中就足够了吗?

      【讨论】:

      • 我可以这样做,但如果可能的话尽量避免它,它是独立的,我尝试保持这种状态。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      • 1970-01-01
      相关资源
      最近更新 更多