Make Lab                
This lab concerns the make command. Around here, make and gmake
(the GNU version of make) are the same thing.
A video introduction is available.
                
Not about cmake                
In this class we tend to use cmake.
As you know, cmake reads a CMakeLists.txt
which describes
the project, and produces a Makefile
. We’re not going to discuss
cmake in this lab, rather, we’re going to talk about what goes
into a Makefile
and how it works.
                
How a Makefile
works                
Consider a program that has two source files, alpha.cc
and
main.cc
.
                
alpha.cc
: the C++ source file contains function alpha()
alpha.h
: the C++ header file with a declaration
for alpha()
, but no actual code.
main.cc
: the C++ source file that contains main()
.
main.cc
contains #include "alpha.h"
and uses the function
alpha()
.
alpha.o
: the compiled, machine-language version of alpha.cc
main.o
: the compiled, machine-language version of main.cc
prog
: the combination of alpha.o
, main.o
, and any
required library functions (cout, exit(), etc.).
We can show their dependencies like this:
                
alpha.cc ──> alpha.o ────┐
∧ │
│ │
│ │
alpha.h │
│ │
│ │
∨ ∨
main.cc ──> main.o ──> prog
The arrows represent dependencies. For example, alpha.o
depends on
alpha.cc
; if alpha.cc
changes, then alpha.o
is out-of-date,
and so we need to recompile alpha.cc
to create alpha.o
.
Similarly, if main.o
or alpha.o
change (probably from a
recompilation due to a C++ source file changing) then we need to
recreate prog
by linking together alpha.o
, main.o
, and any
required library symbols.
                
If alpha.h
changes, then we need to recompile both alpha.cc
and
main.cc
.
                
If this were all that there were to our project, we would just compile
all the *.cc
files every time, because computers are fast. However,
consider a large project, with hundreds of source files.
Compilation (.cc
⇒ .o
) is slow, whereas linking (merging several
*.o
into a single executable prog
) is fast. Therefore, it’s
worth the bother to keep the .o
files around and only recreate them
as necessary.
                
A Makefile
describes, textually, the diagram above. It reduces
those dependencies to rules, and gives commands for creating one
file from another. Here is a Makefile
fragment that would describe
the relationships shown above:
                
prog: main.o alpha.o
g++ -Wall main.o alpha.o -o prog
main.o: main.cc alpha.h
g++ -Wall -c main.cc
alpha.o: alpha.cc alpha.h
g++ -Wall -c alpha.cc
For example, the first rule, says that prog depends on main.o
and alpha.o
, and then gives the command that would (re-)create prog
from main.o
and alpha.o
. Of course, if those files don’t
yet exist, or are out of date, then see the rules for those files. It’s
recursive!
                
Makefile
s can also have variables, which get assigned:
                
FOO=whatever you want
To use them in a rule, use the variable name like this: $(FOO)
                
When you type the shell command make, it reads the Makefile
,
figures out what’s out of date, and executes the commands as needed.
Every file has a modification time associated with it, which make
inspects, so it knows which files are older than which other files.
                
Your task                
- Copy the directory
~cs253/Lab/Make
to a convenient place in your home directory.
- Follow the instructions in the
Makefile
.
How to submit your work:                
In Canvas, check in the
file
Makefile
to the assignment “Lab04”.
It’s due 11:59ᴘᴍ MT Saturday, with a five-day late period.
                
How to receive negative points:                
Turn in someone else’s work.