C Project Makefile with Pattern Rules
Create a complete Makefile for a C project with separate compilation, automatic dependency tracking, pattern rules for .c to .o, and clean targets.
Detailed Explanation
Building C Projects with Make
Make was originally designed for C projects, and it remains the most natural build tool for C codebases. A well-structured C Makefile separates compilation from linking, uses pattern rules for automatic object file generation, and defines variables for compiler options.
Variable Definitions
CC ?= gcc
CFLAGS ?= -Wall -Wextra -std=c11 -O2
LDFLAGS ?=
LDLIBS ?= -lm
TARGET = main
SRCS = $(wildcard src/*.c)
OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
The ?= operator allows users to override variables from the command line: make CC=clang. The wildcard function finds all .c files, and the substitution reference $(SRCS:.c=.o) converts source file names to object file names.
Pattern Rules
%.o: %.c
$(CC) $(CFLAGS) -MMD -MP -c -o $@ $<
This pattern rule tells Make how to build any .o file from a corresponding .c file. The -MMD -MP flags generate dependency files (.d) that track header file dependencies automatically. The automatic variables $@ (target) and $< (first prerequisite) eliminate file name repetition.
Linking
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
The $^ variable expands to all prerequisites (all object files), creating the final executable.
Key Points
- Always use
-Wall -Wextraduring development to catch warnings early - The
-include $(DEPS)directive loads generated dependency files without error if they don't exist yet - Use
CPPFLAGSfor preprocessor flags (-I,-D) separate fromCFLAGS - Add
-gtoCFLAGSfor debug builds,-O2or-O3for release builds
Use Case
Setting up a build system for a C application or library with multiple source files, where you need automatic recompilation when headers change and clean separation between debug and release configurations.