56

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
Paweł Prażak
  • 3,091
  • 1
  • 27
  • 42
Lunar Mushrooms
  • 8,358
  • 18
  • 66
  • 88
  • Have you tried `echo $?`? This can help --> http://www.cyberciti.biz/faq/shell-how-to-determine-the-exit-status-of-linux-and-unix-command/ – fedorqui May 01 '13 at 08:37
  • Eh? Make automatically checks the exit status of the tool, and aborts on error. A simple `mycommand` suffices, no? – bobbogo May 01 '13 at 09:10
  • 4
    The syntax error comes from make removing the line breaks before passing the text block to the shell. Simply add `;`s to the end of each line (apart from the `then` and `fi`) and your snippet will lose its syntax errors. – bobbogo May 01 '13 at 09:11
  • @bobbogo, thanks it worked. The syntax error was due to missing ; – Lunar Mushrooms May 01 '13 at 10:27

4 Answers4

83

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.

suspectus
  • 16,548
  • 8
  • 49
  • 57
31

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.

Community
  • 1
  • 1
c24w
  • 7,421
  • 7
  • 39
  • 47
4

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 > $@
reinierpost
  • 8,425
  • 1
  • 38
  • 70
1

To those who can't still fix it, the original snippet in the question missed a semicolon after mycommand. So, the working example is:

    mycommand; \  # <<== here's the missing semicolon
    if [ $$? -ne 0 ]; \
    then \
        echo "mycommand failed"; \
        false; \
    fi
Luan Nguyen
  • 993
  • 6
  • 14
  • Probably refactor to avoid this, though. See also [Why is testing “$?” to see if a command succeeded or not, an anti-pattern?](https://stackoverflow.com/questions/36313216/why-is-testing-to-see-if-a-command-succeeded-or-not-an-anti-pattern) – tripleee Jun 27 '22 at 17:04