Skip to content

Instantly share code, notes, and snippets.

@rrbutani
Created July 9, 2025 10:27
Show Gist options
  • Select an option

  • Save rrbutani/df86cb5950b716f9511e93f3ddd9cb95 to your computer and use it in GitHub Desktop.

Select an option

Save rrbutani/df86cb5950b716f9511e93f3ddd9cb95 to your computer and use it in GitHub Desktop.

see:

semantics of order-only deps:

  • when deciding whether to rebuild a target, the mtimes (or existence) of order-only deps are not considered
  • if the target is built (i.e. due to a normal prereq that was newer), it will wait on order-only deps
  • even if the target is not built (i.e. up to date), order-only deps will be scheduled for building (if out of date)

in short: order-only deps need to exist but don't need to be up to date

  • i.e. dep that you're not sensitive to the actual contents of...
  • the example in the fuchsia docs (shared object; file needs to exist to link the final binary but isn't actually read until later, when the binary is run) is actually a pretty good one
  • to be clear: you never build a target with "stale" order-only deps; you just skip rebuilding targets where the only "change" was newer order-only deps

put another way:

  • if your order-only dep rebuilds and your target was deemed dirty and scheduled for building, your target will be built after your order-only dep
  • but your order-only dep rebuilding does not, itself, cause a rebuild of your target
  • i.e. possibilities are:
    • order only deps followed by your target
    • OR: order only deps
  • order is maintained; your target will never be built before its order-only deps

some scenarios to check your understanding:

dirty() { touch $1; sleep 0.1; touch $2; } # make $1 out of date w.r.t. $2

make() { command make -j2; }
ninja() { command ninja -j2; }
check() { make; ninja; }
foo (order only dep) hey (rdep) pre cmd GNU Make Ninja (same as Make)
non-existent non-existent rm foo hey foohey foohey
non-existent dirty (newer pre-reqs) rm foo; dirty hey Makefile foohey foohey
non-existent up-to-date (all pre-reqs older) rm foo; touch hey foo foo
dirty/PHONY non-existent dirty foo{,.inp}; rm hey foohey foohey
dirty/PHONY dirty (newer pre-reqs) dirty foo{,.inp}; dirty hey Makefile foohey foohey
dirty/PHONY up-to-date (all pre-reqs older) dirty foo{,.inp}; touch hey foo foo
up-to-date non-existent touch foo; rm hey hey hey
up-to-date dirty (newer pre-reqs) touch foo; dirty hey Makefile hey hey
up-to-date up-to-date (all pre-reqs older) touch foo; sleep 0.1; touch hey
use nix -p gnumake ninja
/foo
/hey
/.ninja_log
/.direnv
rule touchSlow
command = echo $out... && sleep 1 && touch $out && echo $out done
rule touch
command = echo $out && touch $out
build foo: touchSlow foo.inp
build hey: touch Makefile || foo
foo: foo.inp
@echo foo...
@sleep 1
@touch $@
@echo foo done
hey: Makefile | foo
@touch $@
@echo hey rebuilt
.DEFAULT_GOAL := hey
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment