Makefiles are freqently used to compile code. This section will not go into detail on what steps are involved in compilation (nor does it assume any knowledge about code compilation), but rather explains how Makefiles can make compiling easier.
Often times when you’re working on a software project, your code is contained in more than one file. Let’s say we’re working on such a project and we have 3 files: “main.c,” “moreCode.c,” and “moreCode.h.” In order to run your project, you want to create an executable file by running this command:
This creates an executable called “a.out” which you’re able to run and all is
good. However, you want to tweak this command a bit by adding some flags to the
gcc
command and so you decide you actually want to run this command in order
to generate the executable (don’t worry about what these extra flags mean,
they’re beyond the scope of this course):
That’s quite a lot to type out everytime you want to compile your project, and it’s also inefficient if we end up recompiling something that hasn’t changed! This is the perfect example of where a Makefile would come in handy.
Let’s start the Makefile with a line indicating which shell to use and a line indicating which targets will be phony targets:
Next we’ll define some variables that will be useful in writing our rules:
Here CC
contains the name of the compiler and CCFLAGS
contains the flags we
want to use when we compile code. Now lets write some of the rules:
The first rule creates an executable “main” and depends on input files “main.o”
and “moreCode.o.” The recipe says, “use the variables we defined above (the
compiler name and the flags) to compile “main.o” and “moreCode.o” into an
executable called “main” (that’s what the -o
flag is for).” Notice that the
prerequisites for this rule are intermediate .o files that we don’t have!
Luckily the Makefile will figure out how to create these from the .c files
we’ve provided.
The second rule cleans up the output of running make
.
Now if we run make
, we get an executable called “main.” If we run it a second
time, we will see that
since we haven’t updated the code and so there is no need to recompile.
There is, however, an issue with our Makefile. We never told the Makefile that our code also depends on “moreCode.h.” Let’s add another rule to account for this:
This rule says that when creating a target ending in .o, the dependencies are
both the corresponding .c file and also “moreCode.h.” The recipe says, “using
the compiler and the flags that we’ve specified above, create the intermediate
.o file (this is what the -c
flag is for) from a .c file (the $<
indicates
the first prerequisite, which is the .c file), and give the .o file the name of
the target (this is what -o $@
is for).”
A couple of external tutorials were helpful in creating these pages. These links contain more info on using Makefiles for code compilation: