Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

stop on error when target of makefile rule is a foreach function

I have a makefile that defines several rules where the target is a foreach function.

$(foreach var,$(list), $($(var)_stuff) $($(var)_more_stuff)):
    @echo Building $@ from $^...
    $(CC) $(FLAGS) ...

Is there any way to get make to quit when encountering an error without going through the entire list.

like image 662
8bitwide Avatar asked Jun 29 '12 00:06

8bitwide


2 Answers

One workaround is to "manually" invoke exit on failure.

For example, assume we have a directory called scripts with a number of shell scripts (with filenames that end with .sh) that we want to execute.

Then a variable declaration like this:

LIST_OF_SCRIPTS ?= $(wildcard scripts/*.sh)

will give us a list of those scripts, and a target like this:

run-all-scripts
  @$(foreach scriptfile,$(LIST_OF_SCRIPTS),$(scriptfile);)

will run all of those scripts, but as you note, the foreach loop will keep going whether or not one of the scripts returns an error code. Adding a || exit to the command will force the subcommand to exit on error, which Make will then treat as a failure.

E.g.,

run-all-scripts
  @$(foreach scriptfile,$(LIST_OF_SCRIPTS),$(scriptfile) || exit;)

will do what you want (I believe).

Specifically, using your pseudo-code example, I think you want something like this:

$(foreach var,$(list), $($(var)_stuff) $($(var)_more_stuff)):
    @echo Building $@ from $^...
    ($(CC) $(FLAGS) ...) || exit

(where all I've changed is wrapping the (CC) $(FLAGS) ... bit in parens and appending || exit to make it fail on error).

like image 113
Rod Avatar answered Sep 27 '22 20:09

Rod


The foreach is completely evaluated and substituted before any of the rules are executed. So the behaviour of this should be identical to as if you had hardcoded the rule without using the foreach. In other words, it's not directly relevant to the problem.

There are only a few possible explanations for what you're seeing, mostly described in the manual here:

  • You are running Make with -k or --keep-going
  • You are running Make with -i or --ignore-errors
  • Your targets is defined as prerequisites of the special .IGNORE target
  • Your recipe starts with a -
  • Your recipe isn't actually returning a non-zero exit status
like image 29
Oliver Charlesworth Avatar answered Sep 27 '22 20:09

Oliver Charlesworth