1

I encountered this kind of construction in a makefile:

clean:
    @echo "Cleaning"
ifeq "DEV" "$(VERSION)"
    $(MAKE) clean -C bin/
else
    @echo "Unsupported"
    @false
endif

What is @false doing?

p.s.

Googling brought me e.g. here - they use it but they don't explain it.

hans
  • 1,043
  • 12
  • 33
  • BTW, you could have followed your link further to http://netbsd.gw.com/cgi-bin/man-cgi?false+.i386, which may have given an hint. – kabanus Apr 10 '18 at 14:36

2 Answers2

5

I'm going to expand on @kabanus's answer a touch here (and this was too long for a comment...)

First of all the @ symbol simply tells make to not echo the command to stdout. So the recipe false and @false will do the same thing, except only the first will echo the command being run.

Next, when make builds a target, it will run each recipe line by line. If a recipe line returns non-zero (false), it will stop building the target (it will not execute any recipes beyond that one). As well, it will consider the target to have failed building, and anything dependent on it will also fail, and thus make in general will fail, returning a non-zero status.

So if you did make bar with the makefile:

foo:
    @echo this will be printed '(foo)'
    @false
    @echo this will not be printed '(foo)'

bar: foo
    @echo this will not be printed '(bar)'

The second echo in foo will not appear, as make will fail in the recipe above it and abort building foo. bar will also not be built because its dependency was not built, so you will not see the echo from bar.

Notice that if you do have a recipe line that you know may fail, but you want to ignore, you can get around this behavior by adding a - in front of it as so:

foo:
    @echo this will be printed '(foo)'
    -@false
    @echo this will also be printed '(foo)'

Which will do both echos. It will run false, which does nothing, but then ignore it's return value due to the - sign. See this SO question for details

Lastly, the return value for the make command will also effect && and || operators as well as if statements. Often in scripts you will see something like:

 make foo && cp foo /tftpboot/foo && echo success

If make returns false, it will not try the cp or the echo. It is always good practice to have make return non-zero on failure, as people expect this behavior.

Neuron
  • 5,141
  • 5
  • 38
  • 59
HardcoreHenry
  • 5,909
  • 2
  • 19
  • 44
  • Thank you for a very complete answer. It also explains that a recipe `mv ...` after `@false` make no point in this [example](https://www.netbsd.org/docs/pkgsrc/makefile.html) – hans Apr 11 '18 at 09:23
3

When you run that part of the Makefile (i.e. make clean) by default the status code will be 0 (success) since echo won't fail. The @false invokes the shell built-in (now days) false which does nothing but fails, so the last command fails (usually sets the status code to 1).

Thus if you check the status code ($?) after running make with an unsupported mode you can see a failure. This is a good coding practice I would say. @true is the same, but returns 0 - it's unneeded since success of the other commands will return 0 anyway.

An example use case in bash:

make clean VERSION=somethingThatIsntSupported
if [ $? -gt 0 ]; then echo "Oh no! Make failed, are you sure that version is OK?"; fi

Of course this is redundant here, but the contents of the if could be complex as you like.

kabanus
  • 24,623
  • 6
  • 41
  • 74
  • Ok, so it makes sens as the last command in the clause. What is the usecase [here](https://www.netbsd.org/docs/pkgsrc/makefile.html)? – hans Apr 10 '18 at 14:37
  • @hans As stated - so a code running make in some script can check `$?` and see if it failed - and do something if needed. – kabanus Apr 10 '18 at 14:37