Summary

The lab assumes that you are familiar with compiling and linking C code and focuses on how to automate the process through the use of make and Makefiles.

The lab covers

  1. What are Makefiles and how to invoke make

  2. What are Makefile rules, targets, prerequisites and recipes.

  3. Makefile variables

For more detailed information on make consult the documentation that came with your OS and online.

What are Makefiles and how to invoke make

Makefiles are text files that reside on your drive. By convention the file is also called Makefile. Here is an example

Makefile
hello:
    gcc hello.c -o hello

To run this Makefile type

make

in the same directory as the file. Alternatively you can specify the name of the Makefile to make by using the -f option, e.g.,

make -f Makefile

What are Makefile rules, targets, prerequisites and recipes.

Makefiles contain rules . A rule has the following schema

target : prerequisite ...
  TAB    recipe
         ...
  • You can think of target as the name of the file that this rule will generate.

  • After the colon : we have a space separated list of files/targets that are prerequisites. The list of prerequisite can be empty. If the prerequisite is a file, make will look for this files in your current folder. If a prerequisite is a target make will jump to that target and create it first before coming back to this rule.

  • The next line must start with a TAB special character. It must be a TAB and not spaces.

  • Following the TAB character we have the commands that make will perform in order to create the target.

So looking at our simple Makefile from the previous section, we have

  1. one target called hello

  2. the target hello has no prerequisites

  3. the recipe is the command gcc hello.c -o hello

By default make will run the first target in the Makefile. In the case that we want to run some other target we can pass the target name as an argument to make, e.g., make hello.

Makefiles also accommodate targets that are not files. These are called phony targets. Think of phony targets as names for tasks.

Makefile.2
all: hello     (1)

hello:         (2)
	gcc hello.c -o hello

.PHONY: all   (3)

We can tell make which target(s) are phony by using the special target name .PHONY and listing all the phony targets as prerequisites.

1 specifies that all has one prerequisites hello and there are no recipes for target all. This means that make will have to build the target hello first in order to satisfy the target All.
2 is a new target that we added called hello, it has no prerequisites and the recipe builds hello.c
3 specifies all as a phony target.

If we do not specify all as a phony target and it happens that there is a file with the name all, make will take into account the file’s timestamp when calculating what needs to be build. This might have side effects you do not expect.

Another typical phony target is clean. This is the target typically used to remove temporary and generated files.

Makefile.3
all: hello

hello:
	gcc hello.c -o hello

clean:                  (1)
	-rm hello *.o   (2)

.PHONY: all clean
1 defines our new rule named clean.
2 the recipe runs the command rm hello *.o to remove the executable hello and files with the suffix .o. Notice the starting hyphen -. The starting hyphen instructs make that it should not fail in case that the command fails, e.g., calling make clean when there is no hello file or any \*.o file will fail the execution of rm but the target clean will succeed.

Here is the output from running make clean when there is no hello file or *.o files present

make -f Makefile.3 clean
rm hello *.o
rm: cannot remove ‘hello’: No such file or directory
rm: cannot remove ‘*.o’: No such file or directory
make: [clean] Error 1 (ignored)

Let’s also update our rule for hello. There is a prerequisites that we should have for that target, hello.c. When the file changes we would like make to rebuild the target hello and any other target that depends (has hello as a prerequisite) on hello.

Makefile.4
all: hello

hello: hello.c
	gcc hello.c -o hello

clean:
	-rm hello *.o

.PHONY: all clean

Makefile variables

make allows for the definition and use of variables. Consider a Makefile that builds 3 source files hello.c, announce.c and yell.c. Here is our first version of the Makefile without the use of variables.

Makefile.5
# begins a comment till the end of the line
#
# makefile for siri


all: hello.o announce.o yell.o
	gcc -o siri hello.o announce.o yell.o

hello.o: hello.c
	gcc -c -Wall hello.c

announce.o: announce.c
	gcc -c -Wall announce.c

yell.o: yell.c
	gcc -c -Wall yell.c

clean:
	-rm *.o

.PHONY: all clean

We create variables with the syntax VAR_NAME=VAR_VALUE and we use a variable with the syntax $(VAR_NAME). Here is our Makefile refactored with variables.

Makefile.6
#
# makefile for siri
# use `#` to begin a comment till the end of the line


CC = gcc
CFLAGS = -c -Wall


all: hello.o announce.o yell.o
	$(CC) -o siri hello.o announce.o yell.o

hello.o: hello.c
	$(CC) $(CFLAGS) hello.c

announce.o: announce.c
	$(CC) $(CFLAGS) announce.c

yell.o: yell.c
	$(CC) $(CFLAGS) yell.c
clean:
	-rm *.o

.PHONY: all clean

The information in this lab should help you to get started with Makefiles. There are a lot more features to make and Makefiles, consult the make documentation that is part of your OS or online.