Hello Hendrik,

this is not the point. My concern is the different behavior of Pattern Rules with Grouped Targets (implicit.mk) and Explicit Rules with Grouped Targets (explicit.mk).

Am 11.09.26 um 10:52 PM schrieb Henrik Carlqvist:
On Fri, 11 Sep 2026 18:40:33 +0200
joergboe via Bug reports and discussion for GNU  make<[email protected]>
wrote:

* Further requires the translation of foo.s that bar.i is present (import).

More precise:

* Further requires the translation of foo.s that bar.i is present and _current_.

* These files are translated to %.o (object) and %.i (interface) files _at once_.

Ok

foo.o foo.i : bar.i
But the above rule is a bad way to say that foo.o and foo.i only requires
bar.i to be present. The above rule says that foo.o and foo.i should be
rebuilt if bar.i is newer. Instead you might want a order only prerequisite
which means that bar.i first will need to be created, but if it already
exists, it will not cause a rebuild:

foo.o foo.i : | bar.i
Thus bar.i is a regular prerequisite and not a Order Only Prerequisite.
$

Running the script:

$ rm -f foo.* bar.* target
$ touch foo.s bar.s
$ make -f implicit.mk
touch bar.o bar.i
touch foo.o foo.i
touch target
$

Remove bar.o an run implicit.mk again:

$ rm bar.o
$ make -f implicit.mk
touch bar.o bar.i
touch target
$

Running implicit.mk again:

$ make -f implicit.mk
touch foo.o foo.i
touch target
$

The target is updated again even if nothing was changed!
But something did change the previous time you run make, bar.i got a new
timestamp and that now causes foo.o and foo.i to be rebuilt.

Obviously the change of bar.i is not considered and the update of
foo.o/foo.i is omitted.
The reason that the update of bar.i was not detected at the second run of make
is that bar.i just happened to get touched because of how the recipe was
written. The recipe is something that make just executes. Only targets and
prerequisites are considered when make decides which recipes are to be
executed. So make detects that bar.o needs to be rebuilt after you removed it
and the recipe then just happens to also touch bar.i. I would prefer a rule
like this:

%.o %.i : %.s
        touch $@
The manual (Chpt.: 10.5.1) says:

"Pattern rules may have more than one target; however, every target must contain a |%| character. Multiple target patterns in pattern rules are always treated as grouped targets (see Multiple Targets in a Rule <https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html>) regardless of whether they use the |:| or |&:| separator."

and (Chpt.: 4.10):

"If instead of independent targets you have a recipe that generates multiple files from a single invocation, you can express that relationship by declaring your rule to use /grouped targets/."

This means the rule in implicit.mk is correct:

%.o %.i : %.s
    touch $*.o $*.i

With the above rule, only bar.o and target will be rebuilt after bar.o has
been removed.

regards Henrik

The file 'explicit.mk' describes exactly the same context and yet behaves differently.

Reply via email to