I'm wondering if there's a way to implement trap
in GNU make
, similar to that built into BASH
?
If the user presses CTRL-C
, or if make
itself fails (non-zero exit), I'd like to call a particular target or macro.
I'm wondering if there's a way to implement trap
in GNU make
, similar to that built into BASH
?
If the user presses CTRL-C
, or if make
itself fails (non-zero exit), I'd like to call a particular target or macro.
At this point in time, GNU make doesn't have native support.
There is a reliable workaround however:
.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"
This catches interruptions, terminations AND any non-zero exit codes.
Note the $(MAKE)
so cmdline overrides and make options get passed to submake.
On trap:
DELETE_ON_ERROR does NOT work for directories, so this is key for cleaning up after mktemp -d
, for example
Replace <DO CLEANUP HERE>
with valid CMD.
A simplified version of @kevinf’s answer which seems good enough for basic cases:
run:
bash -c "trap 'docker-compose down' EXIT; docker-compose up --build"
(This example is for a reason: docker-compose up
does say
When the command exits, all containers are stopped.
but it does not rm
the stopped containers like docker run --rm
would, so you can still see them with docker ps -a
.)
No. GNU make’s signal handling already leaves a lot to be desired. From within its signal handler, it calls functions like printf
that are not safe to be called from within a signal handler. I have seen this cause problems, for example .DELETE_ON_ERROR
rules don’t always run if stderr
is redirected to stdout
.
For example, on a CentOS 7.4 box:
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 was sent an interrupt signal, but foo
still exists.
Make does not support it, but using BASH tricks you can accomplish something similar.
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
The "unmount" will run after the "make" completes. This is usually a satisfactory solution if you are attempting to cleanup operations that may occur during the build but are not cleaned up normally on "make" exit.
make produces return codes. As far as I can remember right now, it returns 0 for success, 2 for failure (please check the documentation). Therefore, would it be enough for you to wrap make inside a shell script for example?