D   A   T   A   W   O   K

Creation: August 28 2016
Modified: September 11 2018

GNU Make

If a target is included as a command-line argument, that target is updated. Else the first target is used (default goal).

target_1 ... target_n: [prereq_1 ... prereq_n] 

Commands are preceded by a TAB character.

If any prerequisite has an associated rule, make attempts to update it first.

If any prerequisite is newer than the target, the associated commands are executed.

Rules types

A rule does not have to be defined all at once.


The wildcards are the same as the bourne shell.

When a wldcard appears in a target or in a prerequisite it is expanded immediatelly by make. When it appears in a command then it is expandedn in the subshell.

Phony tagets

Targets that do not represent files. Normally phony targets are always executed because the commands associated with the rule do notcreate the target name. But if a file named as the phony target exists this will prevent the rule execution. To prevent this problem, it is good practice to explicitly declare such targets as PHONY:

.PHONY: clean
    echo "cleaning"

Automatic variables

Automatically created by make if a rule is matched. Can be used within the commands list context.

VPATH and vpath

The VPATH variable consists of a list of directories to search when make needs a file that is not available in the current directory. The list will be searched for targets as well as prerequisites, but not for files mentioned in commands.

The vpath directive is a more precise way to achieve the same goals. The syntax is

vpath pattern directory-list

Pattern rules

The stem of the target file is represented by a % character. Make built-in rules are all instances of pattern rules. Example, this one specifies how to compile a .o file from a .c file:

%.o: %.c
    $(CC) $(CFLAGS) -c $<

To list all the built-in rules:

$ make --print-data-base

A pattern can contain a prefix, a suffix or both. When the rule is used, the stem if the target is substituted to the stem of the prerequisites.

Special Targets

Is a built-in phony target uses to change make's default behaviour. For instance, .PHONY declares that its prerequisite should always be considered out of date.


Variable are alias to other strings defined via one of the four possible assignment operators.

Characters disallowed in a variable name are :, # and =. To get the value of a variable, enclose the variable name in $() (single letter variable names can omit the parentheses).

Variables a user may want to customize on the command line or in the environment are uppercase.

Spaces before a variable name are trimmend, while ones after the vale not.

Variable types

Simply expanded. The righthand side is expanded immediately and the result saved as the variable value. Are defined using the := assignment operator.

Recusively expanded. The righthand side is (re)expanded every time the variable is used by another expression that is not a recursive assignment. Are defined using the = operator.

Conditional assignment. Assignment is performed if and only if the variable does not yet have a value. Defined by the ?= operator.

Append assignment. Appends text to a variable (even if undefined). For simple variables this can be replaced by the following:

simple := $(simple) newstuff

But the same is not allowed for recursive variables, it yields an infinite loop when expanded. Thus the append operator was the correct way to append text to recursive variables.

Righthand side of += is expanded immediately if the lefthand side was originally defined as a simple variable. Otherwise, its evaluation is deferred.

Lefthand side of a variable assignment is always immediatelly expanded.


A macro is just a variable that can contain embedded newlines. Macros are created using the define directive.

define dosomething
    @echo Creating $@
    touch $@

A macro can be used within a command like a variable.


Macro names are always immediatelly expanded. The macro body expansion is deferred by default, but if we use the assignment operator it follows the same rules as the variables.

Variable expansion

Variable definitions are parsed as follows:

immediate = deferred
immediate ?= deferred
immediate := immediate
immediate += deferred or immediate

define immediate [=]

define immediate ?=

define immediate :=

define immediate +=
    deferred or immediate

immediate: immediate

ifeq/ifneq/ifdef/ifndef immediate

Target specific variables

If a target require a special treatment, for example a specific variable definition, we have two options:

Conditional processing

Parts of a makefile can be omitted or selected while the makefile is being read using conditional processing.

Basic syntax:

    text if the condition is true
    text if the condition is false

The if-condition can be one of:

ifdef variable-name
ifndef variable-name
ifeq test
ifneq test


    echo "defined"
    echo "not defined"

Conditional processing directives can be used within command scripts as well as at the top level.

Within the test part of the conditional spaces are important.

ifeq (a, a)

Is true. While

ifeq ( a, a)

Is false. To prevent such errors we can use the quoted version:

ifeq 'a' 'a'


External pieces of makefile can be included via the include directive. If one of the included files cannot be found make reports the error and continue with the makefile processing to try to find a rule to build the missing include file. If a rule is found, the target is created and the makefile is parsed again, else the error is reported an make stops.


Functions are called as we deference a variable, but includes one or more parameters separated by commas. A function can get data from four sources: parameters passed using call, global variables, automatic variables, and target-specific variables.

User defined

A user defined function is stored in a variable or a macro. Parameters are referenced within the body of the macro with $1, $2, etc.

The syntax for expandig a variable or macro is

$(call macro-name[, param1...])

call is a built-in make function that expands its first argument and replaces occurrences of $1, $2, etc., with the remaining arguments it is given. If parameters are not given then we can omit the call keyword (macro-name) is a normal macro.


