5

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.

  • 1
    what's the exit code of diff when you run it manually? – umläute Nov 11 '13 at 17:03
  • @umlaute it's 1 – Marcus Junius Brutus Nov 11 '13 at 17:13
  • @umlaute ok so replacing 'diff' with '-diff' fixes it - it was a Makefile thing – Marcus Junius Brutus Nov 11 '13 at 17:16
  • I'm at a loss on why you want to make and then immediately apply the patch... e.g., why not just use cp? Since that doesn't really make much sense, I assume this is a simplified test case. – derobert Nov 11 '13 at 18:27
  • @derobert your assumption is correct. I note as much at the beginning of my post ("Narrow-down ..") – Marcus Junius Brutus Nov 11 '13 at 19:10
11

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.

  • @Bananguin Thanks for the edit, that probably is true. I'm not entirely sure what OP is trying accomplish... – derobert Nov 11 '13 at 18:26
  • actually i just felt bad because your version was not wrong, just one corner too much for me to handle before dinner. still, it's more spelled out now :D – Bananguin Nov 11 '13 at 18:29
  • The Unix convention for return codes is a bit broader than “0 for success, >0 for failure”. For commands that return a boolean result, the convention is “0 for yes, 1 for no, >1 for failure”. diff is an example of this, as are grep, test, … – Gilles Nov 12 '13 at 0:09
  • @Gilles Well, diff would ask "are these files different?"... Arguably, diff is backwards. But I guess both it and cmp both return 0 for match, 1 for differ. – derobert Nov 12 '13 at 0:31
  • @derobert diff and cmp ask “are these files identical?” – Gilles Nov 12 '13 at 0:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.