>_cmd.script

make

Build automation tool that runs rules from a Makefile

Development

By CMD Script Team · 5 min read · Last updated

SYNTAX
make [OPTIONS] [TARGET...]

Options

Command options and flags
FlagDescription
-f FILEUse FILE as the makefile instead of the default Makefile/makefile
-j NRun up to N recipes in parallel; without N, make tries to run all jobs at once
-nDry run: print the commands that would execute without running them
-C DIRChange to DIR before reading the makefile or doing anything else
-BUnconditionally rebuild all targets, ignoring timestamp comparisons
-kKeep going as far as possible after a recipe fails, instead of stopping immediately

Distribution compatibility

  • Ubuntu
  • Debian
  • Fedora
  • Arch
  • macOS (via Xcode Command Line Tools)

What it does

make reads a Makefile, a declarative description of targets, their prerequisites, and the shell commands (recipes) needed to build each target, then figures out which targets are out of date and runs only the necessary recipes to bring everything up to date. It compares file modification timestamps: if a prerequisite is newer than its target, the target's recipe reruns; if everything is already newer than its dependents, make reports there's nothing to do. This dependency-driven, incremental approach is what makes make fast for large projects — only the parts that actually changed get rebuilt.

Beginner examples

  • make — build the default (first) target in the Makefile, conventionally all
  • make TARGET — build a specific named target, e.g. make test
  • make clean — run a project's conventional clean target to remove build artifacts
  • make -n — dry run, showing what commands would run without executing them
  • make -f custom.mk — use a makefile with a non-default name
make

Advanced examples

  • Build in parallel across all CPU cores: make -j$(nproc)
  • Force a full rebuild, ignoring timestamps: make -B
  • Build a target defined in a Makefile in a different directory without cd'ing there: make -C src all
  • Keep building other independent targets even if one fails: make -k
  • Override a Makefile variable from the command line: make CC=clang CFLAGS="-O2 -g"
  • Install built artifacts to the system (commonly requires root): sudo make install
make -j$(nproc) CFLAGS="-O2 -Wall"

Common mistakes

  • Editing a Makefile recipe line and using spaces instead of a literal tab character — make requires recipe lines to start with a tab, and mixing in spaces produces a "missing separator" error.
  • Assuming make install is a universal, built-in action — it's just a target that happens to be a strong convention; a Makefile without one won't support it.
  • Forgetting that make skips a target's recipe entirely if the target file already exists and is newer than all its prerequisites — a common surprise when a build seems to do nothing after a change to a file the Makefile doesn't know about.
  • Running make -j on a Makefile with implicit shared-state dependencies (recipes that write to the same file) not properly declared as prerequisites, causing race conditions during parallel builds.

Tips

  • Use make -n before running an unfamiliar or risky target to preview exactly what commands would execute.
  • make -j$(nproc) is a quick way to use all available cores without hardcoding a specific number.
  • Check available targets quickly with grep -E '^[a-zA-Z_-]+:' Makefile when a project doesn't document them elsewhere.
  • Use make -C dir target instead of cd dir && make target in scripts — it keeps your script's working directory unchanged.

Best practices

  • Declare all real file outputs and inputs as targets/prerequisites accurately so make can correctly determine what needs rebuilding — incomplete dependency graphs are the most common source of stale-build bugs.
  • Mark targets that don't correspond to real files (like clean, test, install) as .PHONY so make always runs them regardless of whether a file with that name exists.
  • Prefer make -j$(nproc) in CI for faster builds, but ensure the Makefile's dependencies are correct enough to be safe for parallel execution.
  • Use variables (CC, CFLAGS, PREFIX) rather than hardcoding paths and flags, so users can override behavior from the command line without editing the Makefile.

Try it yourself

A simulated shell with a sample home directory — experiment freely, nothing leaves your browser. Type help to list supported commands.

Real-world use cases

  • Building a C/C++ project from source: make compiles only the files that changed since the last build, linking the final binary.
  • Running a project's test suite via a conventional make test target as part of a CI pipeline.
  • Installing a compiled tool system-wide with sudo make install after building from a tarball or git checkout.
  • Automating repetitive multi-step tasks (linting, formatting, building, packaging) by defining each as its own Makefile target.

Common interview questions

  • How does make decide whether to rebuild a target? It compares the modification timestamp of the target file against each of its prerequisites; if any prerequisite is newer, or the target doesn't exist, make reruns that target's recipe.
  • What is a .PHONY target and why is it needed? A .PHONY target tells make that a target name (like clean or test) doesn't correspond to a real file, so make should always run its recipe rather than skipping it because a file with that name happens to exist and look up to date.
  • How do you parallelize a make build? Pass -j N (or -j$(nproc) for all cores) so make runs independent recipes concurrently, based on the dependency graph.
  • Why would a recipe line fail with 'missing separator'? Because make requires recipe lines to be indented with a literal tab character, not spaces; an editor that auto-converts tabs to spaces is a common cause.

Frequently Asked Questions

How does make decide what to rebuild?

make compares the modification timestamp of each target file to its prerequisites. If any prerequisite is newer than the target (or the target doesn't exist yet), make runs that rule's recipe to rebuild it. Unrelated, up-to-date targets are skipped entirely.

What does make install do?

install is just a conventional target name, not a built-in feature. Project Makefiles typically define an install target that copies built binaries, libraries, and man pages into system locations like /usr/local/bin, often controlled by a PREFIX variable.

How do I speed up a build with make?

Use make -j N to run up to N recipes in parallel, e.g. make -j4, or make -j$(nproc) to match the number of available CPU cores. This only helps when the dependency graph has independent targets that can build concurrently.

What happens if I run make with no target?

make builds the first target defined in the Makefile, which by convention is usually named all.

Cheat sheet

Download a quick-reference cheat sheet for make.