How to get exit status of a shell command used in GNU Makefile?

57,521

Solution 1

In the makefile-:

mycommand || (echo "mycommand failed $$?"; exit 1)

Each line in the makefile action invokes a new shell - the error must be checked in the action line where the command failed.

If mycommand fails the logic branches to the echo statement then exits.

Solution 2

Here are a couple of other approaches:


shell & .SHELLSTATUS

some_recipe:
    @echo $(shell echo 'doing stuff'; exit 123)
    @echo 'command exited with $(.SHELLSTATUS)'
    @exit $(.SHELLSTATUS)

Output:

$ make some_recipe

doing stuff
command exited with 123      
make: *** [Makefile:4: some_recipe] Error 123

It does have the caveat that the shell command output isn't streamed, so you just end up with a dump to stdout when it finishes.


$?

some_recipe:
    @echo 'doing stuff'; sh -c 'exit 123';\
    EXIT_CODE=$$?;\
    echo "command exited with $$EXIT_CODE";\
    exit $$EXIT_CODE

Or, a bit easier to read:

.ONESHELL:

some_recipe:
    @echo 'doing stuff'; sh -c 'exit 123'
    @EXIT_CODE=$$?
    @echo "command exited with $$EXIT_CODE"
    @exit $$EXIT_CODE

Output:

$ make some_recipe

doing stuff                  
command exited with 123      
make: *** [Makefile:2: some_recipe] Error 123

It's essentially one string of commands, executed in the same shell.

Solution 3

If all you want is for the make to be aborted iff the tool exits with a nonzero status, make will already do that by default.

Example Makefile:

a: b
    @echo making $@
b:
    @echo making $@
    @false
    @echo already failed

. This is what happens with my make:

$ make
making b
make: *** [Makefile:6: b] Error 1

Make sure partially or wholly created targets are removed in case you fail. For instance, this

a: b
    @gena $+ > $@
b:
    @genb > $@

is incorrect: if on the first try, genb fails, it will probably leave an incorrect b, which, on the second try, make will assume is correct. So you need to do something like

a: b
    @gena $+ > $@ || { rm $@; exit 1; }
b:
    @genb > $@
Share:
57,521
Lunar Mushrooms
Author by

Lunar Mushrooms

Updated on November 25, 2021

Comments

  • Lunar Mushrooms
    Lunar Mushrooms over 2 years

    I have a makefile rule in while I am executing a linux tool. I need to check the exit status of the tool command, and if that command fails the make has to be aborted.

    I tried checking with $?, $$? \$? etc in the makefile. But they gives me syntax error when makefile runs.

    What is the right way to do this ?

    Here is the relevant rule in Makefile

        mycommand \
        if [ $$? -ne 0 ]; \
        then \
            echo "mycommand failed"; \
            false; \
        fi
    
  • szmoore
    szmoore over 5 years
    The $(shell ...) in the first recipe might be confusing but it does only evaluate if that recipe is executed (I originally thought otherwise, whoops)
  • imz -- Ivan Zakharyaschev
    imz -- Ivan Zakharyaschev over 5 years
    .SHELLSTATUS must have appeared recently, probably, in GNU Make >= 4.
  • davidrmcharles
    davidrmcharles almost 2 years
    In my case echo prints the message, but exit 1 does not abort my Makefile execution. :(
  • davidrmcharles
    davidrmcharles almost 2 years
    Replacing exit 1 with sh -c 'exit 1' solved my problem.
  • tripleee
    tripleee almost 2 years
    Probably refactor to avoid this, though. See also Why is testing “$?” to see if a command succeeded or not, an anti-pattern?