24

I have a problem with order-only prerequisites. These do not execute first at all. Am I mis-understanding the way order-only prerequisites work?

The following make script:

.PHONY: mefirst mefirst2

mefirst:
    @echo "I'm first!"

mefirst2:
    @echo "I'm first too!"

normaltarget: normaltarget2 | mefirst2
    @echo "normaltarget done"

normaltarget2: a b c 
    @echo "normaltarget2 done"

helloworld: normaltarget | mefirst
    @echo "helloworld done"

.DEFAULT_GOAL := go
go: helloworld
    @echo "go done"

a:
    @echo a
b:
    @echo b
c:
    @echo c

...prints out the following:

a
b
c
normaltarget2 done
I'm first too!
normaltarget done
I'm first!
helloworld done
go done

...instead of what I would expect:

I'm first!
I'm first too!
a
b
c
normaltarget2 done
normaltarget done
helloworld done
go done

What am I doing wrong?

svick
  • 236,525
  • 50
  • 385
  • 514
George André
  • 770
  • 1
  • 6
  • 14
  • "order-only" doesn't mean "different order". BTW the size of the example could probably be cut in half or more without losing anything. – MarcH Jan 29 '20 at 08:38

1 Answers1

50

Am I mis-understanding the way order-only prerequisites work?

Yes, that is what it looks like.

The name "order-only" is somewhat confusing. The prerequisites behind the | are called "order-only prerequisites" not because they change the order of recipe execution inside the list of prerequisites for a single target, but because their only purpose is to have certain targets created before others, like a bootstrap. As accurately explained by user bobbogo below ( -- thanks for correcting): if make decides to rebuild a prerequisite of a target, it will run the recipe for that prerequisite. Now, for an ordinary prerequisite this update implies that the target is now out-of-date, and make will have to run the target's recipe. For an order-only prerequisite on the other hand, make does not mark the target as needing an update.

For example see the section Types of Prerequisites for a use case where a directory should be created before the objects in that directory are created.

Take this example makefile:

a: b
    touch a

b: c
    touch b

c:
    touch c

x: | y 
    touch x

y: | z 
    touch y

z:
    touch z

As you can see, b and c are normal prerequisites of a and b, whereas y and z are order-only prerequisites of x and y. Starting from a clean slate, they look the same:

:~$ make a
touch c
touch b
touch a
:~$ make x
touch z
touch y
touch x
:~$ make a
make: `a' is up to date.
:~$ make x
make: `x' is up to date.

However, if we now manually "update" the prerequisites at the end of the chain (c and z), we see the difference:

