我想知道是否有一种方法在GNU
如果用户按下
make
中实现trap
,类似于内置于BASH
中的功能?如果用户按下
CTRL-C
,或者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"
这会捕获中断、终止和任何非零退出代码。
请注意$(MAKE)
,因此cmdline覆盖和make选项将传递给子make。
在trap上:
对于目录,DELETE_ON_ERROR不起作用,因此这对于在mktemp -d
后清理非常重要。
使用有效的CMD替换< DO CLEANUP HERE >
。
@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
命令。(我有与此答案中描述的确切用例相同的情况。) - ely不行。GNU make的信号处理已经有很多问题了。在它的信号处理程序中,它调用像printf
这样的函数,这些函数不能安全地从信号处理程序中调用。我曾经看到过这导致的问题,例如.DELETE_ON_ERROR
规则如果将stderr
重定向到stdout
,则不一定总是运行。
例如,在CentOS 7.4上:
Create the following Makefile
:
.DELETE_ON_ERROR:
foo:
touch $@
sleep 10
Open it in vim
and run :make
,
Vim/make prints
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实现中的错误吗? - Hakan BabaMake 不支持,但是可以使用 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 命令会返回一个状态码。就我目前所知,它返回 0 表示成功,返回 2 表示失败(请查看文档)。因此,您是否可以将 make 命令放入一个 Shell 脚本中以解决问题?