I have set of targets, that should be executed according to some order requirements. There is correct order:
wake
fuse
flash
eep
verify
lock
Some of those targets are grouped as another (phony) empty targets:
.PHONY: wake
full: fuse flash eep lock
Unfortunately, when i call make full --dry-run
i see that make
tries to execute rules in incorrect order: wake flash eep lock fuse
. Therefore i get incorrect results (erased-out MCU).
I've tried to add some order-only prerequisites. Here is skeleton of my Makefile with those:
.PHONY: wake
wake:
<...>
.PHONY: flash
flash: build/main.hex | fuse
<...>
.PHONY: eep
eep: build/main.eep.hex | fuse flash
<...>
.PHONY: verify
verify: build/main.hex | fuse flash eep
<...>
.PHONY: fuse
fuse: | wake
<...>
.PHONY: lock
lock: | fuse flash eep
<...>
build/main.hex: <some files here>
<...>
Now make full
works fine, but PHONY order-only target's rules are executed even when i try to execute some specific rule. For example:
make eep
results in execution of wake fuse flash eep
.
I don't want to waste time for full flashing while i need only to write new eep image.
Seems like so-called "order-only prerequisites" are treated like regular prerequisites.
How can i force "order-only prerequisites" to work like real order-only requirements? Is there more elegant solution?
I think you misunderstand what order-only refers to. Order only means that a prerequisite must be built before the target, but if the order-only prerequisite is newer than the target, it does not require the target to be rebuilt. But, if the order-only prerequisite does not exist, the target is still considered out of date (and because all of your targets are .PHONY, none of these exist...)
Instead of using phony targets, you can use 'sentinel' files, which are basically dummy files that mark if/when each of the targets was last run:
.PHONY: flash fuse wake eep verify lock all
all: verify
flash: .flash.sentinel
fuse: .fuse.sentinel
wake: .wake.sentinel
eep: .eep.sentinel
.flash.sentinel: build/main.hex .fuse.sentinel
<...>
touch $@
.fuse.sentinel: .wake.sentinel
<...>
touch $@
.eep.sentinel: build/main.eep.hex fuse.sentinel flash.sentinel
<...>
touch $@
.wake.sentinel: build/main.eep.hex fuse.sentinel flash.sentinel
<...>
touch $@
verify: build/main.hex eep.sentinel fuse.sentinel flash.sentinel
<...>
Notice, that on a clean build, make all
will rebuild everything generating the .sentinel files. Subsequent calls to make all
will only rebuild anything that is considered out of date. So for example, if you modified build/main.hex
, it would rebuild flash
, eep
, wake
and fuse
, but if you don't change anything, it would not do anything (because everything is already done). If you build make flash
, it will rebuild flash, and any other prerequisites it considers out of date.
Now, if, on the other hand you wanted to force only the flash rule to run when you type make flash
, regardless of whether any of the other targets are out of date, then you could add a symmetrical tree, one that has prereq's and one that doesn't:
.PHONY: flash fuse wake eep verify lock
.PHONY: do_flash do_fuse do_wake do_eep do_verify do_lock
.PHONY: all
all: do_lock
flash do_flash:
<...>
fuse do_fuse:
<...>
wake do_wake:
<...>
eep do_eep:
<...>
verify do_verify:
<...>
lock do_lock:
<...>
do_fuse : do_wake
do_flash : do_fuse
do_eep : do_flash
do_verify : do_eep
do_lock : do_verify
Which means if you do make flash
, it has no prerequisites, and will only run the rule. If you do make all
, all
has prerequisite do_verify
, which has another prerequisite, etc, all the way down, and all of these would be run in the correct order.