This rule is the whole point of make, and knowing it explains every 'why did/didn't it rebuild?' question.
make's core rule is simple: a target is out of date if the file doesn't exist, or if any of its prerequisites has a newer modification time than it. Out-of-date targets have their recipe run; up-to-date ones are skipped.
Because the check is applied recursively, editing one source file rebuilds exactly the chain above it: util.c changes, so util.o is rebuilt, which makes it newer than app, so app is relinked, while main.o is left alone.
Consequences you'll meet:
- A recipe must actually create or update the target file. If it doesn't, make thinks the target is missing every time and reruns it.
- Listing every real input as a prerequisite matters. If
main.cincludesutil.hbut the rule doesn't list it, editing the header won't trigger a rebuild, and you get stale, confusing builds. touch filemakes a file newer and forces dependents to rebuild;make -Brebuilds everything unconditionally.make -n(dry run) prints what would be executed without running it: the best way to check your rules.- Timestamps can mislead: switching Git branches, copying files with preserved times, or clock skew across network filesystems can make make skip work it should do. When in doubt,
make cleanand rebuild.
Example
out.txt: in.txt
tr a-z A-Z < in.txt > out.txt
# $ echo hello > in.txt
# $ make -> tr a-z A-Z < in.txt > out.txt
# $ make -> make: 'out.txt' is up to date.
# $ touch in.txt
# $ make -n -> tr a-z A-Z < in.txt > out.txt (printed, not run)
# $ make -> runs the recipe again
# $ make -B -> rebuilds even if up to dateRemember
- A target is rebuilt if it is missing or older than any prerequisite
- List every input, including headers, as a prerequisite
- make -n shows what would run; make -B forces a rebuild
Watch out for
- A recipe that never creates its target file, so it runs on every make.