make
Automate software build processes
TLDR
Call the first target specified in the Makefile (usually named "all")
Call a specific target
Call a specific target, executing 4 jobs at a time in parallel
Use a specific Makefile
Execute make from another directory
Force making of a target, even if source files are unchanged
Override a variable defined in the Makefile
Override variables defined in the Makefile by the environment
SYNOPSIS
make [options] [targets]
make -f FILE [targets]
PARAMETERS
-f FILE, --file=FILE, --makefile=FILE
Specifies an alternative Makefile to use instead of the default Makefile
or makefile
.
-j [N], --jobs[=N]
Allows N jobs (commands) to run simultaneously. If N is omitted, make
runs as many jobs as possible, typically limited by CPU cores.
-k, --keep-going
Continues building as much as possible even after a command fails.
-n, --just-print, --dry-run, --recon
Prints the commands that would be executed, but does not actually execute them. Useful for debugging Makefiles.
-s, --silent, --quiet
Suppresses the echoing of commands as they are executed, showing only the output of the commands themselves.
-C DIR, --directory=DIR
Changes the current working directory to DIR before reading Makefiles or doing anything else.
-B, --always-make
Unconditionally makes all targets, even if their prerequisites are up to date.
DESCRIPTION
make
is a powerful command-line utility used for automating the compilation of software projects and managing dependencies. Its primary function is to read a Makefile (or makefile) which contains a set of rules defining how to build a project's components. Each rule specifies a target (what to build), its prerequisites (files it depends on), and a recipe (the commands to execute to build the target).
When make
is invoked, it intelligently determines which parts of a project need to be recompiled by comparing the timestamps of target files and their prerequisites. If a prerequisite is newer than its target, or if the target doesn't exist, make
executes the associated recipe. This approach ensures efficient, incremental builds, saving significant time by only rebuilding what has changed. make
is indispensable for large, complex software projects written in languages like C, C++, and for managing general build processes where dependencies need to be tracked precisely.
CAVEATS
While powerful, make
can have a steep learning curve due to its unique syntax and implicit rules. Debugging complex Makefiles can be challenging, especially when dealing with variable expansions and shell interactions. Its dependency on file timestamps can sometimes be problematic in distributed or network file system environments. For highly dynamic build processes or complex package management, newer build systems might offer more flexibility or abstraction.
MAKEFILE STRUCTURE
A Makefile consists of rules, variables, and comments. A basic rule is defined as: target: prerequisites
recipe
where `\t` represents a tab character. Targets are typically files to be created (e.g., executable, object file) or actions to perform (e.g., clean
). Prerequisites are files or other targets the target depends on. The recipe is a sequence of shell commands to execute if the target is out of date or does not exist.
IMPLICIT RULES
make
provides a set of built-in, or implicit, rules that simplify common tasks. For example, it knows how to compile a .c
file into a .o
object file using cc -c $<
without explicit definition in the Makefile. These rules save time and effort, but can sometimes lead to unexpected behavior if not understood.
VARIABLES
Makefiles extensively use variables to store lists of files, compiler options, or paths, making them more organized and reusable. Variables are defined using VAR = value
and referenced with $(VAR)
or ${VAR}
. They significantly enhance the flexibility and maintainability of build configurations.
HISTORY
The make
utility was originally developed by Stuart Feldman at Bell Labs in April 1976. It emerged from the need to manage dependencies in large software projects, specifically to avoid recompiling an entire system when only a few files had changed. Before make
, developers had to manually track file changes and issue compilation commands, a tedious and error-prone process. make
quickly became a standard and essential tool in Unix-like operating systems. The most widely used version today is GNU Make, which has significantly extended the original functionality with features like conditional execution, functions, and powerful string manipulation, solidifying its role as a cornerstone of software development on Linux and other Unix-like platforms.