GNU make


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:

$ cat 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.