Makefiles: What is an order-only prerequisite?
Asked Answered
G

5

39

The GNU make manual introduces order-only prerequisites:

target: prerequisite1 prerequisite2 | orderonlyprerequisite1 orderonlyprerequisite2

However, while that manual page gives an example and describes the purpose of order-only prerequisites, at no point does the manual page answer the question in the title: What is an order-only prerequisite?

Can you give a precise definition how order-only prerequisites behave?

Grieg answered 21/9, 2019 at 11:26 Comment(0)
K
54

First, let's recall what the ordinary prerequisites are.

Basically, the prerequisites in Makefile have two functions:

  1. They are checked and, if necessary, are built before the target
  2. If any of the prerequisites gets rebuilt (or is simply newer than the target) then the target will also be rebuilt.

Now, the order-only prerequisites do item 1, i.e. impose build-order, but not item 2.

Kismet answered 21/9, 2019 at 11:57 Comment(3)
This doesn't explain which run first the ordered prerequisites or the normal ones. For example, are the normal ones supposed to complete first, before the ordered ones are ran? I'm seeing them all essentially be parallelized when I have two on the right and one of them itself is parallelized, but the docs don't say anything about that.Macdermot
@TrentonD.Adams Parallel execution is a different question which, I believe, was answered many times before.Kismet
@TrentonD.Adams You cannot suppose that. All prerequisites will follow same rules, and the normal ones won't necesarily be completed before the order-only ones. For GNU Make targets, all its children are the same, although the order-only prerequisites won't force a target rebuilt by themselves.Jeffries
R
49

Suppose you have a Makefile like this

baby: love
    touch $@

love: 
    touch $@

then make says,

touch love
touch baby

now you rm love and again make say

touch love
touch baby

because in order to make baby you must make love, and every time you make love, you must make baby. However, suppose you don't want to make baby every time you make love. In that case you can use a pipe.

baby: | love
    touch $@

now you rm love and make says only

touch love

because although in order to make baby you must make love, it is not the case that every time you make love, you must make baby.

Richella answered 30/7, 2021 at 2:10 Comment(10)
In other words the target is not executed on prerequisite update. But I'm wondering about one thing, all this seems to work only if creation of files/folders is involved in recipes (touch in your example), but what if recipe is a command not related to creating/updating any file or folder? How to guarantee that order-only prerequisite does not enforce target?Glad
For instance, I replaced touch in your example with echo and now both target and prerequisite are always executed, no matter if I use order-only or not. Does it mean, the target should always have touch to make sure that it's already been executed and hence does not need to be executed again?Glad
Oh, moreover, looks like the filename should be exactly the same as the target name, other filenames won't work (I guess this is why $@ is used)Glad
@Glad the make is intended to do incremental build. if something is not out of date, then it won't be rebuilt. The only way make can know if something is out of date is my looking at the date of the file. So yes, the target must match the filename. However, if you want to use echo instead of touch, then you need to use phony targets. See gnu.org/software/make/manual/html_node/Phony-Targets.htmlRichella
I cannot resist commenting on this brilliant metaphor in the used example! LolChiles
This is should be the top acceptable answer. Now I will never forget what an order only prerequisite is.Moleskin
I never seen anything like this before in stackoverflow lol. This guy is a genius.Cess
"because in order to make baby you must make love, and every time you make love, you must make baby" -- but if you wanted to do that, couldn't you just run 'make love'? That would already make love without making baby. If you're running 'make baby', doesn't that mean you want to make baby too?Foam
I think I understand the use-case now, it's for prerequisites which must be present but whose content does not affect the outcome of the target produced. In the example: producing baby requires love, but changing love won't affect what baby will be produced. So we don't need to bother reproducing baby, and so only produce love.Foam
@Foam yes that is a good way to think of it. Also, without any pipe, love is a prerequisite resource of baby. But with a pipe, love is a prerequisite action of baby.Richella
L
3

I think the documentation does describe how they behave. It describes how a normal prerequisite behaves:

A normal prerequisite makes two statements: first, it imposes an order in which recipes will be invoked: the recipes for all prerequisites of a target will be completed before the recipe for the target is run. Second, it imposes a dependency relationship: if any prerequisite is newer than the target, then the target is considered out-of-date and must be rebuilt.

Then it describes how the behavior of an order-only prerequisite differs from that; it will:

impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed.

Lumper answered 21/9, 2019 at 12:31 Comment(0)
L
1

Others have already quoted the GNU make manual and given example Makefiles. I'd like to add two situations that benefit from order-only prerequisites.

First, directories as targets. You want to create a file bin/package.jar, and you want to create bin if necessary. This Makefile fragment looks good:

bin/package.jar: bin
    jar cfm $@ manifest.txt $(CLASSES)

bin:
    mkdir $@

But it has a potential flaw. If bin is ever newer than bin/package.jar, then make will rebuild bin/package.jar when it doesn't need to. Yet bin's modification time changes if any files change inside it! This can happen for unexpected reasons in larger Makefiles. The manual describes this:

In this situation, you want the directory to be created before any targets are placed into it but, because the timestamps on directories change whenever a file is added, removed, or renamed, we certainly don’t want to rebuild all the targets whenever the directory’s timestamp changes. One way to manage this is with order-only prerequisites: make the directory an order-only prerequisite on all the targets:

bin/package.jar: | bin
    jar cfm $@ manifest.txt $(CLASSES)

bin:
    mkdir $@

Second, checking if a file exists but ignoring its contents. Suppose you want the same Makefile to create manifest.txt, checking for a Java source file and putting its name inside manifest.txt. Again, use an order-only prerequisite:

MAINCLASS=Coffee

manifest.txt: | $(MAINCLASS).java
    echo "Main-Class: $(MAINCLASS)" > $@

# Other targets may use $(MAINCLASS).java or $(MAINCLASS).class

manifest.txt requires $(MAINCLASS).java to exist. But changing the contents of $(MAINCLASS).java (which changes its modification time, which is what make uses) should not rebuild manifest.txt.

Loricate answered 7/3, 2024 at 2:19 Comment(0)
S
0

Let me take an example like this:

target: update-target-if-this-got-updated | make-this-if-not-available-and-dont-touch-target

So you can easily understand the way it works

  • target : only care about "update-target-if-this-got-updated"
  • make-this-if-not-available-and-dont-touch-target : cares about its own existance
Stead answered 30/5, 2024 at 6:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.