Makefiles

Makefiles#

We’ll look at GNU Make to manage building projects that are split across multiple files. Make allows us to specify rules for how to compile and link the code.

Note

A popular alternative to GNU Make is CMake.

We’ll use this to manage our planets + multiple files example.

A first GNUmakefile#

Here’s a basic makefile, which we’ll name GNUmakefile:

Listing 107 GNUmakefile#
# by default, make will try to build the first target it encounters.
# here we make up a dummy name "ALL" (note: this is not a special make
# name, it is just commonly used).

ALL: planet_sort_split

# explicitly list the rules for making each of the object files

planet_sort_split.o: planet_sort_split.cpp planet.H
	g++ -std=c++20 -c planet_sort_split.cpp

planet.o: planet.cpp planet.H
	g++ -std=c++20 -c planet.cpp

# explicitly write the rule for linking together the executable

planet_sort_split: planet_sort_split.o planet.o
	g++ -o planet_sort_split planet_sort_split.o planet.o

There are a few different types of lines, but the most important are the rules that are of the form:

target: dependencies ...
     commands
     ...

Important

make uses a tab character to indent the commands to be executed for each target, not spaces.

For example, the rule:

planet_sort_split.o: planet_sort_split.cpp planet.H
     g++ -std=c++20 -c planet_sort_split.cpp

says that planet_sort_split.o depends on the files planet_sort_split.cpp and planet.H. And the rule to make it is g++ -c planet_sort_split.cpp. By specifying the dependencies, make knows whether it needs to recompile a file by looking at whether its dependencies changed.

Tip

It is common to put a target called ALL at the top that depends on the executable you want to produce, since by default make will try to build the first target it encounters.

Using make#

We build the project by doing:

make

When you do this, you’ll see that it first builds the object files (in order that they were listed as dependencies) and then does the link step.

try it…

If you type make again, it doesn’t do anything, since none of the source files changed, so it does not need to update the build.

If you modify one file, e.g.,

touch planet.cpp

and then do make again:

make

Then it will only execute the rules that depend on the file that changed.