make and Makefile are very important when building a project. As a programmer using Windows, I know little about Makefile.

I will record what I learned about make and Makefile.

Introduction

Rule

1
2
3
4
target ... : prerequisites ...
command
...
...

target is an object file. It can be .o file or any elf file. It can also be a label.

prerequisites are files or objects needed to generate target.

command is any shell command needed to be executed

Example

1
2
3
4
5
6
main: main.o
cc -o main.o
main.o: main.c defs.h
cc -c main.c
clean:
rm main main.o
  1. We will use main.c and defs.h to compile main.c to generate main.o.

  2. We will use link main.o to generate main

  3. clean is a name of an action. Noting is behind : means no prerequisites. So when we execute make, commands under clean won’t be executed automatically. We must write clean, this label after make obviously.

How does it work

The whole procedure is like a stack. To build a , we need b c d. If b c d don’t exist, we need to build b c d. Maybe we need e f g to build b c d.

Finally, we will find all basic files we need and ‘pop’ files one after another. If not, make will fail.

Variable

Now, we have a more complicated example:

1
2
3
4
edit : main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o

As we can see, many .o file repeat two times, which means if we add or remove one file, we must change it in two places. It’s not convenient.

To solve this problem, we can do like this:

1
2
3
4
obj = main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
edit: $(obj)
cc -o edit $(obj)

Now, we only need to change obj to reach our goals.

Automatic derivation

Let’s see the first example

1
2
main.o: main.c defs.h
cc -c main.c

Actually, make knows main.o are built by main.c. So, we don’t need to write a list of commands. The simplified one is like this:

1
main.o: defs.h

We only need to point out the head file main.o needs.

Rules for clean

The original parts for clean are like this:

1
2
clean:
rm main main.o

A more robust way of writing is like this:

1
2
3
.PHONY : clean
clean:
-rm main main.o

.PHONY means that clean is Pseudo target. If there exists a file named clean. .PHONY will take effect.

- means that maybe there’s something wrong with some of the files, but don’t worry. Go ahead.

Rules

VPATH

VPATH in Makefile will point out a directory. If files can’t be found in current directory, make will search in VPATH.

VPATH = src:../headers

In the example above, VPATH point out two directories: src and ../headers. They are separated by :.

vpath

This is a keyword not a variable.

There are 3 methods:

1
2
3
4
5
6
1. vpath <pattern> <directories>
#Specify search <directories> for files that match the <pattern>
2. vpath <pattern>
#Clear search <directories> for files that match the <pattern>
3. vpath
#Clear all <directories> that have been set up

% needs to be included in <pattern>. For example, %.h represents all files ending up with .h.

Pseudo target

clean is a pseudo target. .PHONY specify a pseudo target obviously no matter whether there exists a file named clean.

1
2
3
4
5
6
7
8
9
10
11
all: prog1 prog2 prog3
.PHONY: all

prog1: prog1.o utils.o
cc -o prog1 prog1.o utils.o

prog2: prog2.o
cc -o prog2 prog2.o

prog3: prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o

The first target in Makefile will be used as its default target.

all is a pseudo target depending on three other targets. By this way, many targets can be built together.