What Is Make, and Why Should You Care?

Lesson 1: What Is Make, and Why Should You Care?

Make is a build automation tool โ€” one of the oldest pieces of software still in daily use. It was written by Stuart Feldman at Bell Labs in 1976, and fifty years later it's still the backbone of millions of projects, from Linux kernel builds to the Makefiles lurking in most open-source repos. Understanding Make is understanding the fundamental shape of every build system that came after it.

The Problem Make Solves

Imagine a project where main.c and util.c compile into two object files that link into one program. Every time you change one source file, you want to recompile only what changed and relink โ€” not rebuild everything from scratch. That's the incremental build problem, and it predates modern IDEs by decades.

Before Make, developers did this by hand: a shell script that blindly recompiled everything, or a painful mental checklist of "which .o files depend on which .h files." Make's insight was to make this declarative: you describe the relationships between files, and Make figures out the order of operations and the minimal set of work.

app main.o util.o main.c main.h util.c

Arrows point from a file to the files that depend on it. If main.c is newer than main.o, Make recompiles main.o; if any object is newer than app, Make relinks. Everything else is left alone. That's the whole trick โ€” and it's shockingly powerful.

What Make Actually Gives You

CapabilityWhy it matters
Incremental correctnessRebuilds exactly what changed, never more, never less (when the graph is right).
Minimal workA one-line edit triggers one recompile, not a full rebuild.
Parallelismmake -j builds independent targets concurrently using the graph's structure.
ReproducibilityThe Makefile is a machine-readable recipe: anyone can reproduce the artifact.
PortabilityGNU Make runs on Linux, macOS, BSD, and Windows (via MSYS/MinGW/WSL).

Where Make Shines: Good Uses

People associate Make with C, but it works anywhere you have "derive files from other files." Good use cases include:

  • Compiling C, C++, Fortran, Go, Rust, and any language with a compiler.
  • Documentation pipelines โ€” LaTeX to PDF, Markdown to HTML, API docs generation.
  • Code generation โ€” protobuf/Thrift stubs, lex/yacc, OpenAPI clients, database migrations.
  • Data pipelines โ€” derived datasets, reports, and plots where one file depends on others.
  • Packaging โ€” tarballs, Docker images, installers assembled from many inputs.
  • Task orchestration โ€” a make test, make lint, make deploy convention that teams learn once.
Key idea: Make's mental model is "target files depend on prerequisite files, and a recipe turns prerequisites into the target." Once that clicks, everything else โ€” variables, patterns, functions โ€” is just ergonomics on top.
Not a silver bullet: Make is a build tool, not a general task runner or orchestrator. Complex cross-platform builds, web-bundler ecosystems, and large dependency graphs often deserve something else. Lesson 8 covers exactly when to reach for an alternative.

๐Ÿง  Knowledge Check

1. When was Make written, and by whom?

2. What is the core "declarative" idea behind Make?

3. Which of these is a legitimate use case for Make?

Further Reading