Force Makefile to execute script after building any target (just before exiting)

Viewed 4046

I'd like to execute a shell command when make exits, regardless of whatever target it built. Seems like make doesn't have a way to do this directly. However, here's an example of having make execute a shell command upon startup, regardless of the target:

Force Makefile to execute script before building targets

Is there any similar hack have make execute a shell command once just before exiting? I could put the command at the bottom of every target, but a) it would get executed multiple times, and b) that is ugly and difficult to manage.

4 Answers

Combining @Gavin Smith and @MadScientist answers with these other questions:

  1. How to pass argument to Makefile from command line?
  2. Makefile match any target / task
  3. How to get the invoking target of makefile?
  4. Suppress "nothing to be done for 'all' "
  5. Makefile: declare all targets PHONY
  6. Makefile set global variable in target body

I built this:

Makefile

ECHOCMD:=/bin/echo -e
SHELL := /bin/bash

define DEFAULTTARGET :=
    printf 'Calling makerules.mk "%s"\n\n' "${MAKECMDGOALS}"
    make -f makerules.mk ${MAKECMDGOALS}

    printf '\n'
    printf 'Running something after all rules finished\n'
endef

%:
    @:
#   printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"

    $(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
    $(eval IS_MAKEFILE_RUNNING_TARGETS=1)

all:
    @:
#   printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"

    $(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
    $(eval IS_MAKEFILE_RUNNING_TARGETS=1)

makerules.mk

all:
    printf 'Calling my all rule\n'

foo:
    printf 'Calling my foo rule\n'

bar:
    printf 'Calling my bar rule\n'

xyzzy:
    printf 'Calling my xyzzy rule\n'

Usage examples:

  1. make

    printf 'Calling makerules.mk "%s"\n\n' ""
    Calling makerules.mk ""
    
    make -f makerules.mk
    make[1]: Entering directory '/cygdrive/d/User/Downloads'
    printf 'Calling my all rule\n'
    Calling my all rule
    make[1]: Leaving directory '/cygdrive/d/User/Downloads'
    printf '\n'
    
    printf 'Running something after all rules finished\n'
    Running something after all rules finished
    
  2. make all

    printf 'Calling makerules.mk "%s"\n\n' "all"
    Calling makerules.mk "all"
    
    make -f makerules.mk all
    make[1]: Entering directory '/cygdrive/d/User/Downloads'
    printf 'Calling my all rule\n'
    Calling my all rule
    make[1]: Leaving directory '/cygdrive/d/User/Downloads'
    printf '\n'
    
    printf 'Running something after all rules finished\n'
    Running something after all rules finished
    
  3. make all foo

    printf 'Calling makerules.mk "%s"\n\n' "all foo"
    Calling makerules.mk "all foo"
    
    make -f makerules.mk all foo
    make[1]: Entering directory '/cygdrive/d/User/Downloads'
    printf 'Calling my all rule\n'
    Calling my all rule
    printf 'Calling my foo rule\n'
    Calling my foo rule
    make[1]: Leaving directory '/cygdrive/d/User/Downloads'
    printf '\n'
    
    printf 'Running something after all rules finished\n'
    Running something after all rules finished
    
  4. make all foo bar

    printf 'Calling makerules.mk "%s"\n\n' "all foo bar"
    Calling makerules.mk "all foo bar"
    
    make -f makerules.mk all foo bar
    make[1]: Entering directory '/cygdrive/d/User/Downloads'
    printf 'Calling my all rule\n'
    Calling my all rule
    printf 'Calling my foo rule\n'
    Calling my foo rule
    printf 'Calling my bar rule\n'
    Calling my bar rule
    make[1]: Leaving directory '/cygdrive/d/User/Downloads'
    printf '\n'
    
    printf 'Running something after all rules finished\n'
    Running something after all rules finished
    
  5. make all foo bar xyzzy

    printf 'Calling makerules.mk "%s"\n\n' "all foo bar xyzzy"
    Calling makerules.mk "all foo bar xyzzy"
    
    make -f makerules.mk all foo bar xyzzy
    make[1]: Entering directory '/cygdrive/d/User/Downloads'
    printf 'Calling my all rule\n'
    Calling my all rule
    printf 'Calling my foo rule\n'
    Calling my foo rule
    printf 'Calling my bar rule\n'
    Calling my bar rule
    printf 'Calling my xyzzy rule\n'
    Calling my xyzzy rule
    make[1]: Leaving directory '/cygdrive/d/User/Downloads'
    printf '\n'
    
    printf 'Running something after all rules finished\n'
    Running something after all rules finished
    

Related questions:

  1. Stop executing makefile
  2. Force exit from a Makefile target without raising an error
  3. Suppress make rule error output
  4. Make: how to continue after a command fails?
  5. https://unix.stackexchange.com/questions/460606/make-how-to-suppress-make-error-messages-without-suppressing-other-output
  6. makefile use variable defined in target
  7. How do I get a makefile function to stop the current target?
  8. Can I make a makefile abort outside of a rule?
  9. Remove target from MAKECMDGOALS?
  10. How to detect if the makefile **`--silent`** / **`--quiet`** command line option was set?

Update

This is the same as the above, but now you have everything in a single Makefile:

  1. Getting the name of the makefile from the makefile

Makefile

ECHOCMD:=/bin/echo -e
SHELL := /bin/bash


ifeq (${IS_MAKEFILE_RUNNING_TARGETS},)

MAKEFILE_JUSTNAME := $(firstword ${MAKEFILE_LIST})

define DEFAULTTARGET :=
    printf 'Calling "%s" "%s"\n\n' "${MAKEFILE_JUSTNAME}" "${MAKECMDGOALS}"
    make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}

    printf '\n'
    printf 'Running something after all rules finished\n'
endef

%:
    @:
#   printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"

    $(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
    $(eval export IS_MAKEFILE_RUNNING_TARGETS=1)

all:
    @:
#   printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"

    $(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
    $(eval export IS_MAKEFILE_RUNNING_TARGETS=1)


else

all:
    printf 'Calling my all rule\n'

foo:
    printf 'Calling my foo rule\n'

bar:
    printf 'Calling my bar rule\n'

xyzzy:
    printf 'Calling my xyzzy rule\n'


endif
Related