Table of contents
Open Table of contents
๐ Introduction
A practical Make utility cheatsheet covering GNU Make syntax, rules, variables, and functions.
๐งฉ Syntax
target: dependencies
command
command
command
...
target: File names separated by spaces or a label for a recipe.dependencies: Filenames separated by spaces. Files must exist before the commands of the target are executed.command: Commands to be executed. Must start with a tab character.
๐งช Basic Examples
๐ Hello World
Create a simple Makefile that prints โHello, World!โ when you run make hello.
hello:
echo "Hello, World!"
Make Output:
% make hello
echo "Hello, World!"
Hello, World!
Explanation:
hello: Target name.echo "Hello, World!": Command to be executed when thehellotarget is invoked.
When running make hello, Make checks whether the target hello is up to date by looking for a file named hello. Since the target has no prerequisites and no such file exists, Make decides it needs to be built and executes the associated command.
๐ Simple Example with Dependency
Create a Makefile that compiles a C program.
hello: hello.c
cc hello.c -o hello
hello.c:
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
Output:
# First run
% make
cc hello.c -o hello
# Second run
% make
make: `hello' is up to date.
How It Works:
- First Run
- When
makeis executed, the first targethellois looked up. hellotarget has a dependencyhello.c, which exists.- Since the
hellofile does not exist, the commandcc hello.c -o hellois executed to create thehelloexecutable.
- When
- Second Run
- When
makeis executed again, it checks thehellotarget. hellotarget has a dependencyhello.c, which exists.- Since the
hellofile exists and was created afterhello.c,makedetermines that the target is up to date and does not execute any commands.
- When
Note: Make uses file timestamps to determine if a target needs to be rebuilt. If any dependency is newer than the target, the commands will be executed to update the target.
๐งฑ Multiple Targets and Dependencies
Create a Makefile that compiles multiple C programs.
hello: hello.o
cc hello.o -o hello
hello.o: hello.c
cc -c hello.c -o hello.o
hello.c:
echo '#include <stdio.h>\n\nint main() {\n printf("Hello, World!\\n");\n return 0;}' > hello.c
- First Run
makestarts with targethellowhich depends onhello.o(missing).- Recursively walks down:
hello.odepends onhello.c(missing). hello.chas no dependencies, so its command runs first.- Backtracks:
hello.ocommand runs (compileshello.ctohello.o). - Backtracks:
hellocommand runs (linkshello.oto create executable). - All three targets build in dependency order:
hello.cโhello.oโhello.
- Second Run
- When
makeis executed again, it checks thehellotarget. hellotarget has a dependencyhello.o, which exists.hello.otarget has a dependencyhello.c, which exists.- Since all files exist and
hellois newer thanhello.o, andhello.ois newer thanhello.c,makedetermines that no target needs rebuilding and does not execute any commands.
- When
Rule: Rebuild the target if any prerequisite is missing or older than it. Rebuilding a prerequisite triggers rebuilds up the chain.
๐ฏ Rules & Targets
๐งน Target Clean
clean target is commonly used to remove outputs of other targets.
.PHONY: clean
clean:
rm -f *.o hello
- It is not a real file; use
.PHONY: cleanto prevent conflicts if a file namedcleanexists. - Without
.PHONY, if a file namedcleanexists,make cleanwill be skipped (treated as up-to-date). - Runs only when explicitly invoked:
make clean(or by default ifcleanis the first target in the Makefile).
hello: hello.c
cc hello.c -o hello
# To prevent conflicts with a file named 'clean'
.PHONY: clean
clean:
rm -f hello hello.o hello.c
๐งพ Types of Prerequisites
Syntax:
target: normal-prerequisites | order-only-prerequisites
commands
normal-prerequisites: If any of these are newer than the target, the target is rebuilt.order-only-prerequisites: These must exist before the target is built, but do not trigger a rebuild if they are newer than the target.
๐ฆ Target all
allruns all other targets by default.
all: target1 target2
target1:
echo "Building target 1"
target2:
echo "Building target 2"
๐ฏ Multiple Targets
- Multiple targets for a rule will run each target.
target1 target2:
echo "$@"
# Equivalent to:
# target1:
# echo "target1"
# target2:
# echo "target2"
$@expands to the current target name being built.
โธ๏ธ Double Colon Rules
- Allow multiple independent rules for the same target.
- Execute all rules in the order they appear in the Makefile.
- If single colon + multiple rules for same target, only the second rule is used along with warnings.
target::
echo "First rule for target"
target::
echo "Second rule for target"
๐งฎ Variables
- Variables can be strings or lists of strings.
- Reference variables using
$(VAR_NAME)or${VAR_NAME}.
Example:
files = file1 file2
file1_var = file1_var_result
file2_var = file2_var_result
some_file: $(files)
echo "Variables" $(files)
file1:
echo "This is file 1" ${file1_var}
file2:
echo "This is file 2" ${file2_var} > file2
Output:
% make
echo "This is file 1" file1_var_result > file1
echo "This is file 2" file2_var_result > file2
echo "Variables" file1 file2
Variables file1 file2
โ๏ธ Assignment Operators
=: Simple assignment, value is expanded when the variable is used. Value can reference other variables which come after it but before variable is used.:=: Immediate assignment, value is expanded when the variable is defined. Value can reference only other variables which come before it.?=: Conditional assignment, assigns value only if the variable is not already defined.+=: Append assignment, appends value to the existing value of the variable.
# = Assignment example
var1 = "= Assignment: Hello $(var2)"
var2 = " - World"
# =: Assignment expands var2 when var1 is used
var2 := ":= Assignment: Hello $(var2) : $(var3)"
var3 := " -- World"
# =?: Assignment expands var2 when var1 is defined
var4 = "?: Assignment: Hello "
var5 ?= "$(var4) -- World" # this will be set
var4 ?= "$(var4) -- Universe" # this will not set
#=+ Assignment example
var6 = "+= Assignment: Hello"
var6 += " -- World"
all:
echo "[var1] : $(var1)"
echo "[var2] : $(var2)"
echo "[var3] : $(var3)"
echo "[var4] : $(var4)"
echo "[var5] : $(var5)"
echo "[var6] : $(var6)"
Output:
[var1] : = Assignment: Hello := Assignment: Hello - World :
[var2] : := Assignment: Hello - World :
[var3] : -- World
[var4] : ?: Assignment: Hello
[var5] : ?: Assignment: Hello -- World
[var6] : += Assignment: Hello -- World
๐ค Automatic Variables
$@: The file name of the target of the rule.$^: Output all prerequisites.$?: The names of all the prerequisites that are newer than the target.$<: The name of the first prerequisite.
๐ฏ Target-specific Variables
- Target-specific variables allow defining variables that apply only to specific targets.
target1: VAR := "Value for target1"
target1:
echo "In target1: VAR = $(VAR)"
target2:
echo "In all target: VAR = $(VAR)"
- In this example,
VARis set to โValue for target1โ only when buildingtarget1. Fortarget2,VARis undefined unless set globally.
๐งฉ Pattern-specific Variables
- Pattern-specific variables allow defining variables that apply to targets matching a specific pattern.
%.tgt: VAR := "Value for $@"
s.tgt:
echo "In $@: VAR = $(VAR)"
a.b:
echo "In $@: VAR = $(VAR)"
๐ซ Override Directive
- Variables can be overridden via command line arguments (e.g.,
make VAR=value). - Use the
overridedirective to force a variable value and prevent command line overrides.
VAR1 := "default"
override VAR1 := "forced"
VAR2 := "normal"
.PHONY: vars
vars:
echo "VAR1 = $(VAR1)"
echo "VAR2 = $(VAR2)"
- VAR2 can be overridden via command line, but VAR1 cannot due to the
overridedirective.
% make -s VAR1=var1_override_value VAR2=val2_override_value
VAR1 = forced
VAR2 = val2_override_value
๐ฉ MAKEFLAGS Variable
MAKEFLAGSvariable contains the flags passed tomakecommand.
var = 10
all:
echo "[$(var)] : MAKEFLAGS : $(MAKEFLAGS)"
Output:
make -s -i
[10] : MAKEFLAGS : si
๐ Patterns & Wildcards
๐ Wildcard - *
*: Matches filenames, can be used in targets, dependencies orwildcard()function.- Variable assignment:
*withoutwildcard()is treated literally. - Dependency or target:
*is expanded by the shell to match filenames. If no files match, it remains as*.
files := $(wildcard *.c)
tgt: $(files)
echo "C source files: $^"
ls -lrt $?
Other scenarios:
incorrect_assignment := *.c # treated literally as the string "*.c"
correct_assignment := $(wildcard *.c) # expands to matching .c files
all: first second third
# Fails, string *.c is used as literal dependency - not available
first: $(incorrect_assignment)
# stays as *.c literal, shell expands it at runtime
second: *.c
third: $(correct_assignment)
๐ช Wildcard - %
matchingmode: Matches one or more characters in a string called a โstemโ.replacingmode: Takes stem frommatchingmode and replaces it in the target pattern.- Often used in pattern rules.
๐งฑ Static Pattern Rules
Syntax:
targets...: target-pattern: prereq-patterns...
commands
Example:
objects = file1.o file2.o file3.o
all: $(objects)
cc $^ -o all
$(objects): %.o: %.c
cc -c $< -o $@
all.c:
echo "int main() { return 0; }" > all.c
# Note: all.c does not use this rule because Make prioritizes more specific matches when there is more than one match.
%.c:
touch $@
clean:
rm -f *.c *.o all
With Filter:
obj_files = foo.result bar.o lose.o
src_files = foo.raw bar.c lose.c
all: $(obj_files)
# Note: PHONY is important here. Without it, implicit rules will try to build the executable "all", since the prereqs are ".o" files.
.PHONY: all
# Ex 1: .o files depend on .c files. Though we don't actually make the .o file.
$(filter %.o,$(obj_files)): %.o: %.c
echo "target: $@ prereq: $<"
# Ex 2: .result files depend on .raw files. Though we don't actually make the .result file.
$(filter %.result,$(obj_files)): %.result: %.raw
echo "target: $@ prereq: $<"
%.c %.raw:
touch $@
clean:
rm -f $(src_files)
๐ Pattern Rules
- Used to define rules for building files that match a certain pattern.
- Define fallback rules for building files when no specific rule is found.
- More specific rules take precedence over pattern rules.
%.c:
touch $@
program: first.c second.c
cc $^ -o program
โ๏ธ Commands & Execution
๐ Command Echoing/Silencing
- By default,
makeechoes each command before executing it. - To silence a specific command, prefix it with
@. - Run
makewith-sor--silentto silence all command echoing.
target:
@echo "This command will not be echoed"
echo "This command will be echoed"
๐ต Double Dollar Sign ($$)
- In Makefiles, a single dollar sign (
$) is used for Makefile variable references. - To pass a literal dollar sign to the shell command, use double dollar signs (
$$).
Example: print the current working directory using pwd command:
target:
echo "Current directory: $$(pwd)"
โถ๏ธ Command Execution
- Each command in a recipe is executed in a separate shell instance by default.
- To run all commands in the same shell instance:
- Use a line continuation (
\) at the end of each line except the last. - Separate commands with semicolons (
;).
- Use a line continuation (
target1:
cd ..
echo "Current directory: $$(pwd)"
target2:
cd ..; echo "Current directory: $$(pwd)"
๐ Default Shell
makeuses/bin/shas the default shell to execute commands.- To change the shell, set the
SHELLvariable at the top of the Makefile.
SHELL := /bin/bash
target:
echo "Using shell: $$BASH_VERSION"
๐จ Error Handling
- By default, if a command fails (returns a non-zero exit status),
makestops executing further commands. - To ignore errors for a specific command, prefix it with a hyphen (
-). - Add
-kor--keep-goingoption when runningmaketo continue building other targets even if some fail. Target that are failed and their dependents will be skipped. - Add
-ior--ignore-errorsoption when runningmaketo ignore all errors.
all: target1 target2 target4
target1: target3
echo "**target1**:Building target1 on when make -i is used"
target3:
echo "**target3**: Building target3 by default"
false
echo "**target3**: This command will only run if 'make -i' is used."
target2:
echo "**target2**: Building target2 on when make -i or -k is used"
false
echo "**target2**: This command will run only if 'make -i' is used."
target4:
-false
echo "**target4**: This command will run because the error is ignored. only if make -i or -k is used."
Outputs:
- Output with
make -s: Normal behavior, stops on first error.
**target3**: Building target3 by default
make: *** [target3] Error 1
- Output with
make -k -s: Ignores error targets and its dependencies, continues building other targets after errors.
**target3**: Building target3 by default
make: *** [target3] Error 1
**target2**: Building target2 on when make -i or -k is used
make: *** [target2] Error 1
**target4**: This command will run because the error is ignored. only if make -i or -k is used.
make: Target `all' not remade because of errors.
- Output with
make -i -s: Ignores all errors, continues executing all commands.
**target3**: Building target3 by default
**target3**: This command will only run if 'make -i' is used.
**target1**:Building target1 on when make -i is used
**target2**: This command will run only if 'make -i' is used.
**target4**: This command will run because the error is ignored. only if make -i or -k is used.
๐ Killing a Make Process
- To stop a running
makeprocess, you can send an interrupt signal (SIGINT) by pressingCtrl + Cin the terminal wheremakeis running.
๐งฐ make arguments
--dry-runor-n: Show what would be done, without actually doing it.-touch: Update the timestamps of targets without executing commands.--old-file=FILENAMEor-o FILENAME: Consider FILENAME as up to date.make clean run test: You can specify multiple targets to be built in a singlemakecommand, it runs each target in the order they are specified.
๐ Advanced Features
๐ Recursive Make
- Use
$(MAKE)variable to invokemakerecursively in sub-makefiles. - Instead of calling
makedirectly, use$(MAKE)to ensure that any flags or options passed to the top-levelmakeare also applied to the sub-make.
contents := "subdir: \n\techo \"Running for Recursive Make\""
all:
echo "$(contents)"
echo "building sub-makefile in subdir..."
mkdir -p subdir
echo "$(contents)" > subdir/Makefile
$(MAKE) -C subdir
๐ค export Directive
- Use
exportdirective to make variables available to sub-makefiles or shell commands executed bymake.
VAR1 := "Hello"
VAR2 := "World"
export VAR1
all:
echo "Exported shell variable: $$VAR1"
echo "Non exported make variable: ${VAR2}"
.EXPORT_ALL_VARIABLESspecial target exports all variables to sub-makefiles and shell commands.
.EXPORT_ALL_VARIABLES:
VAR1 := "Hello"
VAR2 := "World"
all:
echo "Exported shell variable: $$VAR1"
echo "Exported shell variable: $$VAR2"
๐งพ Define Directive
definedirective allows defining multi-line commands which can be reused in various targets.define,endefsyntax is used to define a multi-line variable.
define cann_script
echo "Starting cann process..."
sleep 1
echo "Cann process completed"
endef
cann1: cann2
$(cann_script)
echo "Cann1 target finished."
cann2:
$(cann_script)
echo "Cann2 target finished."
๐ Conditional Directives
- Conditional directives allow conditional execution of parts of the Makefile based on certain conditions.
ifeq (arg1, arg2),ifneq (arg1, arg2),ifdef VAR,ifndef VARare used for conditional checks.
VAR := value
eqtest:
ifeq ($(VAR), value)
echo "VAR is equal to value : $(VAR)"
else
echo "VAR is not equal to value : $(VAR)"
endif
neqtest:
ifneq ($(VAR), other_value)
echo "VAR is not equal to other_value : $(VAR)"
else
echo "VAR is equal to other_value : $(VAR)"
endif
ifdeftest:
ifdef VAR
echo "VAR is defined : $(VAR)"
else
echo "VAR is not defined"
endif
ifndeftest:
ifndef VAR1
echo "VAR1 is not defined"
else
echo "VAR1 is defined : $(VAR1)"
endif
Output:
VAR is equal to value : value
VAR is not equal to other_value : value
VAR is defined : value
VAR1 is not defined
๐ ๏ธ Functions
๐งฑ Function Syntax
$(function-name arguments) or ${function-name arguments}
๐ Text Functions
| Function | Description | Example |
|---|---|---|
subst from,to,text | Replace all occurrences of from with to in text. | $(subst .c,.o,src.c src2.c) โ src.o src2.o |
patsubst pattern,replacement,text | Replace words in text matching pattern with replacement. | $(patsubst %.c,%.o,src.c tgt.p) โ src.o tgt.p |
strip text | Remove leading and trailing whitespace from text. | $(strip Hello World ) โ Hello World |
findstring find,text | Search for find in text. Returns find if found, else empty. | $(findstring World,Hello World!) โ World |
filter pattern...,text | Return words in text that match any of the patterns. | $(filter %.c %.h,src.c tgt.p src2.h) โ src.c src2.h |
filter-out pattern...,text | Return words in text that do not match any of the patterns. | $(filter-out %.c %.h,src.c tgt.p) โ tgt.p |
sort list | Sort words in list lexicographically and remove duplicates. | $(sort banana apple orange apple) โ apple banana orange |
word n,text | Return the nth word from text (1-based). | $(word 3,one two three four) โ three |
wordlist s,e,text | Return words from s to e (inclusive) from text. | $(wordlist 2,4,one two three four) โ two three four |
words text | Return the number of words in text. | $(words one two three four) โ 4 |
firstword text | Return the first word from text. | $(firstword one two three) โ one |
lastword text | Return the last word from text. | $(lastword one two three) โ three |
๐ File Functions
| Function | Description | Example |
|---|---|---|
dir names... | Return the directory part of each file name. | $(dir src/main.c inc/header.h) โ src/ inc/ |
notdir names... | Return the file name part (without directory). | $(notdir src/main.c inc/header.h) โ main.c header.h |
suffix names... | Return the suffix (extension) of each file name. | $(suffix src/main.c README) โ .c |
basename names... | Return the base name (without suffix). | $(basename src/main.c inc/h.h) โ src/main inc/h |
addsuffix suffix,names... | Add suffix to each file name. | $(addsuffix .o,main util) โ main.o util.o |
addprefix prefix,names... | Add prefix to each file name. | $(addprefix src/,main.c util.c) โ src/main.c src/util.c |
join list1,list2 | Join corresponding elements from two lists. | $(join a b,c d) โ ac bd |
wildcard pattern... | Return list of existing files matching patterns. | $(wildcard src/*.c) โ src/main.c src/util.c |
realpath names... | Return absolute paths (resolves symlinks). | $(realpath ./src/main.c) โ /path/to/src/main.c |
abspath names... | Return absolute paths (does not resolve symlinks). | $(abspath ./src/main.c) โ /path/to/src/main.c |
โ Conditional Functions
| Function | Description | Example |
|---|---|---|
if condition,then,else | If condition is non-empty, return then; else else. | $(if $(VAR),Set,Not Set) |
or cond1,cond2,... | Return first non-empty condition. | $(or $(V1),$(V2),default) |
and cond1,cond2,... | Return first empty condition, or last if all non-empty. | $(and $(V1),$(V2)) |
intcmp lhs,rhs[,lt,eq,gt] | Compare integers lhs and rhs. Returns lt, eq, or gt arg. | $(intcmp 5,10,lt,eq,gt) โ lt |
๐งช Let Function
Syntax: $(let var [var ...], list, text)
letfunction allows defining temporary variables for use withintext.var: One or more variable names to define.list: Values to assign to the variables.text: The text in which the temporary variables can be used.
Example:
result = $(let x y z, 10 20 30, $(shell echo "$(x), $(y), $(z) => SUM: $$(($(x)+$(y)+$(z))))"))
all:
echo $(result)
Output:
% make
echo 10, 20, 30 => SUM: 60
๐ Foreach Function
foreachfunction iterates over a list and applies a specified operation for each item.
Syntax: $(foreach var, list, text)
var: The loop variable that takes each value fromlist.list: A space-separated list of items to iterate over.text: The operation to perform for each item, wherevaris replaced by the current item.
Example:
items = apple banana cherry
all:
echo $(foreach item, $(items), Item: $(item))
๐ File Function
file operation, filename, text: Perform file operations like reading and writing files.- Modes:
overwrite: Writetexttofilename, replacing existing content.>operator is used.append: Appendtexttofilenameusing the>>operator.
- Used for providing long command line arguments.
Example:
long_text = This is a very long text that needs to be written to a file for use in a command line argument.
all:
$(file >long_arg.txt, $(long_text))
cat long_arg.txt
Output:
% make all
cat long_arg.txt
This is a very long text that needs to be written to a file for use in a command line argument.
๐ Call Function
callfunction is used to invoke user-defined functions with arguments.
Syntax: $(call function-name, arg1, arg2, ...)
function-name: The name of the user-defined function.$(0)refers to the function itself.arg1, arg2, ...: Arguments to pass to the function.$(1),$(2), โฆ refer to the arguments.
Example:
define greet
Hello, $(1)
endef
all:
echo $(call greet, World)
Output:
% make all
Hello, World
๐ Value Function
value var: Retrieve the literal (unexpanded) value of a variablevar.
Syntax: $(value var)
var: The name of the variable whose literal value is to be retrieved.
Example:
VAR1 := $HOME
all:
echo "Expanded VAR1: $(VAR1)"
echo "Literal VAR1: $(value VAR1)"
Output:
% make -s
Expanded VAR1: OME
Literal VAR1: /Users/turingx
- In $HOME, the H is missing in the expanded output because Make interprets
$Has a variable reference (which is empty) followed by the string โOMEโ. Thevaluefunction retrieves the literal value without expansion, showing the full path.*