Search code examples
makefileexit-code

Why does GNU make exit with 0 on errors?


Makefile:

foo.o: foo.cpp
    g++ -o foo.o foo.cpp

foo.cpp:

aslkfdj

Output:

$ g++ -o foo.o foo.cpp; echo $?
foo.cpp:1:1: error: ‘aslkfdj’ does not name a type
 aslkfdj
 ^
1

$ make; echo $?
g++ -o foo.o foo.cpp
foo.cpp:1:1: error: ‘aslkfdj’ does not name a type
 aslkfdj
 ^
Makefile:2: recipe for target 'foo.o' failed
make: *** [foo.o] Error 1
0
$ 

I would expect an exit code of 2 from make, since g++ returns non-zero, cf.

$ man make|grep exits -A2
       GNU make exits with a status of zero if all makefiles were successfully parsed and no targets that were built failed.  A sta‐
       tus of one will be returned if the -q flag was used and make determines that a target needs to be rebuilt.  A status  of  two
       will be returned if any errors were encountered.

What am I doing wrong?

For the record, I get the same exit code on Xubuntu 15.10:

$ make --version
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

as on some old OS X server:

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i386-apple-darwin10.0

Solution

  • Make clearly states that it recognizes the error and should therefore return error exit code.

    However there are certain scenarios where this would result in unexpected results anyway. For example if there's alias redefining make or echo it could result in echo $? not reporting the error from make. To check if this is the case one could of course run alias to check, type make to see if any aliases/shell functions might override the name, or simply backslash out alias (ie run \make -f ; \echo $? - the -f without filename will make make fail without any need of a makefile).

    A related scenario is when make is not the actual executable of make. For example you could have a shell script that wraps make, but doesn't forward the exit code. To detect this scenario you could run which make to see which executable is really being run (unless alias is in effect)