3

According to GNU Make Manual

A rule with multiple targets is equivalent to writing many rules, each with one target, and all identical aside from that. The same recipe applies to all the targets, but its effect may vary because you can substitute the actual target name into the recipe using ‘$@’. The rule contributes the same prerequisites to all the targets also.

First Makefile:
%.in %.out:
    echo BLANK > $@

Corresponding bash session:

$ ls
Makefile

$ make a.in a.out
echo BLANK > a.in
make: Nothing to be done for 'a.out'.

$ ls
Makefile  a.in

$ make a.out
echo BLANK > a.out

$ ls
Makefile  a.in  a.out

$ make b.in c.out
echo BLANK > b.in
echo BLANK > c.out

$ make d.in d.out
echo BLANK > d.in
make: Nothing to be done for 'd.out'.

$ make e.out e.in
echo BLANK > e.out
make: Nothing to be done for 'e.in'.

$ ls
Makefile  a.in  a.out  b.in  c.out  d.in  e.out
Second Makefile:
%.in:
    echo BLANK > $@

%.out:
    echo BLANK > $@

Corresponding bash session:

$ ls
Makefile

$ make a.in a.out
echo BLANK > a.in
echo BLANK > a.out

$ ls
Makefile  a.in  a.out

$ # nice       

So, the question:

Why doesn't the first Makefile create targets like <name>.in <same name>.out simultaneously? Why isn't it interpreted similar to the second Makefile?

2 Answers 2

2

Your rules tell make that a single invocation of the recipe will create both the .in and .out targets.

https://www.gnu.org/software/make/manual/html_node/Pattern-Intro.html explains this. It says (in the penultimate paragraph):

"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) regardless of whether they use the : or &: separator. "

If you then follow the link to Multiple Targets it explains that grouped targets (normally using the &: separator when you have explicit rules) tell make that a single invocation of the recipe will create all of them, not just one at a time.

So your pattern rule is the equivalent of this:

a.in a.out &:
        echo BLANK > $@

... and not the equivalent of this as you intended:

a.in a.out :
        echo BLANK > $@

As far as I know, there's no way to make a pattern rule which works like the latter and creates just one at a time. You just have to have separate rules for %.in and %.out

2

You aren't supposed to have multiple implicit targets in a single rule. I don't remember if this is stated anywhere, but rules like that are certainly bad practice. Here's what's going on:

$ cat Makefile 
%.in %.out :
        echo BLANK > $@

$ make -d a.in a.out
[... irrelevant output skipped ...]
Updating goal targets....
Considering target file 'a.in'.
 File 'a.in' does not exist.
 Looking for an implicit rule for 'a.in'.
 Trying pattern rule with stem 'a'.
 Found an implicit rule for 'a.in'.
 Finished prerequisites of target file 'a.in'.
Must remake target 'a.in'.
echo BLANK > a.in
Successfully remade target file 'a.in'.
Considering target file 'a.out'.
File 'a.out' was considered already.
make: Nothing to be done for 'a.out'.

Note the lines:

Considering target file 'a.out'.
File 'a.out' was considered already.

Implicit targets don't "exist" until they get to be tried, and thus the rule doesn't get "split" into multiple rules. When a.in is tried and matched successfully all other targets are marked as tried. The vast majority of time this is not what you want. Just write two rules.

6
  • 1
    Why are rules like that certainly bad practice? I just want to have the same recipe for all files that match pattern *.{in,out}. Isn't writing two rules with same recipes bad practice?
    – belkka
    Aug 27, 2017 at 19:17
  • > When a.in is tried and matched successfully all other targets are marked as tried. < Is it a bug?
    – belkka
    Aug 27, 2017 at 19:17
  • @belkka Why are rules like that certainly bad practice? - Because they don't work the way you expect? As an end user you don't really get to make the rules of the tools you're using. Most of the time you don't even get to choose your tools. The best you can do is learn to avoid their quirks. Aug 28, 2017 at 12:52
  • "When a.in is tried and matched successfully all other targets are marked as tried." I still don't understand, is it a bug or itended behaviour? If it is intended behaviour, were can I read about this? When I use rule with several explicit targets (a.in a.out:) make works as I expect -- when a.in is tried and matched successfully all other targets are not market as tried (?)
    – belkka
    Aug 29, 2017 at 12:36
  • @Sato "Because they don't work the way you expect..." I used to think that you had in mind "It is known to be a bad style of writing makefiles" when wrote "rules like that are certainly bad practice" :)
    – belkka
    Aug 29, 2017 at 12:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .