Why does diff fail when invoked from a Makefile

diff()makepatch

Narrow-down of a patch problem I am trying to troubleshoot:
Only two files, each with a size of 1 byte:

  • file a (containing 'a')
  • file b (containing 'b') and

Goal is to make and then apply a patch that will change the value of 'b' to 'a'. Contents of Makefile are:

patch:
        diff -u b a > b2a.patch
        patch -o b.corrected b < b2a.patch
        diff a b.corrected

clean:
        rm -f b2a.patch b.corrected

Given the above, make fails with the following output:

$ make
diff -u b a > b2a.patch
make: *** [patch] Error 1

If, however, I execute the commands in the Makefile one after the other on the bash shell, there is no problem at all.

Best Answer

Make assumes that an exit code of 0 means success, anything else means failure. This is the standard convention used by almost all command-line tools.

Unfortunately, diff is not one of those. Checking the GNU diff info page, and also the Single Unix Specification "diff" entry, 0 means no differences found, 1 means differences found, and ≥2 means error.

You can tell Make to ignore the exit status entirely by prefixing the command with a hyphen, as you did in your comment, but this will ignore actual errors—probably not what you want. Instead, you can:

patch:
        diff -u b a > b2a.patch; [ $$? -eq 1 ]
        patch -o b.corrected b < b2a.patch
        diff a b.corrected; [ $$? -eq 1 ]

Note the ; [ $$? -eq 1 ] bit I've added to the end of the two diff lines. You can use ; test $$? -eq 1 as well, of course. The $? shell variable is $$? due to normal Makefile escaping conventions. Note this also rejects exit status 0 (no differences), which is probably what you want.

BTW: it appears this really ought to be:

patch: b.corrected
        diff …
b.corrected: b2a.patch
        patch …
b2a.patch: a b
        diff …

so that modifications of a and b get picked up, and the files regenerated correctly.

Related Question