Reputation: 2254
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.
Upvotes: 5
Views: 5866
Reputation: 9466
Combining @Gavin Smith and @MadScientist answers with these other questions:
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:
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
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
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
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
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:
This is the same as the above, but now you have everything in a single 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
Upvotes: 1
Reputation: 124704
You could create a wrapper script that simply passes all arguments to make
and then runs the custom action you want:
#!/bin/sh
make "$@" && ./custom_script.sh
Upvotes: 2
Reputation: 100926
As janos says, there is no facility built into make to do it. You can use a wrapper such as he suggests. You an also, if you're willing to live with some amount of "bleah", push that into your makefile using recursion. It would look something like this, perhaps:
ifdef RECURSING
... normal makefile goes here ...
else
.DEFAULT all:
@$(MAKE) RECURSING=true $@ ; r=$$? ; \
<extra shell command here>; \
exit $$r
endif
Upvotes: 4
Reputation: 3154
You could use two makefiles, one of which calls the other. For example
wrapper.mk:
foo bar:
make -f other.mk $@
@echo finished
.PHONY: foo bar
other.mk:
foo bar:
@echo Building $@
Then running "make -f wrapper.mk foo", wrapper.mk runs other.mk to build foo. The .PHONY target means that the targets will be passed to other.mk for consideration everytime regardless of whether the files exist or not.
This requires listing all your targets in wrapper.mk - there may be ways round this using default rules or match-anything rules.
Upvotes: 3