# Makefile Dependencies **Dependencies** tell Make what files a target depends on. When a prerequisite is newer than the target, Make rebuilds. For C programs, headers are implicit dependencies—changing a header should rebuild all `.o` files that included it. **Tracking header dependencies:** A simple approach is to list headers explicitly: ```makefile main.o: main.c util.h config.h gcc -c -o main.o main.c util.o: util.c util.h gcc -c -o util.o util.c ``` When `util.h` changes, both `main.o` and `util.o` are rebuilt. When `config.h` changes, only `main.o` is rebuilt. This works but is tedious to maintain. **Automatic dependency generation:** Most projects generate dependencies automatically: ```makefile %.d: %.c @set -e; gcc -MM $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ -include $(SRCS:.c=.d) ``` This generates `.d` files (dependency lists) from `.c` files. The `-include` reads them (- prefix ignores missing files). On the next build, the dependencies are known. **Simpler approach (gcc -M):** ```makefile depend: gcc -MM *.c > dependencies.txt include dependencies.txt ``` Run `make depend` to generate dependencies, then include them. Each `.o` file's dependencies are tracked. **Modern approach (compiler-generated):** ```makefile CFLAGS = -O3 -Wall -MMD -MP %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -include $(wildcard *.d) ``` `-MMD` tells the compiler to generate `.d` files. `-MP` adds phony prerequisites to avoid errors if headers are deleted. The compiler maintains dependencies as a side effect of compilation. **Rebuilding due to timestamp changes:** Make uses file modification timestamps. If a file's timestamp is newer than its target, the target is rebuilt. ```bash touch util.h # update timestamp make # main.o and util.o are rebuilt ``` **Circular dependencies:** Make detects circular dependencies and reports an error: ```makefile a: b b: a ``` This is invalid. Don't create circular dependencies. **Implicit dependencies:** Some files depend on things Make doesn't know about. Make configuration to a default value: ```makefile app: config.h config.h: @echo "#define VERSION 1" > config.h ``` This ensures `config.h` exists and is up to date before building `app`. **Phony dependencies:** A phony target can be a prerequisite: ```makefile .PHONY: check check: @echo "Running checks..." app: main.o check gcc -o app main.o ``` `app` depends on `check`. Every build of `app` runs `check` first (since `check` is phony and always out of date).