Make Cheatsheet
Automatic Variables
Use this Make reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
The complete table
Automatic variables are set fresh for every rule, and only exist inside a recipe (or in a target-specific variable value). They are not available in the makefile body.
| Variable | Value |
|---|---|
$@ | The target name |
$< | The first prerequisite |
$^ | All prerequisites, duplicates removed, order-only excluded |
$+ | All prerequisites, duplicates kept, in the order written |
$? | Prerequisites newer than the target |
$* | The stem matched by a pattern rule |
$% | The member name, for an archive target like lib.a(obj.o) |
$| | The order-only prerequisites |
Every one has directory and filename halves. D gives the directory part
without a trailing slash, F gives the filename part.
| Form | For sub/out.o | For a two-word $^ |
|---|---|---|
$(@D) | sub | — |
$(@F) | out.o | — |
$(<D) $(<F) | dir and file of $< | — |
$(^D) $(^F) | — | dirs and files of every word |
$(*D) $(*F) | dir and file of the stem | — |
$(@D) is . when the target has no directory part.
Worked example
Given sub/a.c and sub/b.c, with only sub/b.c newer than the target:
sub/out.o: sub/a.c sub/b.c sub/a.c | sub @echo "$$@ = $@" @echo "$$< = $<" @echo "$$^ = $^" @echo "$$+ = $+" @echo "$$? = $?" @echo "$$(@D) = $(@D) $$(@F) = $(@F)"
Output:
$@ = sub/out.o $< = sub/a.c $^ = sub/a.c sub/b.c $+ = sub/a.c sub/b.c sub/a.c $? = sub/b.c $(@D) = sub $(@F) = out.o
Note that the order-only prerequisite sub appears in none of $^, $+, or
$?. That is what makes cc -o $@ $^ safe next to an order-only mkdir rule.
Which one to use where
| Situation | Use |
|---|---|
| Compile one source to one object | $< |
| Link or archive all inputs | $^ |
| Pass the same input twice on purpose | $+ |
| Rebuild only what changed, incremental tools | $? |
| Derive a sibling name in a pattern rule | $* |
| Create the target's directory inside the recipe | $(@D) |
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $< # $< , exactly one source
app: $(OBJ)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) # $^ , every object
libfoo.a: $(OBJ)
$(AR) rcs $@ $? # $? , only the changed members
%.pb.go: %.proto
protoc --go_out=. $<
@echo "stem was $*" # $* , the path minus the suffixThe stem, $*
$* is only meaningful in a pattern rule or a static pattern rule, and it holds
whatever % matched, including any directory part.
build/%.o: src/%.c @echo "$* = $*" # for build/net/tcp.o , $* = net/tcp
In an explicit rule $* is empty in GNU make when the target has a recognized
suffix, and undefined behavior otherwise. Do not rely on it outside pattern
rules. Use $(basename $@) instead.
Making the directory from $(@D)
Two idioms, both common. The order-only version runs mkdir once, the $(@D)
version runs it on every compile but needs no extra rule.
# Order-only prerequisite, preferred.
build/%.o: src/%.c | build
$(CC) -c -o $@ $<
build:
mkdir -p $@
# Inline, works for arbitrarily deep trees.
build/%.o: src/%.c
@mkdir -p $(@D)
$(CC) -c -o $@ $<For deep source trees the inline form is simpler, because the order-only form would need one directory target per subdirectory.
Escaping and the mistakes people hit
- $$ for shell variables. $@ is make's target. A shell positional or
variable must be $$@, $$1, $$HOME.
- $< in a rule with no prerequisites is empty, and the command silently
runs against nothing. Guard with $(if $<,...) or restructure.
- $^ deduplicates. If a link line genuinely needs a library twice, use
$+.
- $? is empty on the first build because the target does not exist yet, so
every prerequisite counts as newer only after the target appears. Rules built
on $? need a fallback for the create-from-scratch case.
- Automatic variables are not visible in $(info ...) at the top level. They
only exist while a rule is being processed. Print them from inside the recipe.
- Filenames with spaces break everything. Make has no quoting for
prerequisite lists. Rename the files.