Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a failing $(shell) command interrupt Make

Tags:

I have a Makefile that starts by running a tool before applying the build rules (which this tool writes for me). If this tool, which is a python script, exits with a non-null status code, I want GNU Make to stop right there and not go on with building the program.

Currently, I do something like this (top level, i.e. column 1):

$(info Generating build rules...) $(shell python collect_sources.py) include BuildRules.mk 

But this does not stop make if collect_sources.py exits with a status code of 1. This also captures the standard output of collect_sources.py but does not print it out, so I have the feeling I'm looking in the wrong direction.

If at all possible, the solution should even work when a simple MS-DOS shell is the standard system shell.

Any suggestion?

like image 770
Carl Seleborg Avatar asked Oct 22 '08 12:10

Carl Seleborg


People also ask

How do you fail a shell script?

One approach would be to add set -e to the beginning of your script. That means (from help set ): -e Exit immediately if a command exits with a non-zero status. So if any of your commands fail, the script will exit.

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?

?= indicates to set the KDIR variable only if it's not set/doesn't have a value. For example: KDIR ?= "foo" KDIR ?= "bar" test: echo $(KDIR)

What is shell in Makefile?

$(shell) is a special function in gmake that runs an external command and captures the output for use in the makefile. For example, you could get the current working directory like this: CWD=$(shell pwd) all: @echo This makefile lives in $(CWD).


2 Answers

There might be a better way, but I tried the following and it works:

$(if $(shell if your_command; then echo ok; fi), , $(error your_command failed)) 

Here I did assume that your_command does not give any output, but it shouldn't be hard to work around such a situation.

Edit: To make it work with the default Windows shell (and probably any decent shell) you could write your_command && echo ok instead of the if within the shell function. I do not think this is possible for (older) DOS shells. For these you probably want to adapt your_command or write a wrapper script to print something on error (or success).

like image 149
mweerden Avatar answered Oct 12 '22 19:10

mweerden


Ok, here's my own solution, which is unfortunately not based on the status code of the collect_sources.py script, but which Works For Me (TM) and lets me see any output that the script produces:

SHELL_OUTPUT := $(shell python collect_sources.py 2>&1) ifeq ($(filter error: [Errno %],$(SHELL_OUTPUT)),)   $(info $(SHELL_OUTPUT)) else   $(error $(SHELL_OUTPUT)) endif 

The script is written so that any error produces an output beginning with "collect_sources: error:". Additionally, if python cannot find or execute the given script, it outputs an error message containing the message "[Errno 2]" or similar. So this little piece of code just captures the output (redirecting stderr to stdout) and searches for error messages. If none is found, it simply uses $(info) to print the output, otherwise it uses $(error), which effectively makes Make stop.

Note that the indentation in the ifeq ... endif is done with spaces. If tabs are used, Make thinks you're trying to invoke a command and complains about it.

like image 31
Carl Seleborg Avatar answered Oct 12 '22 20:10

Carl Seleborg