Makefile 如何捕获GNU make中的错误和中断?

Makefile 如何捕获GNU make中的错误和中断?,makefile,signals,gnu-make,bash-trap,Makefile,Signals,Gnu Make,Bash Trap,我想知道是否有一种方法可以在GNUmake中实现trap,类似于BASH中内置的方法 如果用户按CTRL-C键,或者如果make本身失败(非零退出),我想调用特定的目标或宏。否。据我所知,没有此类功能。make生成返回代码。就我现在所记得的,它返回0表示成功,返回2表示失败(请查看文档)。因此,例如,将make封装在shell脚本中就足够了吗?否。gnumake的信号处理已经有很多需要改进的地方。在信号处理程序中,它调用像printf这样的函数,这些函数在信号处理程序中调用是不安全的。我发现这会

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


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

否。据我所知,没有此类功能。

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

否。gnumake的信号处理已经有很多需要改进的地方。在信号处理程序中,它调用像
printf
这样的函数,这些函数在信号处理程序中调用是不安全的。我发现这会导致问题,例如
。如果
stderr
被重定向到
stdout
,则在出错时删除规则并不总是运行

例如,在CentOS 7.4机箱上:

  • 创建以下
    Makefile

    .DELETE_ON_ERROR:
    
    foo:
            touch $@
            sleep 10
    
  • vim
    中打开它,然后运行
    :make

  • 当它睡觉时,按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
    仍然存在。

    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”退出时未正常清理的操作,这通常是一个令人满意的解决方案。

    此时,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"
    
    .PHONY:内部目标外部目标
    外部目标:
    bash-c“trap”trap-SIGINT SIGTERM ERR;;退出1“SIGINT SIGTERM ERR;$(MAKE)内部目标”
    内部目标:
    echo“在这里做事”
    
    它捕获中断、终止和任何非零退出代码

    请注意
    $(MAKE)
    以便将cmdline覆盖和MAKE选项传递给submake

    关于陷阱:

    • 清除陷阱处理程序(带-)
    • 清理
    • 退出状态为非零,因此生成自动化工具会报告失败的生成
    例如,DELETE_ON_错误不适用于目录,因此这是在
    mktemp-d
    之后进行清理的关键


    替换为有效的CMD。

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

    run:
        bash -c "trap 'docker-compose down' EXIT; docker-compose up --build"
    
    (这个例子有一个原因:
    docker compose up
    确实说

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


    但是它不会
    rm
    停止的容器,如
    docker run--rm
    ,因此您仍然可以使用
    docker ps-a
    )查看它们,以了解有趣的问题,尽管您所做的听起来是个坏主意。我可以这样做,但如果可能,请尽量避免,它是独立的,我正试图保持这种方式。你有没有一些例子说明
    .DELETE\u ON\u ERROR
    不起作用?这是make实现中的错误吗?@HakanBaba添加了详细信息。除了echo中的嵌套引号(当然是非法的)之外,这似乎不起作用,至少对于我想要实现的目标来说是这样的。一个人应该如何使用它?假设我的makefile只有一个具有睡眠和触摸的目标,如@andrewdotn示例(忽略.DELETE_ON_错误),您将如何修改它以使用此解决方法?请参阅编辑。echo“在这里做事”将是睡眠/触摸。在这里执行清理类似于,您按下ctrl-cI时仍然看到目标“运行”的方法失败。。。make:**[run]Interrupt
    当我尝试此操作时,make目标不会运行
    docker compose down
    命令。(我有这个答案中描述的确切的用例。)这确实适用于我这个确切的用例,即确保向上运行后向下运行。