GNU Make


Targets look like this:

target(s): prereq(s)
        recipe line(s)

Recipe lines are indented with hard tabs.

If the prerequisites for a target are newer than the target, then that target will be rebuilt using the recipe.

Double-colon rules can be used if the recipe required to rebuild a target depends on which prerequisite has changed:

target:: foo
        do the thing necessary to rebuild target from foo

target:: bar
        do the thing necessary to rebuild target from bar


The first target defined in the Makefile is the default goal, but you can pass one or more goals on the command-line instead, in which case they will be built in the order specified (and available in $(MAKECMDGOALS)).


Use lower_case names for private variables, and UPPER_CASE names for variables used by implicit rules (like CFLAGS) or for variables meant to be overridden by command-line parameters (like DEBUG).


Make variables come in two flavors: recursively expanded (foo = bar) and simply expanded (foo := bar).

Recursively expanded variables are expanded every time they’re substituted. Consequently, something like this won’t work (because it’s infinite recursion):

foo = $(foo) bar

but this will work (because of the lazy evaluation):

foo = $(bar)
bar = blee

Simply expanded variables are expanded just once, during the first pass.

Conditional definition

To define a variable iff it doesn’t already exist, use the conditional definition operator:

foo ?= bar


Passing a variable on the command-line overrides any definitions of that variable in the Makefile:

FOO = bar
        $(info $(FOO))
$ make

$ make FOO=blee


Environment variables are automatically defined as make variables, unless a variable of the same name is explicitly defined in the Makefile or passed on the make command-line. All make variables are passed as environment variables to recipe sub-shells, except for recursive make invocations, which only receive variables in the parent environment or passed on the command-line (although you can use export to communicate variables to sub-makes).


Makefiles can include other Makefiles:

include doesn’t have to exist, so long as there’s a rule to build it. If an included Makefile is rebuilt, Make will start over from scratch in order to pick up the changes.