C Mastery / Build Systems: Make, CMake, Ninja, Meson
Part 5 — Compilation, Linking, and Building

Build Systems: Make, CMake, Ninja, Meson

This chapter covers the tools that automate compiling and linking: Make, CMake, Ninja, and Meson. They solve the same problem — incremental builds — at different levels of abstraction.

Why This Matters

Hand-typing compiler commands does not scale. Build systems track dependencies and rebuild only what changed, and meta-build systems (CMake, Meson) generate builds for multiple generators and platforms.

Prerequisites

Core Concept

Make

make reads a Makefile of targets, prerequisites, and recipes:

app: main.o util.o
	cc main.o util.o -o app

main.o: main.c util.h
	cc -c main.c

util.o: util.c util.h
	cc -c util.c

It rebuilds a target only when a prerequisite is newer.

CMake

CMake is a meta-build system. You write CMakeLists.txt; CMake generates Makefiles, Ninja files, or IDE projects.

cmake_minimum_required(VERSION 3.16)
project(app C)
add_executable(app main.c util.c)

Ninja

Ninja is a fast, low-level build tool. You usually do not write Ninja files by hand; CMake/Meson generate them.

Meson

Meson is a modern meta-build system with a Python-like language and Ninja as its default backend.

project('app', 'c')
executable('app', 'main.c', 'util.c')

Examples

Make build

make            # build
make clean      # clean

CMake build

cmake -S . -B build -G Ninja
cmake --build build

Meson build

meson setup build
meson compile -C build

How It Works

Make uses timestamps and a dependency graph. Ninja does the same but is optimized for speed and parallelism. CMake/Meson generate low-level build files, so the *generated* system does the actual tracking.

Variations

Dependency generation

Compilers can emit dependency info (-MMD -MP), which build systems consume to track header changes automatically.

Out-of-source builds

CMake/Meson encourage building in a separate build/ directory, keeping the source tree clean.

Common Mistakes

Undefined Behavior

Portability

platform-appropriate builds.

Under the Hood

Build systems construct a directed acyclic graph of build steps and execute the minimal set needed to bring outputs up to date. Ninja is designed for incremental speed; Make is the classic interpreter.

Practical Usage

Exercises

1. Write a Makefile for a two-file project with a header dependency. 2. Convert the project to CMake and build it out-of-source. 3. Use -MMD -MP and confirm header changes trigger rebuilds. 4. Build the same project with Meson + Ninja.

Deep Challenge

Set up a CMake project with a static library and an executable that links it, plus a compile definition that toggles a feature. Explain how CMake's dependency tracking handles header changes and rebuilds.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.build.make05
c.build.cmake05
c.build.ninja05
c.build.meson04