Because the obvious rule "object depends on its source .c" doesn't capture the headers that .c includes. If main.c includes uart.h and you edit uart.h, main.c's own timestamp is unchanged, so Make sees main.o as up to date and skips recompiling it, even though the header it depends on changed. The result is a stale build: main.o was compiled against the old header, so if, say, a struct's layout changed, half your program uses the old layout and half the new, causing memory corruption that's maddening to debug because you "did rebuild." The fix is automatic dependency generation: pass -MMD (and -MP) to GCC so that while compiling it emits a .d file listing every header the translation unit included as additional prerequisites, and then -include those .d files in the Makefile. Now Make knows main.o depends on uart.h, and editing the header correctly recompiles every object that includes it. This auto-dependency setup is considered essential for any non-trivial C/C++ project precisely because hand-maintaining header dependencies is error-prone and forgetting them silently breaks incremental correctness.
Debugging & Toolchain · Interview question
Why might changing a header file not trigger a rebuild, and how do you fix it?
A strong answer
What a weak answer sounds like
You know the answer. Do you know what gets you dinged?
Pro breaks down the answer most candidates actually give to this question — and the specific reason an interviewer marks it down. It’s the difference between sounding correct and sounding senior, on all 472 questions.
From the lesson
The Build Process & Makefiles
Automating compile-and-link and rebuilding only what changed: Make rules (target/prereq/recipe), pattern rules and variables, and auto-generated header dependencies that avoid stale builds.