Make is like a chef, which use recipes to produce software. And the recipe is called Makefile. Inside makefile, there are lots of targets.

# Makefile basic syntax, this line is comment.
target: prerequisites     # space-separated list
<tab>     shell-commands  # command run in shell

Basics

Make uses file modification timestamps (mtime) to determine if a target needs rebuilding:

  1. If the target does not exist, make runs the following commands.
  2. If any prerequisite is newer than the target, make runs the command to rebuild it.
  3. If the target is newer than all prerequisites, make does nothing.
  4. If any prerequisite is missing, make tries to make missing prerequisite, and this new prerequisite must be newer than target, go to 2.
  5. Prerequisite list could be empty. E.g. phony targets. Phony targets could also have prerequisites.
  6. Make makes the target always the newest.
$ make <target>       # default Makefile, capital M
$ make -f <makefile>  # specify a makefile

If target is missing in make command line, the first target in Makefile is the default target.

.RECIPEPREFIX

As a programmer, tab is always replaced with 4 spaces. Therefore, it’s very convenient to use another symbol.

.RECIPEPREFIX = $  # replace tab with $ symbol
target: prerequisites
$ shell-commands

.PHONY

Some targets are not real, they are defined as PHONY targets. For those phony targets, make would not check if they are existed, and directly run the following commands.

An example:

# $<: the first prerequisite
# $^: the whole prerequisite list
# $@: target

.RECIPEPREFIX = $
.PHONY: all lib clean

lib: libringbb.so
all: lib run clean

libringbb.so: ring_byte_buf.c ring_byte_buf.h
$ gcc -std=c99 -Wall -Wextra -O3 -fsanitize=address -shared -fPIC $< -o $@

run: test_ringbb.c libringbb.so
$ gcc -std=c99 -Wall -Wextra -O3 -fsanitize=address -Xlinker -rpath . $< -o $@ -L. -lringbb
$ ./run

clean:
$ rm -f run
$ rm -f libringbb.so

-jN

# multi-thread compilation
$ make -j8 <target>   # 8 jobs
$ make -j  <target>   # infinite jobs

When there are errors, remove -j and run make again, most like you can reproduce the error!

% match

# targets for every .c file
%.o: %.c

Variables

Built-in:

$(CC): default C compiler
$(MAKE): make itself

$@: current target
$<: the first prerequisite
$^: the while prerequisite list
$(@D): the name of the folder of current target
$(@F): the file name of the current target