Skip to content

GNU Make

Why use GNU Make

When you start writing C/C++ projects, you may encounter these situations:

  • A project has multiple source files, and every compile requires a long command
  • Modifying one file forces recompilation of everything, wasting time
  • Complex project structures with many compile options are error-prone to manage manually

GNU Make is a build automation tool that automatically executes compilation and linking by reading Makefile. Almost all C/C++ open-source projects use Make (or Make-based build systems) to manage the build process.

Automated compilation, goodbye to repetitive work

After defining build rules in a Makefile, simply type make to compile the entire project automatically.

Incremental compilation, only recompile modified files

Make detects file modification times and only recompiles changed source files, significantly improving build efficiency.

Cross-platform standard

Make is part of the POSIX standard, available on Linux, macOS, and Windows (via MSYS2/MinGW).

Installing GNU Make

Windows

scoop install make

Note: On Windows, the MSYS2 version of Make is recommended for better compatibility with Unix toolchains.

macOS

Make comes with macOS (via Xcode Command Line Tools):

xcode-select --install

Linux

sudo apt install build-essential

build-essential includes gcc, g++, make, and other basic development tools.

Basic usage

Simplest Makefile

Suppose you have a C project:

main.c
utils.c
utils.h

Create a Makefile:

CC = gcc
CFLAGS = -Wall -g

all: main

main: main.c utils.h
    $(CC) $(CFLAGS) -o main main.c utils.c

clean:
    rm -f main

Usage:

make          # Build the project
make clean    # Clean build artifacts

Core concepts of Makefile

target: dependencies
    command
  • target: The file to generate
  • dependencies: Required files
  • command: Command to generate the target (must start with Tab)

Variables

CC = gcc
CFLAGS = -Wall -g -O2
LDFLAGS = -lm

Automatic variables

$@    # Current target filename
$<    # First dependency filename
$^    # All dependency filenames

Real-world example

A more complete Makefile example:

CC = gcc
CFLAGS = -Wall -g
LDFLAGS = -lm
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
TARGET = myprogram

all: $(TARGET)

$(TARGET): $(OBJ)
    $(CC) $(OBJ) -o $(TARGET) $(LDFLAGS)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f $(OBJ) $(TARGET)

.PHONY: all clean

Other resources