0

I've got a makefile that has a 'contingency step' to bootstrap the environment if the task is run without prior, critical setup:

bootstrap: ensure_opam_switch_once build


.ONESHELL:
$(FRONTEND_OPAM_SWITCH):
    @echo ''
    @echo "$(bold)[make bootstrap]$(sgr0) An opam-switch doesn't exist for frontend/, creating one ..."
    OPAMYES=true $(MAKE) init
    opam exec --sw="${FRONTEND_DIR}" -- $(MAKE) bootstrap
    @EXIT_CODE=$$?
    @exit $$EXIT_CODE

ensure_opam_switch_once: | $(FRONTEND_OPAM_SWITCH)

init:
    # this does critical first-time setup

build:
    # ... everything else happens here

The issue is that several shell-variables need to be set for the rest of the makefile — and I'm not guaranteed to know those variables. (opam sets up some stuff with eval; think rbenv, nvm, pyenv, etc.)

My plan/hack here is to re-execute the make-task after setup, with those shell-variables configured in the environment make is invoked from. (In the above example, that's the opam exec line.)

However, my issue at the moment is that, if the sub-make exits with success, then my @exit $$EXIT_CODE doesn't result in Make exiting! It continues to run and attempt to execute other dependents, which obviously fails because the outer Make invocation doesn't have any of the necessary shell-environment.

Is there a way to stop Make with a successful exit-code?

ELLIOTTCABLE
  • 17,185
  • 12
  • 62
  • 78
  • 1
    I don't know of a (non-kludge) way to abort Make and return a non-error value, but this looks a little like the XY problem. Can you explain a little more clearly which things you want Make to do, in what order and under what circumstances? – Beta Jun 20 '22 at 17:46
  • The short answer is no, there is no way to stop make early with a successful error code. Once it's started it will build all the targets in the part of the graph it starts with, or it will exit early with a failure. You'll have to play a trick using recursive makefiles, such as @Beta or Renault suggest. – MadScientist Jun 21 '22 at 14:01

2 Answers2

0

You could use conditionals to hide or not parts of your Makefile. Example with a PASS make variable that defines what part of the Makefile shall be used:

$ cat Makefile
.PHONY: all

all:
ifeq ($(PASS),)
    @echo 'PASS = $(PASS), VAR = $(VAR)'
    export VAR=VAL; $(MAKE) PASS=1
else
    @echo 'PASS = $(PASS), VAR = $(VAR)'
endif

$ make
PASS = , VAR = 
export VAR=VAL; make PASS=1
make[1]: Entering directory 'foo'
PASS = 1, VAR = VAL
make[1]: Leaving directory 'foo'
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
0

Fwiw, the following stops make, but with exit code 1 "failure", not success as you want:

... $(MAKE) exit-make

exit-make:
    $(error exit-make)
.PHONY: exit-make

#   example --
bigtmp=`find ~ -name 'tmp*.n*'`; \
if [[ $$bigtmp ]]; then echo $$bigtmp; $(MAKE) exit-make; fi

...mk:29: *** exit-make.  Stop.
denis
  • 21,378
  • 10
  • 65
  • 88