Appearance
Make Cheatsheet
Overview
GNU Make is a build automation tool that automatically builds executable programs and libraries from source code by reading files called Makefiles which specify how to derive the target program.
Basic Concepts
Makefile Structure
makefile
target: dependencies
command
command
Key Terms
Target # File to be created or action to be performed
Dependency # Files that target depends on
Recipe # Commands to create target
Rule # Target + dependencies + recipe
Variable # Named value that can be reused
Basic Makefile
Simple Example
makefile
# Simple C program build
program: main.o utils.o
gcc -o program main.o utils.o
main.o: main.c
gcc -c main.c
utils.o: utils.c
gcc -c utils.c
clean:
rm -f *.o program
With Variables
makefile
CC = gcc
CFLAGS = -Wall -g
OBJECTS = main.o utils.o
TARGET = program
$(TARGET): $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)
main.o: main.c
$(CC) $(CFLAGS) -c main.c
utils.o: utils.c
$(CC) $(CFLAGS) -c utils.c
clean:
rm -f $(OBJECTS) $(TARGET)
.PHONY: clean
Variables
Variable Definition
makefile
# Simple assignment
CC = gcc
CFLAGS = -Wall -g
# Recursive assignment (evaluated when used)
SOURCES = $(wildcard *.c)
# Simple assignment (evaluated immediately)
OBJECTS := $(SOURCES:.c=.o)
# Conditional assignment (only if not already defined)
CC ?= gcc
# Append to variable
CFLAGS += -O2
Built-in Variables
makefile
# Automatic variables
$@ # Target name
$< # First dependency
$^ # All dependencies
$? # Dependencies newer than target
$* # Stem of pattern rule match
# Example usage
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
Environment Variables
makefile
# Use environment variables
HOME_DIR = $(HOME)
PATH_VAR = $(PATH)
# Override environment variables
export CC = gcc
export CFLAGS = -Wall
Pattern Rules
Basic Patterns
makefile
# Pattern rule for C files
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Pattern rule for C++ files
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
# Multiple patterns
%.o: %.c %.h
$(CC) $(CFLAGS) -c $< -o $@
Advanced Patterns
makefile
# Static pattern rule
$(OBJECTS): %.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Pattern with subdirectories
build/%.o: src/%.c
@mkdir -p build
$(CC) $(CFLAGS) -c $< -o $@
Functions
String Functions
makefile
# Substitution
SOURCES = main.c utils.c
OBJECTS = $(SOURCES:.c=.o)
# or
OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
# Word functions
FIRST_WORD = $(firstword $(SOURCES))
WORD_COUNT = $(words $(SOURCES))
NTH_WORD = $(word 2,$(SOURCES))
# Filter functions
C_FILES = $(filter %.c,$(SOURCES))
NOT_MAIN = $(filter-out main.c,$(SOURCES))
File Functions
makefile
# Wildcard
SOURCES = $(wildcard src/*.c)
HEADERS = $(wildcard include/*.h)
# Directory functions
SRC_DIRS = $(dir $(SOURCES))
BASE_NAMES = $(notdir $(SOURCES))
BASENAMES = $(basename $(SOURCES))
SUFFIXES = $(suffix $(SOURCES))
# Path manipulation
ABS_PATH = $(abspath relative/path)
REAL_PATH = $(realpath symlink/path)
Conditional Functions
makefile
# If function
RESULT = $(if $(DEBUG),debug,release)
# Or function
COMPILER = $(or $(CC),gcc)
# And function
VALID = $(and $(CC),$(SOURCES))
Conditional Statements
ifeq/ifneq
makefile
ifeq ($(DEBUG),1)
CFLAGS += -g -DDEBUG
else
CFLAGS += -O2 -DNDEBUG
endif
ifneq ($(OS),Windows_NT)
CFLAGS += -fPIC
endif
ifdef/ifndef
makefile
ifdef DEBUG
CFLAGS += -g
endif
ifndef CC
CC = gcc
endif
Conditional Assignment
makefile
# Set if not already defined
CC ?= gcc
# Set based on condition
CFLAGS = $(if $(DEBUG),-g -O0,-O2)
Advanced Features
Include Files
makefile
# Include other makefiles
include config.mk
include $(wildcard *.d)
# Silent include (no error if file doesn't exist)
-include optional.mk
Dependency Generation
makefile
# Automatic dependency generation
DEPDIR := .deps
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
%.o: %.c $(DEPDIR)/%.d | $(DEPDIR)
$(CC) $(DEPFLAGS) $(CFLAGS) -c $< -o $@
$(DEPDIR):
@mkdir -p $@
DEPFILES := $(SOURCES:%.c=$(DEPDIR)/%.d)
$(DEPFILES):
include $(wildcard $(DEPFILES))
Order-Only Prerequisites
makefile
# Create directory before building objects
$(OBJECTS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
Phony Targets
Common Phony Targets
makefile
.PHONY: all clean install test help
all: $(TARGET)
clean:
rm -f $(OBJECTS) $(TARGET)
install: $(TARGET)
cp $(TARGET) /usr/local/bin/
test: $(TARGET)
./$(TARGET) --test
help:
@echo "Available targets:"
@echo " all - Build the program"
@echo " clean - Remove build files"
@echo " install - Install the program"
@echo " test - Run tests"
Multi-Target Builds
Multiple Programs
makefile
PROGRAMS = client server
COMMON_OBJS = utils.o network.o
all: $(PROGRAMS)
client: client.o $(COMMON_OBJS)
$(CC) -o $@ $^
server: server.o $(COMMON_OBJS)
$(CC) -o $@ $^
clean:
rm -f *.o $(PROGRAMS)
.PHONY: all clean
Library Building
makefile
LIBNAME = libutils
STATIC_LIB = $(LIBNAME).a
SHARED_LIB = $(LIBNAME).so
LIB_OBJS = utils.o network.o
all: $(STATIC_LIB) $(SHARED_LIB)
$(STATIC_LIB): $(LIB_OBJS)
ar rcs $@ $^
$(SHARED_LIB): $(LIB_OBJS)
$(CC) -shared -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -fPIC -c $< -o $@
Command Line Usage
Basic Commands
bash
# Build default target
make
# Build specific target
make clean
make install
# Build with variables
make DEBUG=1
make CC=clang
# Parallel builds
make -j4
make -j$(nproc)
# Dry run (show commands without executing)
make -n
# Silent mode
make -s
# Keep going on errors
make -k
Debugging
bash
# Print variables
make -p
# Debug mode
make -d
# Print database
make --print-data-base
# Trace execution
make --trace
Complex Examples
C++ Project
makefile
CXX = g++
CXXFLAGS = -std=c++17 -Wall -Wextra -g
LDFLAGS = -lpthread
SRCDIR = src
OBJDIR = obj
SOURCES = $(wildcard $(SRCDIR)/*.cpp)
OBJECTS = $(SOURCES:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
TARGET = myprogram
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CXX) $(OBJECTS) -o $@ $(LDFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $(OBJDIR)
$(CXX) $(CXXFLAGS) -c $< -o $@
$(OBJDIR):
mkdir -p $(OBJDIR)
clean:
rm -rf $(OBJDIR) $(TARGET)
# Dependency generation
-include $(OBJECTS:.o=.d)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp | $(OBJDIR)
$(CXX) -MM -MT $(@:.d=.o) $< > $@
Multi-Directory Project
makefile
# Project structure
PROJECT_ROOT = .
SRC_DIRS = src src/utils src/network
INC_DIRS = include
OBJ_DIR = build
BIN_DIR = bin
# Find all source files
SOURCES = $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
OBJECTS = $(SOURCES:%.c=$(OBJ_DIR)/%.o)
TARGET = $(BIN_DIR)/myapp
# Compiler settings
CC = gcc
CFLAGS = -Wall -g $(addprefix -I,$(INC_DIRS))
LDFLAGS = -lm
.PHONY: all clean dirs
all: dirs $(TARGET)
dirs:
@mkdir -p $(OBJ_DIR) $(BIN_DIR)
@mkdir -p $(foreach dir,$(SRC_DIRS),$(OBJ_DIR)/$(dir))
$(TARGET): $(OBJECTS)
$(CC) $^ -o $@ $(LDFLAGS)
$(OBJ_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Best Practices
Makefile Organization
makefile
# Variables at the top
CC = gcc
CFLAGS = -Wall -g
TARGET = myprogram
# Default target first
all: $(TARGET)
# Pattern rules
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Specific rules
$(TARGET): $(OBJECTS)
$(CC) $^ -o $@
# Phony targets at the end
.PHONY: all clean install
clean:
rm -f *.o $(TARGET)
Error Handling
makefile
# Check for required tools
ifeq ($(shell which $(CC)),)
$(error Compiler $(CC) not found)
endif
# Validate variables
ifndef SOURCES
$(error SOURCES variable is not defined)
endif
# Conditional compilation
ifeq ($(shell pkg-config --exists gtk+-3.0; echo $$?),0)
CFLAGS += $(shell pkg-config --cflags gtk+-3.0)
LDFLAGS += $(shell pkg-config --libs gtk+-3.0)
else
$(warning GTK+ 3.0 not found, building without GUI)
endif
Performance Tips
makefile
# Use order-only prerequisites for directories
$(OBJECTS): | $(OBJDIR)
# Minimize shell calls
SOURCES := $(shell find src -name '*.c')
# Use built-in rules when possible
# Instead of:
# %.o: %.c
# $(CC) $(CFLAGS) -c $< -o $@
# Just use the built-in rule
# Parallel-safe directory creation
$(OBJDIR):
@mkdir -p $@
Integration
With Version Control
makefile
# Get version from git
VERSION = $(shell git describe --tags --always --dirty)
CFLAGS += -DVERSION=\"$(VERSION)\"
# Include git info
GIT_COMMIT = $(shell git rev-parse HEAD)
BUILD_DATE = $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
CFLAGS += -DGIT_COMMIT=\"$(GIT_COMMIT)\" -DBUILD_DATE=\"$(BUILD_DATE)\"
With Package Managers
makefile
# pkg-config integration
CFLAGS += $(shell pkg-config --cflags libssl)
LDFLAGS += $(shell pkg-config --libs libssl)
# Check dependencies
check-deps:
@pkg-config --exists libssl || (echo "libssl not found" && exit 1)
Troubleshooting
Common Issues
bash
# Missing separator error
# Make sure recipes use tabs, not spaces
# Target not found
make: *** No rule to make target 'foo'. Stop.
# Check target name and dependencies
# Circular dependency
make: Circular dependency dropped.
# Review dependency chain
# Debug makefile
make -p | grep target_name
make -d
Debugging Tips
makefile
# Print variable values
debug:
@echo "CC = $(CC)"
@echo "CFLAGS = $(CFLAGS)"
@echo "SOURCES = $(SOURCES)"
@echo "OBJECTS = $(OBJECTS)"
# Check if file exists
check-file:
@test -f myfile.c && echo "File exists" || echo "File missing"
Resources
- Official Manual: gnu.org/software/make/manual
- GNU Make: gnu.org/software/make
- Tutorial: makefiletutorial.com
- Best Practices: clarkgrubb.com/makefile-style-guide