RedGrittyBrick
RedGrittyBrick

Reputation: 4002

Preserving order of prerequisites in $^ in GNU make

Given this makefile

.SUFFIXES: .mmd .tmp .html

a.html : h.tmp a.tmp
b.html : h.tmp b.tmp
c.html : h.tmp c.tmp C.tmp

.tmp.html:
        cat $^ > $@

.mmd.tmp:
        Markdown.pl $< > $@

where h.mmd is a header to be inserted at the start of each html file.

The command make ?.html produces this

$ touch h.mmd
$ make ?.html
Markdown.pl h.mmd > h.tmp
cat a.tmp h.tmp > a.html
cat b.tmp h.tmp > b.html
cat c.tmp h.tmp C.tmp > c.html

The prerequisites have been sorted alphabetically. Can I preserve the order specified in the dependency lines so that the cat command includes each part in the specified order?

Upvotes: 2

Views: 63

Answers (2)

MadScientist
MadScientist

Reputation: 100956

It doesn't have anything to do with alphabetical order or sorting. The prerequisites are not sorted and the value of $^ is not rearranged, with one exception:

In all implicit rules the implicit dependency is always the first element in the prerequisite list, regardless of whether you added it later as an explicit prerequisite in a different location.

It might be simpler to see if you convert your suffix rule into a pattern rule (but both work the same): A suffix rule like:

.tmp.html: ; cmd

is the same thing as a pattern rule like:

%.html: %.tmp ; cmd

So if you have:

%.html: %.tmp ; @echo $^

c.html : d.tmp b.tmp c.tmp a.tmp

because the pattern match for a target c.html is c, the matching prerequisite c.tmp will always be the first prerequisite even though they're listed in different order in the explicit prerequisites list. So the output of this will be:

c.tmp d.tmp b.dmp a.tmp

Note: not sorted, but the matching prerequisite appears first.

There is no way to "turn this off". The only solution, as suggested by @RedGrittyBrick, is to not list the prerequisite pattern at all. You can use their idea of:

%.html: ; @echo $^

c.html : d.tmp b.tmp c.tmp a.tmp

Or continue to use a suffix rule like:

.html: ; @echo $^

c.html : d.tmp b.tmp c.tmp a.tmp

and both will give the same result:

d.tmp b.tmp c.tmp a.tmp

Upvotes: 3

RedGrittyBrick
RedGrittyBrick

Reputation: 4002

I don't properly understand this but one way that worked for me was to make a one-line change to replace the suffix rule .tmp.html: with a pattern rule %.html:

.SUFFIXES: .mmd .tmp .html

a.html : h.tmp a.tmp
b.html : h.tmp b.tmp
c.html : h.tmp c.tmp C.tmp

%.html:
        cat $^ > $@

.mmd.tmp:
        Markdown.pl $< > $@

which preserves order

$ touch h.mmd
$ make ?.html
Markdown.pl h.mmd > h.tmp
cat h.tmp a.tmp > a.html
cat h.tmp b.tmp > b.html
cat h.tmp c.tmp C.tmp > c.html

So that is an answer, albeit incomplete because ...

What I understand:

  • A target can have multiple rules.
  • $^ is the combined set of all prerequisites from all rules for a target.

What I don't understand:

  • Why this affects the order of the elements of $^ in the same command.

Upvotes: 0

Related Questions