:~$ touch c
:~$ make a
touch b
touch a
:~$ touch z
:~$ make x
make: `x' is up to date.

This shows how order-only prerequisites that exist do not invalidate any targets, independent of their time-stamp. Deleting the order-only target does result in rebuilding though (but only rebuilding of that missing file):

:~$ rm c
:~$ make a
touch c
touch b
touch a
:~$ rm z
:~$ make x
touch z

Having that said, the correct way to change the order in which your recipes are run is by correcting the dependencies between the targets. For example, if you want mefirst to be built before a, then you need to make mefirst a prerequisite for a, as in

a: mefirst
    @echo a

It is not possible to give the entire solution to your question since you did not describe in detail in which order you expect recipes to run.


There is a shortcut to your answer which is not the solution but still interesting to know. Although not documented, it seems that the prerequisites of a single target are processed in the order that they appear. The | sign does not change that. In your simple case, you can take advantage of that to achieve the output that you are looking for:

normaltarget: mefirst2 normaltarget2
    @echo "normaltarget done"

and

helloworld: mefirst normaltarget
    @echo "helloworld done"

However, as pointed out by yourself, this "solution" breaks as soon as the -j flag is used to run recipes in parallel. Also, as pointed out by user bobbogo, relying on this ordering mechanism is bad practice. Introducing new dependencies can interfere with the ordering. So don't do this :-)

Reinier Torenbeek
  • 16,669
  • 7
  • 46
  • 69
  • 2
    Thank you for the clarification Reinier. I tried that first, however it does not work when using -j flag with heavy parallelism. The "myfirst" prerequisite is going to be executed at the same time as the following, since it's all parallell and make tries to make all prerequisites. – George André Jul 21 '14 at 09:56
  • 2
    In that case, if you really need x to be (re-)made before y even in the parallel case, then you have to make x a prerequisite of y itself, as opposed to putting them both on the same line. That is exactly what the prerequisite list is for: to indicate which target depends on which (and therefore which target needs to be (re)made first). However, your question is not detailed enough to provide an exact solution for your case, since it is not clear what exactly the dependencies of your different targets should be. There are many ways to achieve your output. – Reinier Torenbeek Jul 21 '14 at 15:18
  • 4
    Sorry, but this answer is **wrong** in a number of important respects. As @George points out, the order of build is _not_ left to right. If your makefile ever relies on this then it is broken. The fix suggested above is wrong. Also, pre-requisites after the `|` are built in the entirely normal way. If they are not up-to-date, then their recipe will be run. The crucial difference is that after such an update, _make_ will not carry on to run the recipe for the original target. This is in stark contrast to the ordinary pre-reqs—if these needed updating then that implies the target is out of date. – bobbogo Jul 23 '14 at 11:51
  • @bobbogo: The example that I added to the answer contradicts your claim about how prerequisites after the `|` are built and confirms my initial statements -- if I understand your remarks correctly. I did change the answer to include the proper solution and downgrade my initial solution to a quick-and-dirty trick; thanks for the correction. – Reinier Torenbeek Jul 24 '14 at 23:53
  • @Reinier I see no contradiction between my assertion and your test results. Everything is in order. Your opening paragraph about order only pre-reqs is still wrong though :-(. There is nothing special about make rebuilding OOPRs. If they are out of date, make _will_ run their recipe. This is standard behaviour. You say "and then never to be re-made" which is simply **wrong**. – bobbogo Aug 11 '14 at 16:58
  • @bobbogo Then how do you explain the result under the text _However, if we now manually "update" the prerequisites at the end of the chain..._. It shows that `x` is not remade, even though `z` has a newer timestamp. In fact, no recipe is run for the `x y z` example, so the rebuilding of OOPRs _is_ different and it behaves exactly as I described -- and as the documentation describes. – Reinier Torenbeek Aug 11 '14 at 18:50
  • @Reinier Yes it behaves exactly as you described, but that is just coincidence. It also behaves exactly as I and the documentation describe. You can test this by adding the line `.PHONY: z` to the makefile. Now `z` is always out of date. If you `$ make x` (say), you will see that _make_ always updates `z`, even though it is order-only. – bobbogo Aug 12 '14 at 13:30
  • @bobbogo Adding `.PHONY: z` does not explain anything; the purpose of `.PHONY` is to force to always run `z`'s recipe and has nothing to do with order only or regular prerequisites. I do not see how you can explain the difference between the result of `make a` and `make x` in the example that I gave, unless it works the way I described. – Reinier Torenbeek Aug 12 '14 at 15:04
  • 1
    @bobbogo But re-reading the question, I see that the OP has the `.PHONY` target as well -- and therefore you ar of course you are right to say that its prerequisites `mefirst` and `mefirst2` will always be remade. That `.PHONY` target sort of interferes with the concept of OOPR's, I would not expect any OOPR to be the prerequisite of `.PHONY` in the first place. My answer would be accurate if the `.PHONY` target was not there. – Reinier Torenbeek Aug 12 '14 at 15:32
  • @Reinier Your answer currently says about OOPRs "but because their only purpose is to have certain targets created before others, like a bootstrap, and then never to be re-made." OOPRs are confusing, and its unhelpful to post information that's not 100% right. OOPR _are built in the same way that ordinary PRs are_. I would be very interested in an example that disproves this. You can tell this is so by running `make -Rrd` and examining the decisions _make_ is, er, making. – bobbogo Aug 13 '14 at 18:51
  • @bobbogo Like I said before, the example below _"However, if we now manually "update" the prerequisites at the end of the chain (c and z), we see the difference:"_ disproves your statement. The only difference between `a` and `z` is the OORP and the recipes are run in a different way, just like I describe... Please explain the result of that example if OOPRs are indeed built in the same way that ordinary PRs are. – Reinier Torenbeek Aug 13 '14 at 21:06
  • @Reinier In your example, you ask _make_ to make `x`. _make_ looks to see whether `y` is out of date. It then looks to see if `z` is out of date. `z` is not out of date. `z` is however newer than `y`. The _only reason_ `y` is not updated is that `z` is OO. You can see this happening by running `make -Rrd`. The point is _make_ updates all the pre-requisites of `x` as usual, whether they are ordinary or OO. – bobbogo Aug 14 '14 at 12:35
  • 6
    @Reinier The _crucial_ difference between an OOPR and an ordinary PR is this: if make decides to rebuild a PR of a target (whether OO or ordinary), it will run the recipe for that PR (as usual). Now, for an ordinary PR this update implies that the target is now out-of-date, and _make_ will have to run the target's recipe. For an OOPR OTOH, _make_ does not mark the target as needing an update. (The target's recipe may still get run, but that will be due to other PRs, not this particular OOPR.) – bobbogo Aug 14 '14 at 12:46
  • 3
    @bobbogo OK -- sorry for being stubborn and thanks for your additional explanations. I played around with the example `makefile` a bit more, also using your suggested `-Rrd`. It works exactly as you describe indeed, I stand corrected. I will update my answer and thanks for educating. – Reinier Torenbeek Aug 14 '14 at 13:00
  • 1
    I want to thank you both ReinierTorenbeek and @bobbogo for contributing and making this answer outstanding. I ended up doing as you prescribed and everything worked as intended. – George André Jul 27 '15 at 14:42