Question

Say I have the following files:

buggy_program:

#!/bin/sh
echo "wops, some bug made me exit with failure"
exit 1

Makefile:

file.gz:
    buggy_program | gzip -9 -c >$@

Now if I type make, GNU make will happily build file.gz even though buggy_program exited with non-zero status.

In bash I could do set -o pipefail to make a pipeline exit with failure if at least one program in the pipeline exits with failure. Is there a similar method in GNU make? Or some workaround that doesn't involve temporary files? (The reason for gzipping here is precisely to avoid a huge temporary file.)

Was it helpful?

Solution 3

Here's a possible solution that doesn't require bash. Imagine you have two programs thisworks and thisfails that fail or work fine, respectively. Then the following will only leave you with work.gz, deleting fail.gz, ie. create the gzipped make target if and only if the program executed correctly:

all: fail.gz work.gz

work.gz:
    ( thisworks && touch $@.ok ) | gzip -c -9 >$@
    rm $@.ok || rm $@

fail.gz:
    ( thisfails && touch $@.ok ) | gzip -c -9 >$@
    rm $@.ok || rm $@

Explanation:

In the first line of the work.gz rule, thisworks will exit with success, and a file work.gz.ok will be created, and all stdout goes through gzip into work.gz. Then in the second line, because work.gz.ok exists, the first rm command also exits with success – and since || is short-circuiting, the second rm does not get run and so work.gz is not deleted.

OTOH, in the first line of the fail.gz rule, thisfails will exit with failure, and fail.gz.ok will not be created. All stdout still goes through gzip into fail.gz. Then in the second line, because fail.gz.ok does not exist, the first rm command exits with failure, so || tries the second rm command which deletes the fail.gz file.


To easily check that this works as it should, simply replace thisworks and thisfails with the commands true and false, respectively, put it in a Makefile and type make.

(Thanks to the kind people in #autotools for helping me with this.)

OTHER TIPS

Try this

SHELL=/bin/bash -o pipefail

file.gz:
    buggy_program | gzip -9 -c >$@

You could do:

SHELL=/bin/bash

.DELETE_ON_ERROR:
file.gz:
    set -o pipefail; buggy_program | gzip -9 -c >$@

but this only work with bash.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top