CS253: Software Development with C++

Spring 2023

Make

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.                 

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!                 

Makefiles 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                

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 24-hour late period for a 25% penalty.                 

How to receive negative points:                

Turn in someone else’s work.