Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I trap errors and interrupts in GNU make?

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.

like image 927
Cyrus Avatar asked Jun 10 '09 07:06

Cyrus


People also ask

How do I ignore an ERROR in makefile?

To ignore errors in a recipe line, write a ' - ' at the beginning of the line's text (after the initial tab). The ' - ' is discarded before the line is passed to the shell for execution.

What does $< mean in makefile?

The variable $@ represents the name of the target and $< represents the first prerequisite required to create the output file.

What is Gmake in Linux?

GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files. Make gets its knowledge of how to build your program from a file called the makefile, which lists each of the non-source files and how to compute it from other files.

How do you exit a makefile?

1 Answer. You can execute a command in the shell from the Makefile by using the $(shell command) syntax. If for instance you would want to exit status of the ls command in bash you would type: ls --qwfpgjl > /dev/null 2>&1 ; echo $?


3 Answers

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:

  • clear trap handler (with -)
  • do the cleanup
  • exit with non-zero exit status, so build automation tools report the failed build.

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.

like image 157
Kevin Avatar answered Oct 16 '22 14:10

Kevin


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.)

like image 45
Jesse Glick Avatar answered Oct 16 '22 15:10

Jesse Glick


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:

  1. Create the following Makefile:

    .DELETE_ON_ERROR:
    
    foo:
            touch $@
            sleep 10
    
  2. Open it in vim and run :make,

  3. While it is sleeping, hit Ctrl-C

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.

like image 41
andrewdotn Avatar answered Oct 16 '22 15:10

andrewdotn