5.3.6Build Systems & Toolchain

Makefiles — targets, prerequisites, recipes, variables, automatic variables

1,987 words9 min readdifficulty · medium1 backlinks

WHY does Make exist?

WHAT Make actually reasons about is a graph of files (a DAG — Directed Acyclic Graph). Each node is a file; an edge means "this file is built from that file."


The anatomy of a rule

HOW Make decides to run a recipe

This is recursive: before checking t(Pi)t(P_i), Make first ensures each PiP_i is itself up-to-date (build the prerequisites first). That's a post-order traversal of the dependency DAG.

Figure — Makefiles — targets, prerequisites, recipes, variables, automatic variables

Variables — DRY for build rules

Use variables with $(VAR) or ${VAR}. A single character needs no parens: $@.


Automatic variables — the secret weapon


A complete, real Makefile


Forecast-then-Verify


Flashcards

What are the three parts of a Make rule?
Target, prerequisites, and recipe.
Why must a recipe line start with a TAB?
Make uses the literal TAB as the separator that marks a line as a recipe; spaces give "missing separator" error.
Make's rebuild condition for target T
Rebuild if T doesn't exist OR any prerequisite is newer than T (t(P_i) > t(T)).
Difference between = and :=
= is recursive/lazy (expanded each use); := is simple/eager (expanded once at definition).
What does $@ mean?
The target name of the current rule.
What does $< mean?
The first prerequisite.
What does $^ mean?
All prerequisites, space-separated, duplicates removed.
What does $? mean?
Only the prerequisites newer than the target (the stale ones).
What does $* mean?
The stem matched by % in a pattern rule.
What does .PHONY do?
Declares a target as not a real file, so its recipe always runs even if a file by that name exists.
What does $(SRCS:.c=.o) produce?
A substitution reference replacing the .c suffix with .o in each word of SRCS.
In app: main.o utils.o, recipe $(CC) $^ -o $@, what links?
Links main.o and utils.o into app; $^=all objects, $@=app.
What traversal order does Make use on the dependency DAG?
Post-order — build prerequisites before the target.
Why use ?=?
Assign a variable only if it isn't already defined (good for overridable defaults).

Recall Feynman: explain to a 12-year-old

Imagine you're making a sandwich-building robot. You tell it: "To make a sandwich, you first need bread and filling." The robot is lazy in a smart way: if you already have a sandwich and nobody touched the bread or filling since, it won't waste time making another one. But if you bought fresh bread (newer than the sandwich!), it knows the old sandwich is out of date and builds a new one. The target is the sandwich, the prerequisites are bread and filling, and the recipe is "put filling between bread." The little symbols like $@ are just shortcuts so the robot can say "the thing I'm making" without writing its name again.


Connections

  • Compilation Pipeline — Make orchestrates the preprocess→compile→assemble→link stages.
  • Linkers and Object Files — why $^ (all .o) feeds the linker.
  • Directed Acyclic Graphs (DAG) — Make's dependency model is a DAG traversed post-order.
  • CMake and Build Generators — higher-level tools that generate Makefiles.
  • Incremental Compilation — the timestamp principle that makes Make fast.
  • Shell Scripting Basics — recipes are just shell commands.

Concept Map

reasons about

defined by

has

has

has

must start with

triggers

rebuild if prereq newer

requires

walks

kept DRY by

differ by

uses

Make build tool

File dependency DAG

Rule

Target

Prerequisites

Recipe

Recipe needs literal TAB

Rebuild decision

Post-order traversal

Variables

= vs := vs ?= vs +=

Automatic variables

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Make ek aisa tool hai jo aapke project ko smartly build karta hai — yaani jo file change hui hai sirf usi se jude hisse dobara compile karta hai, baaki ko chhod deta hai. Iska core funda ek hi hai: timestamp comparison. Agar output file (jaise main.o) apni source file (main.c) se purani hai, matlab source naya hai, to Make recipe chala ke output ko dobara banata hai. Agar output already naya hai, to Make kehta hai "already up-to-date" aur time bachata hai.

Har rule ke teen parts hote hain: target (jo banana hai), prerequisites (jis se banega), aur recipe (commands). Ek bahut common galti — recipe line TAB se start honi chahiye, spaces se nahi, warna missing separator error aata hai. Variables = (lazy, har baar expand) aur := (eager, ek hi baar value lock) se banate hain; derived lists ke liye := use karo taaki value stable rahe.

Sabse powerful cheez hai automatic variables: $@ = target, $< = pehla prerequisite, $^ = saare prerequisites. Inki wajah se aap ek hi generic pattern rule (%.o: %.c) likh ke saari .c files ke liye .o bana sakte ho — filename baar-baar likhne ki zarurat nahi. Yaad rakhne ka tarika: @=Aim (target), <=left wala (first), ^=poora hat (all). Ye toolchain ka backbone hai — bade C/C++ projects bina Make ke banana practically impossible hai.

Go deeper — visual, from zero

Test yourself — Build Systems & Toolchain

Connections