Est. 1976 Intermediate

Make

The original Unix build automation tool whose dependency-and-recipe model has shaped how software is compiled for nearly fifty years

Created by Stuart Feldman

Paradigm Declarative, Dependency-driven build automation
Typing Untyped (text-based rules)
First Appeared 1976
Latest Version GNU Make 4.4.1 (2023)

Make is the original build automation tool of the Unix world: a program that reads a description of how files depend on one another and runs only the commands needed to bring everything up to date. Created by Stuart Feldman at Bell Labs around 1976, it introduced a deceptively simple idea — a rule pairing a target, its prerequisites, and a recipe — that has proven durable enough to underpin nearly five decades of software construction. Its citation for the 2003 ACM Software System Award put it bluntly: “there is probably no large software system in the world today that has not been processed by a version or offspring of MAKE.”

History & Origins

Make was born from a specific, maddening frustration. As the story is usually told, Steve Johnson — the author of yacc — stormed into Stuart Feldman’s office at Bell Labs, furious at having wasted a morning debugging a program that was already correct. The bug had been fixed in the source, but the corresponding object file had not been recompiled, so the broken binary persisted. The dependency between source and object had been tracked only in a programmer’s head, and that head had forgotten.

Feldman, who joined Bell Labs’ Computing Sciences Research Center around 1973 and worked alongside Unix pioneers such as Ken Thompson, Dennis Ritchie, and Doug McIlroy, realized the dependency relationships could be written down once and acted on mechanically. An early working version of Make was completed around April 1976. Three years later, in April 1979, Feldman described the tool formally in the paper “Make — A Program for Maintaining Computer Programs,” published in Software: Practice and Experience.

Make spread with Unix itself. Vendors produced their own variants — Sun’s DevPro Make, the BSD lineage, and others — and the core behavior was eventually codified in the POSIX.2 standard. In 1988, the GNU Project produced GNU Make, written by Richard Stallman and Roland McGrath, which became the dominant implementation on Linux and, later, macOS.

Design Philosophy

Make’s enduring appeal comes from a single, clear conceptual model that sits between declarative and imperative styles:

  • Declarative dependencies. You describe what depends on what, not the order in which to do things. Make computes the order itself by examining the dependency graph.
  • Incremental by default. Make compares file modification timestamps. A target is rebuilt only if it is missing or older than one of its prerequisites, so unchanged work is skipped automatically.
  • Recipes are just shell. The commands that build a target are ordinary shell lines. Make does not need to understand compilers, linkers, or any particular language — it orchestrates whatever programs you name.

This separation of dependency structure from build commands is the heart of Make’s design. It is general enough to compile C, typeset documents, generate code, run tests, or deploy a website — any task expressible as “to produce X from Y, run this command.”

Core Concepts

Rules

The fundamental unit is the rule. It names a target, the prerequisites it depends on, and a recipe — a sequence of shell commands, each of which must be indented with a tab character (one of Make’s most famous gotchas):

1
2
hello: hello.c
	cc -o hello hello.c

This says: hello depends on hello.c; if hello is missing or older than hello.c, run cc to rebuild it.

Phony Targets

Not every target is a file. Conventional tasks like clean or all are declared .PHONY so Make never confuses them with real files of the same name:

1
2
3
.PHONY: clean
clean:
	rm -f hello *.o

Variables

Variables reduce repetition and make a Makefile configurable:

1
2
3
4
5
CC = gcc
CFLAGS = -O2 -Wall

hello: hello.c
	$(CC) $(CFLAGS) -o hello hello.c

Pattern Rules and Automatic Variables

Pattern rules describe how to build a whole class of files, using automatic variables such as $@ (the target), $< (the first prerequisite), and $^ (all prerequisites):

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

This single rule teaches Make how to turn any .c file into the corresponding .o file, which is why a well-written Makefile can stay short even for a large project.

Putting It Together

A small but complete Makefile for a multi-file C program illustrates the model:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
CC = gcc
CFLAGS = -O2 -Wall
OBJ = main.o util.o

program: $(OBJ)
	$(CC) $(CFLAGS) -o program $(OBJ)

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

.PHONY: clean
clean:
	rm -f program $(OBJ)

Running make builds only the object files whose sources changed, then relinks program. Running make clean removes the build artifacts.

Evolution

For its first decade, Make was a traditional Unix utility, carried along with each vendor’s system and gradually accreting incompatible extensions. The arrival of GNU Make in 1988 reshaped that landscape. Under long-time maintainer Paul D. Smith (who took over in 1997), GNU Make accumulated a powerful set of features that went well beyond the original: a large library of text-manipulation functions, conditional directives, include of other makefiles, automatic dependency generation, and robust parallel execution via make -j and the jobserver protocol that coordinates parallelism across recursive invocations.

