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.

This is my first Makefile:

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

And this is my first 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

This is my second Makefile:

%.in:
    echo BLANK > $@

%.out:
    echo BLANK > $@

And this is 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       

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

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.

  • 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 '17 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 '17 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. – Satō Katsura Aug 28 '17 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 '17 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 '17 at 12:58

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.