为什么GNU make会忽略SIGINT,但是不执行以下命令?

时间:2019-04-22 16:58:35

标签: makefile

即使要用SIGINT停止第91行(gdb)上的命令(通过Ctrl + C),我也要使第92行(killall)上的命令执行:

 88 debug:                                                                                                                                                                                     
 89     make all                                                                                                                                                                               
 90     make flash                                                                                                                                                                             
 91     -$(GDB) $(PROJ_NAME).elf $(GDBCOMMANDS)                                                                                                                                                
 92     killall openocd

但是,即使make打印有关忽略该中断的信息,但此后它仍然不会运行killall:

make: [Makefile:91: debug] Interrupt (ignored)

在不使用SIGINT的情况下退出GDB时,所有工作都按预期进行-执行killall。

在上述情况下,为什么make不尝试执行killall? 我该如何运作?

您可以使用此Makefile自己测试问题(如果退出前在手动窗口中按CTRL + C,则不会执行回显,但如果工作正常,只需按“ q”退出即可):

all:
    -man man                                                                                                                                                                                   
    echo 'It worked!'

2 个答案:

答案 0 :(得分:0)

问题在于,^ C也被make捕获(当您运行^ C时,终端进程组中的所有进程都接收到该信号),make退出(清理后),因此它从不尝试运行任何更多命令,就像在制作过程中输入^ C一样。

避免这种情况的唯一方法是确保make完全不接收SIGINT,并且这样做的唯一方法是更改​​流程组。我不确定是否有任何方便的实用程序可以帮您实现这一目标。

我的建议是不要尝试从制造配方内部调用调试器或其他交互式程序。它不是为此设计的。除了上述问题之外,您还会发现,如果尝试在启用并行构建的情况下运行,则由于只有一个进程可以从终端获取标准输入,因此将随机选择一个进程来获取“真实”标准输入,而其他将关闭其stdin或从/ dev / null或其他内容读取。

相反,为什么不创建一个Shell脚本来进行调试,该脚本将运行您想要的make命令,然后调用gdb。此shell脚本可以使用trap来捕获SIGINT并忽略它,以确保它始终运行清除。

答案 1 :(得分:0)

可接受的答案很好地说明了make的问题,但是要使解决方案仅在make中起作用,可以使用.ONESHELL来完成trap

  1. 在测试您的示例时,我发现man似乎独自忽略了SIGINT,因此,这并不是最好的测试案例
  2. Avoid using recursion,当您可以轻松使用先决条件debug: all flash(但请记住有关并行性的警告)
  3. 如果您确实使用.ONESHELL,明智的做法是也选择.SHELLFLAGS,否则您的食谱将不会像以前那样使用。
  4. 我注意到您正在杀死所有openocd实例,您可能想考虑一种更受控制的方法,即:按照建议编写一个单独的脚本。

编辑:正如评论中指出的那样,不要期望在此之后会建立其他目标。

.ONESHELL:
# The flag -e mimics the traditional behaviour of exiting as soon as any command fails
.SHELLFLAGS := -e -c 

debug: all flash      
     trap 'true' INT                                                                                                                                                                                                                                                                                                                                                        
     $(GDB) $(PROJ_NAME).elf $(GDBCOMMANDS) || error=$$?                                                                                                                                               
     killall openocd  # All of them?
     exit $${error}