Makefile Cheat Sheet
Section titled “Makefile Cheat Sheet”Basic Syntax
Section titled “Basic Syntax”target: prerequisites command command- Target: The file to be created or action to perform
- Prerequisites: Files that must exist before the target can be built
- Commands: Shell commands (must be indented with a TAB, not spaces)
Simple Example
Section titled “Simple Example”hello: hello.c gcc -o hello hello.c
clean: rm -f helloVariables
Section titled “Variables”# Variable definitionCC = gccCFLAGS = -Wall -gSOURCES = main.c util.cOBJECTS = $(SOURCES:.c=.o)
# Using variablesprogram: $(OBJECTS) $(CC) $(CFLAGS) -o program $(OBJECTS)
# Immediate assignment (evaluated immediately)VAR := value
# Recursive assignment (evaluated when used)VAR = value
# Conditional assignment (only if not already set)VAR ?= value
# Append to variableVAR += more_valueAutomatic Variables
Section titled “Automatic Variables”$@ # Target name$< # First prerequisite$^ # All prerequisites$? # Prerequisites newer than target$* # Stem of pattern rule match$(@D) # Directory part of target$(@F) # File part of target
# Example%.o: %.c $(CC) -c $< -o $@Pattern Rules
Section titled “Pattern Rules”# Compile all .c files to .o files%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
# Convert .md to .html%.html: %.md markdown $< > $@
# Multiple patterns%: %.c $(CC) $(CFLAGS) $< -o $@Phony Targets
Section titled “Phony Targets”.PHONY: all clean install test
all: program1 program2
clean: rm -f *.o program1 program2
install: all cp program1 /usr/local/bin/ cp program2 /usr/local/bin/
test: all ./program1 --test ./program2 --testConditional Statements
Section titled “Conditional Statements”# ifeq / ifneqifeq ($(CC),gcc) CFLAGS += -Wextraendif
ifneq ($(DEBUG),) CFLAGS += -DDEBUGendif
# ifdef / ifndefifdef PRODUCTION CFLAGS += -O2else CFLAGS += -gendif
ifndef VERSION VERSION = 1.0endifFunctions
Section titled “Functions”# String substitutionSOURCES = main.c util.cOBJECTS = $(SOURCES:.c=.o)# orOBJECTS = $(patsubst %.c,%.o,$(SOURCES))
# WildcardSOURCES = $(wildcard *.c)
# Shell commandCURRENT_DIR = $(shell pwd)GIT_HASH = $(shell git rev-parse --short HEAD)
# FilterOBJS = main.o test.o util.oMAIN_OBJS = $(filter-out test.o,$(OBJS))
# Directory/basenameDIRS = $(dir src/main.c src/util.c) # src/ src/FILES = $(notdir src/main.c lib/util.c) # main.c util.c
# ForeachDIRS = src lib binALL_SOURCES = $(foreach dir,$(DIRS),$(wildcard $(dir)/*.c))
# Substitution reference$(VAR:old=new) # Replace old with new in VAR
# String functions$(subst from,to,text) # Substitute$(patsubst pattern,replacement,text)$(strip string) # Remove whitespace$(findstring find,in) # Find substring$(filter pattern,text) # Filter matching words$(filter-out pattern,text) # Filter non-matching$(sort list) # Sort and remove duplicates$(word n,text) # Get nth word$(wordlist s,e,text) # Get words s to e$(words text) # Count words$(firstword text) # Get first word$(lastword text) # Get last wordDependencies
Section titled “Dependencies”# Simple dependenciesprogram: main.o util.o helper.o $(CC) -o $@ $^
main.o: main.c util.hutil.o: util.c util.hhelper.o: helper.c
# Auto-generate dependencies%.d: %.c @$(CC) -MM $(CFLAGS) $< > $@.$$$$; \\ sed 's,\\($*\\)\\.o[ :]*,\\1.o $@ : ,g' < $@.$$$$ > $@; \\ rm -f $@.$$$$
-include $(SOURCES:.c=.d)Special Targets
Section titled “Special Targets”.PHONY: target # Target is not a file.SILENT: target # Don't echo commands.IGNORE: target # Ignore errors.PRECIOUS: %.o # Don't delete intermediate files.INTERMEDIATE: %.tmp # Delete after build.SECONDARY: %.o # Don't delete but don't rebuild unnecessarily.DELETE_ON_ERROR: # Delete target if command fails.DEFAULT: # Default rule for unknown targets @echo "No rule for $@"
.SUFFIXES: # Clear suffix list.SUFFIXES: .c .o # Define suffix listCommand Modifiers
Section titled “Command Modifiers”target: @echo "Silent command (no echo)" -rm file.txt # Ignore errors +make other # Always execute (even with -n)Multiple Targets
Section titled “Multiple Targets”# Multiple targets with same recipefile1 file2 file3: dependency command
# Grouped targets (all built together)file1 file2 file3: &: dependency command-that-builds-all-threeInclude Files
Section titled “Include Files”include config.mkinclude *.mk-include optional.mk # Don't error if missingRecursive Make
Section titled “Recursive Make”SUBDIRS = src lib test
all: for dir in $(SUBDIRS); do \\ $(MAKE) -C $$dir; \\ done
# Better approachall: $(MAKE) -C src $(MAKE) -C lib $(MAKE) -C testCommon Patterns
Section titled “Common Patterns”Standard C/C++ Project
Section titled “Standard C/C++ Project”CC = gccCFLAGS = -Wall -Wextra -std=c11 -O2LDFLAGS =LIBS = -lm
TARGET = myprogramSOURCES = $(wildcard *.c)OBJECTS = $(SOURCES:.c=.o)DEPENDS = $(SOURCES:.c=.d)
.PHONY: all clean install
all: $(TARGET)
$(TARGET): $(OBJECTS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
%.d: %.c @$(CC) -MM $(CFLAGS) $< > $@
clean: rm -f $(OBJECTS) $(DEPENDS) $(TARGET)
install: $(TARGET) install -m 0755 $(TARGET) /usr/local/bin/
-include $(DEPENDS)Multi-Directory Project
Section titled “Multi-Directory Project”SRC_DIR = srcBUILD_DIR = buildBIN_DIR = bin
SOURCES = $(wildcard $(SRC_DIR)/*.c)OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)TARGET = $(BIN_DIR)/program
all: $(TARGET)
$(TARGET): $(OBJECTS) | $(BIN_DIR) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) $(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR) $(BIN_DIR): mkdir -p $@
clean: rm -rf $(BUILD_DIR) $(BIN_DIR)
.PHONY: all cleanDebugging
Section titled “Debugging”# Print variable value$(info VAR = $(VAR))$(warning This is a warning)$(error This is an error - stops make)
# Debug targetdebug: @echo "SOURCES: $(SOURCES)" @echo "OBJECTS: $(OBJECTS)" @echo "CFLAGS: $(CFLAGS)"Command Line Usage
Section titled “Command Line Usage”make # Build default targetmake target # Build specific targetmake -n # Dry run (show commands)make -B # Force rebuild allmake -j4 # Parallel build (4 jobs)make -C directory # Run in directorymake VAR=value # Override variablemake --debug # Debug modemake -f other.mk # Use different makefileBest Practices
Section titled “Best Practices”- Always use
.PHONYfor non-file targets - Use
:=for variables that don’t need recursion (faster) - Prefix commands with
@to suppress echo when appropriate - Use prefix to ignore errors selectively
- Generate dependency files for C/C++ projects
- Use pattern rules instead of suffix rules
- Use
$(MAKE)instead ofmakefor recursive calls - Create directories with order-only prerequisites:
| $(DIR) - Quote variables that might contain spaces
- Use
$(shell ...)for external commands