All functions have the form

$(function-name arg1[, arg2...])

Many functions accept a single argument, treating it as a list of space-separated words. Many others accept a pattern as an argument. This patterns uses the same syntax as the pattern rules.

Common functions:

Filter. Select a set of files from a list of space separated words. The pattern must match the entire pattern word to be included in the output list (similar to grep -w). A pattern can contain only one %. If additional % characters are included all but the first are treated as literal characters.

$(filter pattern...,text)

Filter-out. Does the opposite of filter

$(filter-out pattern...,text)

Find string. Search for a string in a list of space separated words. The string cannot contaain widcards.

$(findstring string,text)

Search and replace. There are two versions, one that don't handles wildcards, subst and one that handles them, patsubst. Replaces all occurrences of the search string with the replacement string.

$(subst search-string,replace-string,text)

With the wildcard version, the pattern can contain a single %. The search pattern must match the entire value of text.

$(patsubst search-pattern,replace-pattern,text)

Note: Substitution references are a portable way of performing the same substitution


Count words.

$(words text)

Returns the nth word in text.

$(word n,text)

First word in text. Equivalent to $(word 1,text).

$(firstword, text)

Word list. Returns the words in text from start to end, inclusive.

$(wordlist start,end,text)

Sorts its list argument in lexicographic order and removes duplicates. Also strips extra blanks.

$(sort, list)

Shell command. Accepts a single argument that is expanded and passed to a subshell for execution. Standard output is then read and returned as the value if the function. Newlines are colapsed into a single space. Standard error is not returned.

$(shell command)

Wildcard. Accept a list of patters and performs expansion of each one. If a pattern does not match any file the empty string is returned. Normal shell globbing characters are supported: ~, *, ?, [...], and [^...]. The alternative is to use the shell for expansion, but is slower.

$(wildcard files)

Directory portion of each word in list.

$(dir list)

File portion of each word in the list.

$(notdir list)

Returns the suffix of each word in its argument.

$(suffix name, list)

Removes suffix from a list of wordsl

$(basename list)

Appends the given suffix to each word in a list.

$(addsuffix suffix,list)

Prepends the given prefix to each word in a list.

$(addprefix prefix,list)

Concatenates the first element of list1 with the first element of list2, the second element of list1 with the second element of list2, and so on.

$(join list1,list2)


The eval is a special function to feed text directly to the make parser. The argument to eval is first scanned for variables and expanded (as all arguments to all functions are), then the text is parsed and evaluated as if it had come from an input file.

The argument to eval is expanded twice: once when make prepares the argument list for eval, and once again by eval.

Flow Control

The if function (not to be confused with the conditional directives ifeq, ifneq, ifdef, and ifndef) selects one of two macro expansions depending on the "value" od the conditional expression. The condition is true if contains any characters (even space).

$(if confition,then-part,else-part)


A hook is a function reference that can be redefined by a user to perform their own custom tasks during a standard operation. Example

foo-lib: build-lib-hook = @echo "building foo lib"
bar-lib: build-lib-hook = @echo "building bar lib"

Depending on the target the build-lib-hook expands differently.

define build-lib
    $(AR) $(ARFLAGS) $@ $1
    $(call build-lib-hook,$@)


Commands are one-line shell scripts. Make grabs each line and passes it to a subshell for execution. By default the /bin/sh shell is used and overwrites the environment PATH variable value.

Shell execution control statements must be "single line". Semicolons are used to divide the control statements parts. Example:

for i in `seq 1 10`; do echo $$i; done;

An error in one of the commands immediatelly stops the makefile processing. Note that comma separated multiple shell commands are interpreted as one command by the make parser and are passed to the same subshell for execution.

When a subshell is created, make adds few variables to the environment:

Each subprocess make spawns inherits the three std file descriptors: stdin, stdout, and stderr. It is possible for a command script to read the stdin.

Delete on error

If during the built of a target an error happens by default make stops but the partially built file is not deleted. Even worst this file has its timestap updated, thus, on the next rebuild, such a target is considered up-to-date and thus not rebuilt. If a target is added as a prerequisite of the special .DELETE_ON_ERROR target then errors in any target command will cause make to delete the target.

test: test.c
    gcc -o $< $@
    strip test

In the example if strip fails the target is considered up-to-date anyway.

A complementary problem occurs when make is interrupted by signal, such as Ctrl-C. In this case make deletes the target if the target is not in the prerequisites list of the special .PRECIOUS target.


Prefix modifiers

Automatic dependency generation

The gcc compiler has an option to generate a source file include dependency tree in a format comprensible by make. The dependency list is generated by compiling the source with the -M option.

The following is a makefile snip, described by the GNU make docuentation, for automatic dependency generation.

ifneq ($(MAKECMDGOALS),clean)
-include $(sources:.c=.d)

%.d: %.c
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
    $(SED) 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    $(RM) $@.$$$$

Note that the command is executed in one line. This is due to the fact that the temporary file name extension is set to the current process pid ($$). If we execute the multiple shell commands in separate subshells then the pid can change.