bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: "make -jN" requires mechanical changes to a Makefile


From: Edward Welbourne
Subject: Re: "make -jN" requires mechanical changes to a Makefile
Date: Mon, 13 May 2019 13:36:08 +0000

> Howard Chu wrote:
> > >> Example with one rule creating 4 files:
> > >>
> > >> all : copy1
> > >>
> > >> copy1: Makefile
> > >>         install -c -m 644 Makefile copy1
> > >>         install -c -m 644 Makefile copy2
> > >>         install -c -m 644 Makefile copy3
> > >>         install -c -m 644 Makefile copy4

For this (toy example) case,

# We want to create all 4 copies
all: copy1 copy2 copy3 copy4
# Each of the copies depends on the Makefile:
copy1 copy2 copy3 copy4: Makefile
        install -c -m 644 $< $@

should do the trick.  The rule means: "To update any one of the files
copy1...copy4 (it'll be called $@), you need the Makefile (it'll be
called $<); once $< is up to date, if it's newer than $@, copy it to the
target you're after."  Note that asking for any one of the files means
asking for the rule to be run, no matter how many of them it makes.

However, that's no use to you for the case of bison generating two
files.  Your actual command doesn't just make one file; it makes two
files.  So the target whose command it is needs to be a (single) "both
files" target, not the two files.  Writing

this that .PHONY: both
both: source
        COMMAND

says: if either this or that is older than source, run COMMAND (once).
Whereas

this that: source
        COMMAND

says: for each of this and that (call it $@), if $@ is older than
source, run COMMAND.  If both are older than source, this claims we need
to run COMMAND twice: indeed, serial make could check both this and
that, to see if either is older than source, before running COMMAND for
either of them.  For each that is older than source, make would then
perfectly reasonably queue a copy of COMMAND, with the stale file's name
substituted for $@ anywhere it appears in COMMAND, for subsequent
execution.  It would thus run COMMAND twice, once for each of the files;
and, indeed, this would be correct behaviour if COMMAND only updated $@
(which is what make expects from its rules).

As it happens, serial make leaves the staleness check until just before
it runs the command, so it manages to optimise away the second run, if
COMMAND actually does update both (hence also the one that wasn't $@ on
the first run).  That's more or less an accident, though; and it doesn't
happen for parallel make, which duly does run COMMAND twice, in
parallel; and the two instances try to update the same files, which can
cause problems.  The error isn't in make; it is in the make file, which
misdescribed the recipe as a way to make *each* file, when it's actually
a way to make *both*.

Which is why you need that .PHONY intermediate.
It's what says "this command updates *both* files".

As Paul said, writing code to guess "what the author meant" and
implement that is usually perilous.  There are way too many ways for the
guessing code to get it wrong, at least until your guessing is being
done by a true AI that knows to recognise when it doesn't know what the
author meant, so stops the build to ask what was meant.

So, rather than asking for make to "do what I mean, not what I said",
please take the time to tell make what you really meant.  Describe,
faithfully and fully, how the commands relate to the files, then make
can do its dumb but robust thing reliably.  Making things cleverer
usually leads to them breaking; making them tediously straightforward is
good for reliability,

        Eddy.
-- 
A shortcut is the longest distance between two points.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]