Major modern milestones include GNU Make 4.0 (October 2013), which introduced embedded GNU Guile scripting, output synchronization for cleaner parallel logs, and a loadable-object interface for native extensions. GNU Make 4.4 (2022) refined how MAKEFLAGS propagate and improved jobserver behavior, and GNU Make 4.4.1 (February 2023) followed as a bug-fix release that remains the current stable version.

Alongside GNU Make, the BSD make family evolved independently. The makes in FreeBSD, NetBSD, and OpenBSD share Make’s core model but use a distinct dialect (notably .for loops and != shell assignments), and they build their respective base systems wholesale. Microsoft’s nmake and various other implementations round out a diverse ecosystem unified only by the POSIX common subset.

Current Relevance

Despite decades of would-be replacements, Make remains everywhere. The Linux kernel is built by it, GCC requires it, and the GNU Autotools workflow that produces ./configure && make rests entirely on it. Even projects that adopt newer tools often meet Make at the end of the chain: CMake, Autoconf/Automake, and qmake are frequently configured to generate Makefiles, while faster successors like Ninja were designed explicitly to occupy Make’s niche.

In everyday practice, Make has also enjoyed a quiet renaissance as a generic task runner. Many developers keep a small Makefile in a project root simply so that make test, make lint, make build, and make deploy provide a uniform, language-agnostic entry point — a role that requires none of Make’s compilation heritage but benefits from its ubiquity and zero-configuration availability on virtually every Unix-like machine.

Why It Matters

Make’s importance is hard to overstate. It established the dependency graph plus recipes model that every later build system has had to reckon with, either by adopting it (Apache Ant, Rake, MSBuild) or by reacting against its quirks (Ninja’s speed focus, Bazel’s hermeticity). It demonstrated that build orchestration is a problem worth solving with a dedicated, declarative tool rather than ad-hoc scripts.

It is also a cautionary tale studied as carefully as it is praised. The mandatory tab character, the subtleties of recursive Make, timestamp-based staleness checks that can be fooled, and the tension between portability and GNU extensions are all classic lessons in language and tool design. That a program written in 1976 still sits at the center of how the world compiles software — largely unchanged in its core idea — is among the strongest testaments in computing to getting the fundamental abstraction right.

Learning Resources

  • GNU Make Manualhttps://www.gnu.org/software/make/manual/
  • “Make — A Program for Maintaining Computer Programs” by Stuart I. Feldman (the original 1979 paper)
  • Managing Projects with GNU Make by Robert Mecklenburg (O’Reilly)
  • POSIX make specification — part of the IEEE Std 1003.1 utilities

Make rewards a little study: once the rule model and timestamp logic click, it becomes a remarkably general engine for turning one set of files into another — and a direct window into one of the foundational ideas of software engineering.

Timeline

1976
Stuart Feldman writes an early version of Make at Bell Labs (completed around April 1976) to solve the problem of stale object files in incremental builds
1979
Feldman publishes "Make — A Program for Maintaining Computer Programs" in Software: Practice and Experience (April 1979)
1986
Sun releases its DevPro Make, one of several vendor variants that diverged from the original Unix make
1988
GNU Make first appears, written by Richard Stallman and Roland McGrath as part of the GNU Project
1992
Make's core behavior is incorporated into the POSIX.2 standard (IEEE Std 1003.2), defining a portable common subset
1997
Paul D. Smith takes over long-term maintenance of GNU Make, the role he still holds
2003
Stuart Feldman receives the ACM Software System Award for Make
2013
GNU Make 4.0 released (October 2013), adding GNU Guile integration, the output-sync option, and a loadable-object interface
2022
GNU Make 4.4 released, with changes to MAKEFLAGS handling and improved jobserver support
2023
GNU Make 4.4.1 released (February 2023), a bug-fix release that remains the current stable version

Notable Uses & Legacy

Linux Kernel

The kernel's kbuild system is built on GNU Make; building Linux from source is fundamentally a very large, recursive make invocation.

GNU Compiler Collection (GCC)

GCC requires GNU Make to build, and Make has long been the canonical tool for compiling the C/C++ projects GCC targets.

BSD Operating Systems

FreeBSD, NetBSD, and OpenBSD build their entire base systems with BSD make, a separate lineage from GNU Make with its own makefile dialect.

GNU Autotools

Automake generates portable Makefile.in templates that configure expands into concrete Makefiles, making make the execution engine behind ./configure && make.

Embedded and Systems Software

Toolchains for microcontrollers, firmware, and operating systems routinely rely on hand-written Makefiles for fine-grained control over compilation and flashing.

Language Influence

Influenced

Apache Ant Rake MSBuild CMake Ninja

Running Today

Run examples using the official Docker image:

docker pull alpine:latest

Example usage:

docker run --rm -v $(pwd):/app -w /app alpine:latest sh -c 'apk add --no-cache make && make'
Last updated: