Est. 1988 Intermediate

GNU Make

The GNU implementation of the Unix make utility — a declarative, rule-based language for describing dependency graphs and the commands that produce files from their prerequisites.

Created by Richard Stallman and Roland McGrath (later maintained by Paul D. Smith)

Paradigm Declarative, rule-based dependency language with embedded shell actions and a macro/text-substitution sublanguage
Typing Untyped (everything is text; variables expand to strings)
First Appeared 1988 (GNU implementation); 1976 (original Unix make by Stuart Feldman at Bell Labs)
Latest Version GNU Make 4.4.1 (2023)

GNU Make is the GNU Project’s implementation of the Unix make(1) utility — a declarative, rule-based language for describing how files are produced from other files and the commands required to do so. A makefile is essentially a directed acyclic graph of dependencies annotated with shell recipes; make walks the graph, compares modification times, and runs the recipes whose outputs are older than their inputs.

The make language — its rule/prerequisite/recipe structure, its tab-indented commands, and its macro syntax — was defined by Stuart Feldman’s original 1976 implementation at Bell Labs and later codified by POSIX. This page is about the GNU implementation of that language: its history, the substantial extensions it adds, and why it has become the de-facto reference make for free Unix systems.

Origins

The original make(1) was written by Stuart Feldman at Bell Labs in 1976 and shipped in Version 7 Unix. Feldman’s paper, “Make — A Program for Maintaining Computer Programs,” introduced the core idea that has remained essentially unchanged for half a century: describe each output file as a target, list the input files it depends on, and write a recipe of shell commands that produces the target from the inputs. The tool decides what to rebuild by comparing file modification timestamps.

The GNU Project needed a freely-licensed implementation of make, and the first GNU Make appeared in 1988. The early implementation was due to Richard Stallman, with substantial contributions and the long-term redesign work coming from Roland McGrath, who served as the primary maintainer for many years. Paul D. Smith took over maintenance in the early 2000s and has shepherded the 3.8x and 4.x series since.

From the very beginning, GNU Make was more than a clone: it added pattern rules, conditional directives, a much richer macro/text-manipulation function library, and the convention of recursive $(MAKE) invocations that became fundamental to building large GNU projects.

The Make Language

A makefile is a sequence of rules, variable assignments, and directives. The canonical rule has the form:

1
2
3
target: prerequisite1 prerequisite2
<TAB>recipe-line-1
<TAB>recipe-line-2

The infamous requirement that recipe lines begin with a literal tab character has tripped up generations of new users; GNU Make 3.82 introduced the .RECIPEPREFIX special variable, which allows the prefix to be redefined, but tabs remain the default and the de-facto convention.

The major language constructs are:

ConstructExamplesPurpose
Explicit rulesfoo.o: foo.c foo.hDeclare a specific target’s dependencies and recipe
Pattern rules%.o: %.cA template applied to any target/prereq pair matching the pattern
VariablesCC = gcc, CFLAGS := -O2, OBJ ?= foo.oRecursive (=), simple (:=), conditional (?=), append (+=)
Automatic variables$@, $<, $^, $*, $?Refer to the current target, first prereq, all prereqs, stem, out-of-date prereqs
Functions$(patsubst %.c,%.o,$(SRCS)), $(shell ...), $(foreach ...), $(if ...), $(call ...)Text manipulation and computation
Conditionalsifeq, ifneq, ifdef, ifndef, else, endifBranch on variable values at parse time
Includesinclude other.mk, -include optional.mkCompose makefiles from fragments
Special targets.PHONY, .PRECIOUS, .SECONDARY, .DELETE_ON_ERROR, .SUFFIXES, .POSIXModify make’s behavior for specific targets or globally

The language has two distinct evaluation phases. First, the entire makefile is read and parsed: variable assignments are processed, includes are followed, conditionals are evaluated, and the rule graph is built. Only after the parse phase does make update targets by walking the graph and running recipes. This two-phase model is the source of much of make’s subtlety — for example, := variables are expanded at parse time while = variables are re-expanded each time they are used, and $(eval ...) lets you generate makefile syntax that is then fed back through the parser.

GNU Extensions Beyond POSIX

GNU Make is a superset of POSIX make, and the extensions are extensive enough that “writing a portable makefile” and “writing a GNU makefile” are essentially different disciplines. Notable GNU-only features include:

  • Pattern rules with %: %.o: %.c matches any .o target with a corresponding .c prerequisite. POSIX make has only the older, more limited suffix rules (.c.o:).
  • $(eval ...) and $(call ...): dynamic makefile generation and parameterized macros, used heavily by Autotools, Kbuild, and Buildroot to construct rules programmatically.
  • .SECONDEXPANSION:: when set, prerequisites are expanded a second time after rules have been parsed, allowing prereqs to refer to automatic variables like $$@.
  • A large function library: $(patsubst ...), $(filter ...), $(filter-out ...), $(sort ...), $(strip ...), $(wildcard ...), $(shell ...), $(foreach ...), $(if ...), $(or ...), $(and ...), $(word ...), $(words ...), $(dir ...), $(notdir ...), $(abspath ...), $(realpath ...), and many more — POSIX make has essentially none of these.
  • Order-only prerequisites: target: normal-prereqs | order-only-prereqs distinguishes prerequisites that must exist but whose timestamps should not trigger a rebuild.
  • Conditional directives: ifeq, ifneq, ifdef, ifndef are GNU extensions, not POSIX.
  • .PHONY, .DELETE_ON_ERROR, .ONESHELL, .NOTPARALLEL: special targets that modify make’s behavior. .ONESHELL in particular changes the long-standing convention that each recipe line is a separate shell invocation.
  • The jobserver protocol: when GNU Make runs in parallel (-jN), recursive sub-makes coordinate their concurrency by reading and writing tokens through a shared pipe (or, since 4.4, named pipes). This allows a build tree to honor a global -j limit even across recursive $(MAKE) invocations.
  • Guile integration (since 4.0): GNU Make can be built with embedded GNU Guile, allowing Scheme code to be called from $(guile ...).
  • Loadable objects (since 4.0): load foo.so dynamically loads shared objects that register new make functions written in C.

These extensions are why a great deal of free software’s build infrastructure quietly assumes GNU Make even when the documentation says “make” — and why gmake is often installed as the GNU implementation on systems whose default make is BSD or Solaris flavored.

Parallelism and the Jobserver

GNU Make supports parallel builds via -jN, where N is the maximum number of recipes that may run concurrently. A naive parallel implementation would oversubscribe the system when one make recursively invokes another, because each sub-make would independently spawn N jobs.

GNU Make solves this with the jobserver protocol: the top-level make creates a pipe pre-loaded with N-1 tokens; each recursive sub-make inherits the pipe’s file descriptors and reads a token before starting a recipe, returning the token when the recipe completes. This way, the total number of concurrent jobs across the entire recursive build tree never exceeds the original -j value. As of GNU Make 4.4, a named-pipe variant of the jobserver was introduced to improve portability and make the protocol usable on systems where inheriting raw file descriptors is awkward.

Standardization and Portability

POSIX standardizes a conservative core of make features:

  • The rule/prerequisite/recipe structure and tab-indented recipes.
  • Suffix rules (.c.o: style).
  • A small set of built-in variables and inference rules.
  • Macros (variables) with simple substitution.
  • A handful of special targets: .SUFFIXES, .DEFAULT, .PRECIOUS, .IGNORE, .SILENT, .POSIX.

GNU Make can be invoked with --posix, or a makefile may begin with the special target .POSIX:, to suppress GNU-specific behavior. In practice, however, most makefiles depend on at least one GNU extension — pattern rules in particular — and portability is achieved either by restricting to a small POSIX subset (as Autotools/Automake do, by generating portable makefiles from higher-level descriptions) or by simply requiring GNU Make and saying so explicitly.

Comparison with Other make Implementations

Several actively maintained make implementations coexist:

  • BSD make (bmake, the NetBSD/FreeBSD/OpenBSD lineage): a different superset of POSIX make, with its own non-overlapping extensions — .for loops, modifier syntax like ${VAR:M*.c}, and a distinct conditional syntax. BSD make and GNU Make makefiles are generally not interchangeable beyond their POSIX-conformant subset.
  • System V make / Solaris make: closer to POSIX, with few extensions; largely of historical interest now.
  • NMAKE (Microsoft): a make-like tool for Windows, syntactically similar but semantically divergent and not compatible with GNU Make.
  • Ninja: not a make-compatible tool, but a deliberately minimal build executor designed to be generated by higher-level systems (CMake, Meson, gn). Ninja was created in reaction to make’s slow incremental-rebuild times on very large projects, and trades make’s macro language and human-authorability for raw speed.

Current Status

GNU Make is actively maintained under Paul D. Smith, with version 4.4.1 released in 2023 as the most recent stable version as of 2026. The project has a relatively slow release cadence appropriate to a piece of infrastructure on which essentially every free-software build depends; backwards compatibility is taken seriously, and behavior changes — such as the macro-expansion tightening in 4.3 — are documented carefully because long-lived makefiles in the wild rely on subtle corner cases.

In day-to-day use, GNU Make is one of the most universally-deployed pieces of free software. It is the default make on GNU/Linux, available under the name gmake on most BSDs, macOS (where Apple reportedly ships an older 3.81 as /usr/bin/make, commonly attributed to GPLv3 licensing concerns), and Solaris derivatives, and it is the orchestration substrate of the Linux kernel, the GNU toolchain, Buildroot, Yocto’s lower layers, and a vast amount of legacy and contemporary infrastructure.

Why GNU Make Matters

  • It is the reference make for the free Unix world. The Linux kernel, glibc, GCC, and the great majority of GNU projects assume GNU Make’s semantics and extensions.
  • Its extensions defined modern make idioms. Pattern rules with %, automatic variables in their modern form, $(eval), the jobserver, order-only prerequisites, and .PHONY discipline are all GNU contributions that are taken for granted by anyone who writes makefiles today.
  • It is a small declarative language that has outlived nearly every fashion in build tooling. Despite many attempts to replace it — Ant, Maven, SCons, Rake, Gradle, Bazel, Buck, Pants, Ninja, Meson — GNU Make remains, often as the substrate that those higher-level systems eventually call into.
  • It exemplifies the GNU philosophy of “compatible superset.” GNU Make behaves like POSIX make when asked to and like a much richer tool by default, the same pattern applied across coreutils, findutils, grep, sed, and the rest of the GNU userland.

For a tool whose surface job is “rebuild files when their inputs change,” GNU Make has proved astonishingly durable: a small, declarative dependency language with an embedded macro processor, almost forty years old in its GNU incarnation, and still the workhorse that quietly compiles much of the world’s free software.

Timeline

1976
Stuart Feldman at Bell Labs publishes the original `make` paper and ships the first `make(1)` in Version 7 Unix; it introduces the rule/prerequisite/recipe structure (target, colon, dependencies, tab-indented commands) that every later make would inherit
1988
GNU Make is released as part of the GNU Project, written initially by Richard Stallman and substantially extended by Roland McGrath; from the start it adds pattern rules, conditional directives, and a richer macro language on top of the Feldman design
1992
IEEE Std 1003.2-1992 (POSIX.2) standardizes a portable `make` dialect; GNU Make tracks POSIX while continuing to ship extensions (the `--posix` option and `.POSIX:` special target select strict POSIX behavior)
1996
GNU Make 3.75 is released, consolidating the modern feature set (pattern rules with `%`, automatic variables `$@`/`$<`/`$^`, conditional `ifeq`/`ifneq`, included makefiles via `include`); the 3.7x/3.8x series becomes the long-lived stable line shipped by Linux distributions for over a decade
2002
Paul D. Smith takes over as the long-term maintainer of GNU Make from Roland McGrath, a role he continues to hold through the 3.8x and 4.x series
2006
GNU Make 3.81 is released, adding the `$(eval ...)` function — which allows a makefile to construct and evaluate further makefile syntax at runtime — and the `.SECONDEXPANSION:` special target, enabling a second pass of variable expansion on prerequisites
2013
GNU Make 4.0 is released, introducing GNU Guile (Scheme) integration as an embedded scripting extension, the `--output-sync` option for clean parallel-build output, and significant performance and portability improvements
2016
GNU Make 4.2 is released, with bug fixes around the jobserver protocol, improved `load` (dynamic loadable-object) support, and refined behavior under `-j` parallel builds
2020
GNU Make 4.3 is released, tightening the semantics of `$(file ...)` and the recipe-expansion rules; some long-standing edge cases in macro expansion are made stricter, which surfaces latent bugs in some long-lived makefiles
2022
GNU Make 4.4 is released, introducing the `--shuffle` option (which randomizes prerequisite order to expose order-dependent bugs), a new jobserver-style based on named pipes for better cross-platform parallel coordination, and the `.NOTINTERMEDIATE:` special target
2023
GNU Make 4.4.1 is released as a maintenance update with bug fixes to the new jobserver and shuffle features; this remains the most recent stable release as of 2026

Notable Uses & Legacy

The Linux Kernel

The Linux kernel build system (`Kbuild`) is built on top of GNU Make and depends explicitly on GNU extensions — pattern rules, `$(eval)`, `$(call)`, recursive sub-makes, and the jobserver — to coordinate the compilation of tens of thousands of source files. Building the kernel without GNU Make is essentially impossible.

GNU Autotools (Autoconf / Automake)

The GNU build system generates portable `Makefile.in` templates that are processed by `configure` into `Makefile`s designed to work with both GNU Make and (portably) POSIX make. Automake-generated makefiles are the lingua franca of `./configure && make && make install` and underlie a substantial fraction of all free-software releases.

GCC, Glibc, Binutils, and the GNU Toolchain

The core GNU toolchain projects use GNU Make for their internal build systems. Bootstrapping GCC, in particular, involves multi-stage builds orchestrated entirely by makefiles that recursively invoke themselves with different configurations.

Embedded and Cross-Compilation Toolchains

Build systems for embedded Linux distributions — Buildroot, Yocto/OpenEmbedded's BitBake (partly), and OpenWrt — are built around GNU Make as the orchestration layer for cross-compilation of thousands of upstream packages. Buildroot in particular is a several-thousand-line GNU Make program.

CMake, Meson, and Other Build-System Generators

Higher-level build systems such as CMake (Unix Makefiles generator) and historical Autotools setups emit GNU Make–compatible makefiles as one of their backend formats. Even projects that author their build logic in CMake or Meson typically execute the final compilation through a `make` invocation.

Documentation, Data Pipelines, and Reproducible Research

Outside of compiling C/C++ code, GNU Make is widely used as a general-purpose task runner — driving LaTeX document builds, static-site generators, ETL/data pipelines, and reproducible-research workflows — because its dependency graph and timestamp-based incremental rebuild model fit those problems naturally.

Language Influence

Influenced By

Unix make (Stuart Feldman, 1976) BSD make System V make

Influenced

CMake (as a generator target) Ninja (reportedly created in reaction to make's incremental-rebuild performance on large projects)

Running Today

Run examples using the official Docker image:

docker pull gcc:latest

Example usage:

docker run --rm -v $(pwd):/work -w /work gcc:latest make
Last updated: