Makefiles
- /
- The Blog — Skills & Methods /
- Makefiles
- Michael
- Shell , Programmation
- October 11, 2025
Table of Contents
Make is used to manage executables and program compilation, and it is very effective for large projects because it recompiles only what has changed.
Make is also useful for various small tasks, such as archiving files, etc.
How to use Make
To use make, first create a file named : Makefile
Here is what a makefile consists of :
<target> : <prerequisites>
<command>
Makefiles can define variables (strongly recommended); these variables follow common conventions, are optional, and save a lot of time.
# CC / CXX -> CXX = C++ -> Compilers
# CFLAGS / CXXFLAGS -> Compilation flags
# LDFLAGS -> Linker flags
# SRC -> where the .c files are located
# OBJ -> selects the .o files
# EXEC -> executable name
# Special (automatic) variables
$@ -> target name
$< -> first prerequisite name
$^ -> list of prerequisites
$? -> prerequisites newer than the target
$* -> filename stem without its extension
# Variable declarations:
CC = gcc
EXEC = prog
CFLAGS = -Wall -Wextra -Werror
SRC = $(wildcard *.c) -> Tell it to take all .c files
OBJ = $(SRC:.c=.o) -> Same as SRC but replace .c with .o
# To reference a variable, just write:
$(CC)
It is possible to write conditionals in a makefile.
WINDOWS = yes
ifeq ($(WINDOWS), yes) # If the WINDOWS variable equals yes (ifeq = if equal)
$(EXEC) = prog.exe
else
$(EXEC) = prog
endif
# Makefile layout
#===================================================================#
Layout "BruteForce"
all : prog
prog : main.o code.o # Create prog from main.o and code.o; if they don't exist, build them below *1
gcc -o prog main.o code.o # prog depends on main.o and code.o
main.o : main.c # Build main.o here *2
gcc -o main.o main.c # main.o depends on main.c
code.o : code.c # Then build code.o and go back up *3
gcc -o code.o code.c # code.o depends on code.c
#===================================================================#
Layout "Fast but not safe"
all : $(EXEC) # Same idea as above
# Use % to mean “any”
%.o : %.c # Like (*2 / *3): every .o depends on the corresponding .c
$(CC) -o $(OBJ) -c $(SRC) # Same command as the two above (*2 / *3)
$(EXEC) : $(OBJ) # Then build the target program (*1)
$(CC) -o $(EXEC) $(OBJ) # Same idea as (*1)
#=====================================================================#
Layout "Safe when files depend on each other"
all : $(EXEC)
%.o : %.c
$(CC) -o $@ -c $< # $@ = target (%.o), $< = first prerequisite (%.c)
$(EXEC) : $(OBJ)
$(CC) -o $@ -c $^ # $@ = target ($(EXEC)), $^ = list of prerequisites ($(OBJ)), i.e., all .o files
You can also create targets to organize your files, for example a clean target.
clean : # No prerequisites needed here
rm -rf *.o
Sources : Makefile tutorial