# Makefile Debugging **Debugging Makefiles** is often about understanding why Make made certain decisions. Use flags, echo commands, and systematic investigation. **Dry-run mode (`-n`):** Preview what Make would do without executing: ```bash make -n make -n clean ``` Shows all recipes that would run, in order. Useful for verifying dependencies before running for real. **Verbose mode (`-d`):** Print detailed debug info (heavy output): ```bash make -d | grep -E "Considering|No need|Must remake" | head -20 ``` Shows Make's internal reasoning: which files it's considering, which are out of date, etc. Produces lots of output. **Print variables:** Use `@echo` to inspect values: ```makefile debug: @echo "SRCS: $(SRCS)" @echo "OBJS: $(OBJS)" @echo "CFLAGS: $(CFLAGS)" ``` Run with `make debug`. Helps verify that variables expand as expected. **Print rules:** See what rules apply to a target: ```bash make -p | grep -A 5 "main.o" ``` `-p` (print database) shows all targets and rules. Search for your target to see dependencies and recipe. **Debugging dependency issues:** If a file isn't rebuilding when you expect: ```bash make -d main.o 2>&1 | grep -E "newer|rebuild|remake" ``` Shows whether Make thinks `main.o` is up to date, and why. Look for timestamp comparisons. **Silent recipes:** Recipes print commands by default. Suppress with `@`: ```makefile app: main.o gcc -o app main.o # prints: gcc -o app main.o quiet_app: main.o @gcc -o app main.o # prints nothing, just the output (if any) ``` Use `@` in recipes to reduce noise. But for debugging, remove `@` to see what's executing. **Echo before execution:** Use `@echo` then the command: ```makefile app: main.o @echo "Linking..." gcc -o app main.o ``` Prints `Linking...` then runs `gcc`. Useful for progress messages. **Conditional debugging:** ```makefile ifdef VERBOSE Q = else Q = @ endif app: main.o $(Q)echo "Linking..." $(Q)gcc -o app main.o ``` Set `Q` to `@` (silent) or empty (verbose). Run with `make VERBOSE=1` for details. **Testing pattern rules:** If pattern rules aren't matching: ```bash make -n -p | grep "main.o" ``` Shows which rules could build `main.o` and their prerequisites. Helps diagnose why a pattern rule didn't apply. **Checking for circular dependencies:** ```bash make --trace 2>&1 | head -20 ``` Shows the call stack. Circular dependencies often appear as loops in the trace. **Makefile syntax errors:** Make's error messages can be cryptic: ``` Makefile:5: *** missing separator. Stop. ``` This means line 5 has a recipe without a tab. Check for spaces before commands. **Common mistakes:** ```makefile # Wrong: space before recipe (not tab) app: main.o gcc -o app main.o # ERROR: missing separator # Wrong: variable not defined echo "$(UNDEFINED)" # Wrong: circular dependency a: b b: a # Correct: recipe with tab app: main.o gcc -o app main.o ``` When stuck, use `make -n` to see what Make thinks should happen, and `make -d` for detailed reasoning.