33

Possible Duplicate:
GNU Makefile rule generating a few targets from a single source file

If I have a Makefile rule like this:

a b c:
    echo "Creating a b c"
    touch a b c

output: a b c
    cat a b c > output

and I run make -j9 output

make sees the 3 dependencies (a,b,c), looks for how to produce them: (the "a b c" rule above), but what happens next? Should it not realize that the "a b c" rule only needs to be run once to create all 3 targets?

This is what make actually does:

[pavel@orianna test]$ make -j9 output -n
echo "Creating a b c"
touch a b c
echo "Creating a b c"
touch a b c
echo "Creating a b c"
touch a b c                                                                                                                                                                                                                                                                    
cat a b c > output                                                                                                                                                                                                                                                             
[pavel@orianna test]$

The same recipe is run 3 times, once for each dependency to rule "output"!

Does anyone know why it behaves this way?

Community
  • 1
  • 1
Pavel
  • 5,320
  • 8
  • 35
  • 45
  • Related: http://stackoverflow.com/questions/3016258/generate-multiple-target-using-single-action-rule and http://stackoverflow.com/questions/2973445/gnu-makefile-rule-generating-a-few-targets-from-a-single-source-file – krlmlr Jun 19 '12 at 22:23
  • As of GNU make version 4.3, this is supported by grouped targets. You only need to change `:` for `&:`. https://www.gnu.org/software/make/manual/make.html#Multiple-Targets – jonas-schulze Dec 07 '22 at 16:01

2 Answers2

32

Your a b c: rule tells Make that this is how to build any of these targets, not how to build all of them. Make is not smart enough to analyze the commands and deduce that running the rule once will build all three. Make knows (from the output rule) that it must rebuild a, b and c, so that's what it does. It runs the first rule once for a, once for b and once for c.

If you want to rebuild them individually, do this:

a b c:
    echo "Creating $@"
    touch $@

If you want to rebuild them all at once, do something like this:

.PHONY: things
things:
    echo "Creating a b c"
    touch a b c

output: things
    cat a b c > output

or better still:

THINGS = a b c
.PHONY: things
things:
    echo "Creating $(THINGS)"
    touch $(THINGS)

output: things
    cat $(THINGS) > output
Beta
  • 96,650
  • 16
  • 149
  • 150
  • 3
    Great answer! Thank you. Is creating a phony target the only way, or is there a cleaner way to express "a **and** b **and** c are built by this rule"? – Pavel Aug 16 '11 at 18:06
  • @Pavel, I don't know of a cleaner way (and I would probably take the first option anyhow). But then again I'm still trying to figure out AUZKamath's answer. – Beta Aug 16 '11 at 18:17
  • 13
    See http://www.cmcrossroads.com/ask-mr-make/12908-rules-with-multiple-outputs-in-gnu-make for a survey of methods to deal with this scenario, including the only "correct" way to specify a rule with multiple outputs in gmake (pattern rules, of course!). – Eric Melski Aug 16 '11 at 18:47
10

a b c are three different goals/targets with no prerequisites to it. i,e to say it will build the target whenever it is asked to.

a b c:
    echo "Creating a b c"
    touch a b c

You are asking make to build target named output that has a b c as prerequisites. So targets a b c are built sequentially and finally output is built.

Now in your case all the targets gets built invariably when either of one is called. So to avoid redundant build you will have to add prerequisites to targets a,b,c. Build target 'a' only if 'a' does not exist. Similarly for 'b' and 'c'

a b c: $@
    echo "Creating a b c"
    touch a b c

However this is not advisable. Ideally Makefile targets should be very specific.

Kamath
  • 4,461
  • 5
  • 33
  • 60
  • 2
    This works, but I can't see how. Did Jack Kelly send you? – Beta Aug 16 '11 at 18:17
  • 1
    However, when running this with `make -j3 a b c`, three jobs are created. – krlmlr Jun 19 '12 at 14:49
  • 2
    Can anybody explain how this works? I cannot explain it by reading https://www.gnu.org/software/make/manual/make.html#index-_0024_0040 – Xiphias Sep 06 '16 at 13:28
  • 1
    @krmlr @Xiphias The trick is that when `make` considers `a`, it sees the rule `a: a`. The target is to be rebuilt only if it's older than any of its prerequisites or if any of its prerequisites don't exist. Here the first case is never true and the second case is true only if `a` doesn't exist yet. After the `touch`, `b: b` and `c: c` don't need to be rebuilt. (As for `-j3`, three processes saw `a: a`, `b: b`, `c: c` and worked on them before any `touch`.) – Kirill Bulygin Mar 02 '17 at 16:59