<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">\documentclass[onecolumn,letterpaper,11pt]{article}

%===================================================================
% Include common packages, environments, counters etc
\input{common_latex/common_latex_packages}
\input{common_latex/common_latex_lab_format}
\input{common_latex/common_latex_definitions}
%===================================================================

\begin{document}
\wikidoc{file=Lab.CPPBuild}
\wikidoc{auth=mikerb@mit.edu}

%===================================================================
% Build the Cover Page in an environment style easy for wiki parsing
\begin{labcover}
\labtitle{C++ Lab 07 - Introduction to C++ Build Systems}
\vspace{0.1in}
\labcourse{2.680 Unmanned Marine Vehicle Autonomy, Sensing and Communications}
\vspace{0.2in}
\labpng{0.775}{figures/tsl.png}
\vspace{0.3in}
\labdate{IAP 2024}
\vspace{0.1in}
\labauth{Michael Benjamin, mikerb@mit.edu}
\labauth{Department of Mechanical Engineering}
\labauth{MIT, Cambridge MA 02139}
\vspace{0.2in}
\labtoc{small}
\end{labcover}

%======================================================================
% Add a blank page so first body page is on the right when doubleside
\blankpage

%======================================================================
% Begin the body of the text

%======================================================================
\section{Lab Seven Overview and Objectives}
%======================================================================

We are at the point in our labs where our example programs are
contained in multiple source code files, all passed as arguments to
the \var{g++} compiler on the command line. If you're thinking that
{\em building} an executable this way is starting to get unwieldy, we
agree. And there are many tools and techniques out there to help
manage this, some very simple and some more complex and
sophisticated. The sophisticated tools generalize and in some cases
{\em use} the simple tools, so it's worth introducing the simple build
tools and concepts here and now. Partly because the message should
resonate now that you are starting to have non-trivial programs, and
partly to enable the exercises in later labs to remain simple and
clear. So before we dive further into more advanced C++ language
concepts, we push the pause button and discuss C++ build systems.

\pskip
\noindent
In this lab the following topics are covered.

\begin{labinfo}
\begin{packed_itemize}[2]
\item The Relationship between Compiling and Linking in the Build Process
\item Basic Source Code Project Management
\item The Construction of Archive Libraries for Holding Code Common to Multiple Apps
\item An Introduction to Makefiles to Simplify and Quicken the Build Process
\item A Discussion of Cross-Platform Build Tools such as CMake
\end{packed_itemize}
\end{labinfo}

%=======================================================================
\section{A First Discussion on Source Code File Management}
%=======================================================================

If you have been working through the exercises in all the prior labs, chances are
you have them all in one big directory, and your situation looks something like this:

\vspace{0.1in}
\begin{consoleverb}
 $ ls
 arrays.cpp             filein.cpp             rand_seglist.cpp         string_split.cpp
 arrays_nosmall.cpp     fileout.cpp            rand_vertices_class.cpp  string_split_v2.cpp
 BiteString.cpp         function_hellocap.cpp  rand_vertices.cpp        str_search.cpp
 BiteString.h           function_hellocmd.cpp  rand_vertices_file.cpp   vectors_nosmall.cpp
 cmd_args.cpp           function_hello.cpp     rand_vertices_seed.cpp   Vertex.cpp
 factorial_cmdargs.cpp  function_hellodef.cpp  rand_vertices_sleep.cpp  Vertex.h
 factorial.cpp          function_main.cpp      SegList.cpp              VertexSimple.cpp
 factorial_longint.cpp  function_sepdef.cpp    SegList.h                VertexSimple.h
 FileBuffer.cpp         function_sepdef.h      string_bite.cpp          vertices.txt
 FileBuffer.h           ParseString.cpp        string_deserial.cpp
 filebuff_main.cpp      ParseString.h          string_parse.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
Ideally the above "flat" structure would instead be organized more in line
with the order of the labs, and the top level view would look something like:

\vspace{0.1in}
\begin{consoleverb}
 $ ls
 lab01/     lab03/     lab05/
 lab02/     lab04/     lab06/
\end{consoleverb}
\vspace{0.1in}

\noindent
Perhaps the only thing stopping you from organizing it this way is that source 
code files like \var{Vertex.cpp} and \var{FileBuffer.cpp} are needed in multiple
labs and a little red flag popped up in your head that having multiple versions
of the same source code in different places is a bad idea (bravo to you if that
was the case). This is indeed a bad idea, and there are ways to handle this.

\pskip
\noindent
Our goal in this lab is to allow you to organize things like the geometry source
code (\var{Vertex.h/cpp} and \var{SegList.h/cpp}) into its own folder and the same
with the string parsing utilities, e.g. \var{ParseString.h/cpp}. These dedicated
utility folders will be called {\em libraries} and any number of apps or programs
can access them. The resulting structure will look something like:

\vspace{0.1in}
\begin{consoleverb}
 $ ls
 lab01/     lab03/     lab05/    lib_geometry/
 lab02/     lab04/     lab06/    lib_strings/
\end{consoleverb}
\vspace{0.1in}

%=======================================================================
\section{Digging a Bit Deeper into the Build Process}
%=======================================================================

The term {\em build process} here refers to the steps starting with
source code (a set of \var{.cpp} and \var{.h} files) ending with an
executable file representing your program. So far we have been
building from the command line where each argument is either a source
code file and another argument indicating the desired name of the
executable. For example: \cmd{g++ -o test main.cpp}. There are a few
steps going on under the hood in this process, but you could be
forgiven if you held a conceptual view of this process looking like:

\vspace{0.1in}
\begin{figure}[H]
  \centering 
  \includegraphics[width=0.45\textwidth]{figures/build_simple.png}
  \caption{A simplistic view of the build process.}
  \label{fig_build_simple}
\end{figure}
\vspace{0.1in}

\noindent
Here's another overly simplistic but more correct view that reveals an
intermediate stage prior to the creation of the executable, the
creation of object files:

\vspace{0.1in}
\begin{figure}[H]
  \centering 
  \includegraphics[width=0.75\textwidth]{figures/build_objects.png}
  \caption{A still simplistic but slightly more realistic view of the build process.}
  \label{fig_build_objects}
\end{figure}
\vspace{0.1in}


\noindent
The {\em linker} stitches together pieces of code that reference other
pieces of code. For example, one piece of source code can be compiled
that invokes the \var{biteString()} function found in another piece of
code. During the compilation, the compiler doesn't care that they live
separately, but during linking the pieces are linked together into a
single entitity, the executable. For now you can leave it at that, but
you may want to check this out further at the below URLs:

\vspace{0.1in}
\begin{packed_itemize}
 \item Read the section "1.4 GCC Compilation Process" found here: \newline
\urlx{https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html}

\item The whole page at this url: \newline
\item \urlx{http://mylinuxbook.com/basics-of-gcc-compilation-process-explained/}
\end{packed_itemize}
\vspace{0.1in}

\noindent
The multiple stages are done automatically when building as we have
been building, but they can be split up, and that is key for achieving
an efficient build. The below example illustrates simple case.

%======================================================================
\subsection{A Simple Example to Try}

As an example, the below is how we built the \var{string\_bite}
executable from the previous lab:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_bite BiteString.cpp string_bite.cpp
 $ ls
 BiteString.cpp string_bite.cpp string_bite*
\end{consoleverb}
\vspace{0.1in}

\noindent
If we wanted to, we could break this process up into first build the
object files and then link them as below. First the compiling into
object files. The \var{-c} command line switch tells \cmd{g++} to only
build the object files:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -c BiteString.cpp string_bite.cpp
 $ ls
 BiteString.cpp string_bite.cpp BiteString.o string_bite.o
\end{consoleverb}
\vspace{0.1in}

\noindent
Then the linking of the object files into an executable:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_bite BiteString.o string_bite.o
 $ ls
 BiteString.cpp string_bite.cpp   string_bite*
 BiteString.o   string_bite.o
\end{consoleverb}
\vspace{0.1in}


%======================================================================
\subsection{How to Make Frequent Builds Efficient During Development}

Here we begin to address the build process efficiency. In this case
we're not talking about the time it takes to do a fresh build (no
prior builds on this computer's recent history). Instead we're talking
about efficiency between successive builds during development. The
latter is something typically done many dozens or hundreds of times
during the course of software development. In this scenario, the
primary means for making the build process more efficient is to only
re-compile what needs to be re-compiled since the previous build.

\pskip
\noindent
The situation is depicted below. An executable is comprised of many
source code files. You're presently working on the code in one file.
When you go to re-build the executable, this one file is the only file
that has changed. The others have not. Yet if we continue to build
like we have been doing, ALL source code files are re-compiled anyway:

\vspace{0.1in}
\begin{figure}[H]
  \centering 
  \includegraphics[width=0.65\textwidth]{figures/build_many_one.png}
  \caption{A simplistic view of a program having many source code
    files. In this case we highlight the situation where ONE of those
    files has changed since the previous build. In building the naive
  brute-force way, ALL source code is recompiled, even those source
  code files that have not changed.}
  \label{fig_many_one}
\end{figure}
\vspace{0.1in}

\noindent
In our exercises where the number and size of source files is small, the
inefficiency isn't noticed. Before long, however, it will be noticable
and progressively more painful. Instead we strive for a situation like
that depicted below, where only the changed file is re-compiled:

\vspace{0.1in}
\begin{figure}[H]
  \centering 
  \includegraphics[width=0.65\textwidth]{figures/build_many_two.png}
  \caption{A simplistic view of a program having many source code
    files. Only one source file has changed since the last build. This
    is the only file re-compiled on the following build. The build
    otherwise uses the unchanged object files from the previous build,
    shortening the overall build time.}
  \label{fig_many_two}
\end{figure}
\vspace{0.1in}


%=======================================================================
\refstepcounter{exercise}
\label{ex_prepare}
\subsection{Exercise \ref{ex_prepare}: Prepare Your Code Files for a Reorganization}

As a preparation for later steps, we are going to re-organize the file structure
of code you have developed so far. If you have been doing all the exercises and
using the name suggestions, then the steps should pretty much match up exactly to
what we show below. 

\pskip
\noindent
First, make a copy of what you have done so far. Make a directory called \var{attic}
and {\em move} everything into there with your current file structure. After that, 
create the below new directories as shown:

\vspace{0.1in}
\begin{consoleverb}
 $ mkdir lab02  lab03  lab04  lab05  lab06 lib_geometry lib_strings 
 $ ls
 attic/     lab03/     lab05/    lib_geometry/   
 lab02/     lab04/     lab06/    lib_strings/
\end{consoleverb}
\vspace{0.1in}

\noindent
Each of these new directories, except for the \var{attic}, will be
initially empty, and the next step is to {\em copy} the source code in
the \var{attic} from each of the labs into the right directory. Here's
what it should look like if you followed the naming suggestions from
the exercises.

\vspace{0.1in}
\begin{consoleverb}
 $ cd attic

 $ cp factorial.cpp factorial_longint.cpp factorial_cmdargs.cpp str_search.cpp ../lab02 
 $ cp function_* ../lab03
 $ cp arrays*.cpp fileout.cpp filein.cpp vectors_nosmall.cpp filebuff_main.cpp ../lab04
 $ cp rand_vertices* rand_seglist* ../lab05
 $ cp string_*.cpp ../lab06
 $ cp FileBuffer* BiteString* ParseString* ../lib_strings
 $ cp Vertex* SegList* ../lib_geometry
\end{consoleverb}
\vspace{0.1in}

\noindent
Afterwards, in the top level of your directory, invoking \var{ls *}
should produce something like that shown in the solution for this
exercise shown in Section \ref{sol_prepare}.

\vspace{0.1in}

%=======================================================================
\section{Building a Program with Source Code Across Different Directories}
%=======================================================================

After organizing your code as per the previous exercise, the next
question is how can this code be built now that all the source code
files are not in the same directory. We'll use the code from the
previous lab in our examples below. All this code should now be in the
\var{lab06} directory. In this lab, the \var{string\_bite} executable
{\em was} built from the command line with:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_bite BiteString.cpp string_bite.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
This will no longer work from within the \var{lab06} directory since
\var{BiteString.cpp} is not in that directory. It now resides in
\var{lib\_strings}. We could alter our build command with:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_bite ../lib_strings/BiteString.cpp string_bite.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
This would almost work, but the build will still fail because, inside
\var{string\_bite.cpp} there is this line of code (a pre-processor
directive):

\vspace{0.1in}
\begin{fileverb}
 #include "BiteString.h"
\end{fileverb}
\vspace{0.1in}

\noindent
It may be tempting to fix this by changing the line of code to:

\vspace{0.1in}
\begin{fileverb}
 #include "../lib_string/BiteString.h"
\end{fileverb}
\vspace{0.1in}

\noindent
This is almost always a bad idea. It makes the source code in \var{bite\_string.cpp}
brittle. If the location of the string library is ever moved or renamed, the code
no longer works. A better solution is to simply tell the \cmd{g++} compiler, on
the command line, where it should look for any files being include with the 
\var{\#include} directive. This is done with the \var{-I} command line argument
as follows:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_bite -I../lib_strings ../lib_strings/BiteString.cpp string_bite.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
Now \var{string\_bite} should compile successfully as above. Naming a
directory with the \var{-I} argument is referred to as setting your
"include path".  If your code needs to \var{\#include} code from
multiple places, the argument may be used multiple times on the 
command line. For example, the following is how \var{string\_deserial}
is now built with the new file structure. It needs to \var{\#include}
code from two different directories:

\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_deserial -I../lib_geometry -I../lib_strings   \
 ../lib_geometry/Vertex.cpp ../lib_strings/FileBuffer.cpp      \
 ../lib_strings/BiteString.cpp ../lib_strings/ParseString.cpp  \
 string_deserial.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
The above build command solves the \var{\#include} path problem, but it
is still unwieldy. It {\em seems} like we should be able to get rid of
the \var{../lib\_geometry} part of \var{../lib\_geometry/Vertex.cpp}
by just specifying another {\em path} indicating where to look for
source code files, in the spirit of how the \var{-I} argument works.
There is indeed this option (the \var{-L} command line option), but it
works with {\em archived object files}. So our next discussion is how
these are made. The vast majority of non-trivial C++ objects in the
world do things in this way, so it's worth discussing and start doing
things this way.

\pskip
\noindent
{\bf NOTE:} One final comment on the issue of the \var{\#include}
path. Notice that in earlier labs we have been including files like:

\vspace{0.1in}
\begin{fileverb}
 #include &lt;iostream&gt;
 #include &lt;cstdio&gt;
\end{fileverb}
\vspace{0.1in}

\noindent
And we have not needed to have any \var{-I} entries in our invocations of
\cmd{g++}, but somehow these included files have been found. In C++ a few
conventional locations are automatically part of the include path. These
directories are usually "system" directories (accessible to all users). On
your machine they are likely found in \var{/usr/include} or in one of the
subdirectories like \var{/usr/include/c++/4.2.1/} like on my machine.



%\begin{consoleverb}
% $ g++ -o string_deserial  -I../lib_geometry -I../lib_strings   \
% -L../lib_geomerty -L../lib_strings  -lstrings -lgeometry string_deserial.cpp
%\end{consoleverb}




%=======================================================================
\section{Creating a Library Archive of C++ Utility Source Code}
%=======================================================================

An {\em archive} in C/C++ is a file that bundles a set of object files
into a single file. This file almost always follows the naming
convention of starting with \var{lib} and ending with \var{.a}, e.g.,
\var{libstrings.a} and \var{libgeometry.a} in our two library
examples. An archive file can be build from object files using the
\cmd{ar} command:

\vspace{0.1in}
\begin{consoleverb}
 $ ar cr libarchive.a file1.o file2.o ... fileN.o 
\end{consoleverb}
\vspace{0.1in}

\noindent
The \cmd{ar} command has several optional arguments. We use the two options 
\cmd{cr} here. You can find out what these mean by typing \cmd{man ar} on
the command line to see the manual page for the \cmd{ar} command.
\vspace{0.1in}


%=======================================================================
\refstepcounter{exercise}
\label{ex_archive}
\subsection{Exercise \ref{ex_archive}: Generation of Archive Files with a Script}

In each of your two library folders \var{lib\_geometry} and \var{lib\_strings}, 
build a short script to generate an archive file in each folder. The archive
names should be \var{libgeometry.a} and \var{libstrings.a} respectively. The
script will have two lines, one for generating the object files, and one for
generating the archive file.

\pskip
\noindent
We haven't discussed scripts in our labs so far, and there are several
ways to write scripts and invoke them from the command line (bash
scripts, perl scripts, python scripts to name a few). The simplest
kind of script shouldn't be overlooked - a raw text file. Suppose you
have a text file, named \var{test} for example, with the following few
lines:

\vspace{0.1in}
\begin{fileverb}
 ls 
 mkdir one
 ls
\end{fileverb}
\vspace{0.1in}

\noindent
You can then "execute" this script using the \cmd{source} command as follows:

\vspace{0.1in}
\begin{consoleverb}
 $ source test
\end{consoleverb}
\vspace{0.1in}

\noindent
It's as if you just typed these three commands on the command
line. So, to make things easier for you, and to have a "deliverable"
for this exercise, you should create a (raw text) script file in both
the \var{lib\_geometry} and \var{lib\_strings} directory, and name the
files simply \var{"build"} in both directories.  Each file should have
the two lines:

\vspace{0.1in}
\begin{fileverb}
 g++ ... (you fill this in)
 ar  ...
\end{fileverb}
\vspace{0.1in}

\noindent
You can even add a few lines beginning with \cmd{echo}, another
command line utility that just echoes its arguments. For example, try
adding \var{"echo Done!"}  to be the last line of your script.

\pskip
\noindent
You should be able to invoke your scripts from the command line with 
the following results, first for the geometry library:

\vspace{0.1in}
\begin{consoleverb}
 $ cd lib_geometry
 $ source build
 $ ls
 SegList.cpp       Vertex.cpp        VertexSimple.cpp    build
 SegList.h         Vertex.h          VertexSimple.h      libgeometry.a
 SegList.o         Vertex.o          VertexSimple.o
\end{consoleverb}
\vspace{0.1in}

\noindent
And then for the strings library:

\vspace{0.1in}
\begin{consoleverb}
 $ cd lib_strings
 $ source build
 $ ls
 BiteString.cpp   FileBuffer.cpp   ParseString.cpp  build
 BiteString.h     FileBuffer.h     ParseString.h    libstrings.a
 BiteString.o     FileBuffer.o     ParseString.o    
\end{consoleverb}
\vspace{0.1in}

\noindent
The solution to this exercise is in Section \ref{sol_archive}.
%-------------------------------------------+


%===================================================================
\subsection{Linking to Archive Files in Building an Executable}

Once the archive files have been created, linking against them is fairly
easy. The \cmd{-L} argument to \cmd{g++} names a directory to look for 
archive files. The \cmd{-l} argument names an actual archive file to 
link to. The first example below shows what the compile command would look
like without the use of an archive:


\vspace{0.1in}
\begin{consoleverb}
 $ g++ -o string_deserial -I../lib_geometry -I../lib_strings   \ 
 ../lib_geometry/Vertex.cpp ../lib_strings/FileBuffer.cpp      \ 
 ../lib_strings/BiteString.cpp ../lib_strings/ParseString.cpp  \
 string_deserial.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
The below command shows the equivalent build, using the archive and 
the \cmd{-L} and \cmd{-l} commands.

\vspace{0.1in}
\begin{consoleverb}
 $ g++   string_deserial.cpp -o string_deserial -I../lib_geometry \
-I../lib_strings -L../lib_geometry -L../lib_strings -lstrings -lgeometry 
\end{consoleverb}
\vspace{0.1in}

\noindent
Notice that, for the \cmd{-l} option, there is no space between the
switch \cmd{-l} and the name of the archive, as in
\cmd{-lstrings}. Also note that an argument such as \cmd{-lfoobar} is
seeking a library archive file named \var{libfoobar.a}. The \var{lib}
and \var{.a} are thus filename conventions used for all static archive
files.

\vspace{0.1in}
\noindent
Note also that we put the \var{string\_deserial.cpp} argument
first. In general, the order of arguments does not matter. In
MacOS/Clang order does not matter. In some Linux distributions and
versions of \cmd{g++}, order may matter and the above is most likely
to work.

%=======================================================================
\refstepcounter{exercise}
\label{ex_buildapps}
\subsection{Exercise \ref{ex_buildapps}: Building a Set of Executables with a Script}

In the previous exercise we created simple script files for building
the archive files for our two libraries \var{lib\_strings} and
\var{lib\_geometry}. We named both files \var{build}. In this exercise
we will generate a build file for all executables in lab 06, for all five
executables in that lab: 

\begin{packed_itemize}
 \item \var{string\_split}
 \item \var{string\_split\_v2}
 \item \var{string\_bite}
 \item \var{string\_parse}
 \item \var{string\_deserial}
\end{packed_itemize}

\noindent
Your \var{build} file should have one line for each executable and use
the \var{-I} include path, \var{-L} link path, and archive files already
generated in the library directories. 

\pskip
\noindent
You should be able to invoke your script from the command line with 
the following results:

\vspace{0.1in}
\begin{consoleverb}
 $ cd lab06
 $ source build
 $ ls
 build                string_deserial*     string_parse.cpp     string_split_v2*
 string_bite*         string_deserial.cpp  string_split*        string_split_v2.cpp
 string_bite.cpp      string_parse*        string_split.cpp
\end{consoleverb}

\vspace{0.12in}
\noindent
The solution to this exercise is in Section \ref{sol_buildapps}.
%-------------------------------------------+



%===================================================================
\section{Using Makefiles and GNU Make for Building Projects}
%===================================================================

So far in this lab we have successfully: 

\vspace{0.04in}
\begin{packed_itemize}
 \item Moved away from a flat source code structure with all files in
   the same folder. 
 \item Learned how to create utility libraries (archives) so source
   code common to multiple applications doesn't have to be duplicated
   in each application.
 \item Learned how to build an application with compiler directives to 
   look for header files and archives in folders other than the current
   folder.
\end{packed_itemize}
\vspace{0.04in}

\noindent
Build speed and efficiency aside, things are starting to feel more
organized. We also have introduced some build efficiency too since
presumably those library archives don't need to be re-built if they're
not being changed and our iterative work is in the application code.
The problem is, sometimes that library code is indeed being
changed. When an application links to a library it is a {\em
  dependency}. All the non-library source code for an app are also
dependencies. If {\em any} dependency has been modified between
builds, that dependency needs to be re-compiled. Keeping track of what
files have changed and need re-building can be daunting, and many an
apparent bug has been found to be the result of failing to re-compile
a dependency. So far in previous labs, we have side-stepped this
problem by re-building everything, all the time (all source code and
all dependencies) on each build, whether a file needs re-building or
not. Simple, but not scalable unless you like working slow.

\pskip
\noindent
This is where the GNU 'make' utility comes in.  The GNU 'make' utility
automatically determines which pieces of a large program need to be
recompiled, and issues commands to recompile them. This utility is
very well documented on the GNU website and we ask that you read the
first two sections (Sections 1 and 2, 10 short pages) of the manual
now before proceeding.

\begin{packed_itemize}
\item \urlx{https://www.gnu.org/software/make/manual/}
\end{packed_itemize}

\noindent
If you'd like to have this material available off line, you can get
the whole manual either in raw text or PDF format using \cmd{wget}:

\vspace{0.08in}
\begin{consoleverb}
 $ wget https://www.gnu.org/software/make/manual/make.txt
 $ wget https://www.gnu.org/software/make/manual/make.pdf
\end{consoleverb}
\vspace{0.08in}

\noindent
From the GNU Make manual we see a Makefile is comprised of a series of
{\em rules}:

\vspace{0.08in}
\begin{fileverb}
target ... : prerequisites ...
        recipe
        ...
\end{fileverb}
\vspace{0.08in}

\noindent
As a simple example, we can replace each line in the \var{build} file
created in Exercise \ref{ex_buildapps} with a line like:

\vspace{0.08in}
\begin{fileverb}
string_bite : 
      g++ -I../lib_strings -L../lib_strings -lstrings -o string_bite string_bite.cpp
\end{fileverb}
\vspace{0.08in}

\noindent
This works, but has the drawback that if any of the dependencies of
the \var{string\_bite} executable are modified, a subsequent
\cmd{make} invocation wouldn't know do anything. So we add the
dependencies to the prerequisites part of the rule:

\vspace{0.08in}
\begin{fileverb}
string_bite : ../lib_strings/libstrings.a string_bite.cpp
      g++ -I../lib_strings -L../lib_strings -o string_bite string_bite.cpp -lstrings 
\end{fileverb}
\vspace{0.08in}

\noindent
Now if \var{libstrings.a} or \var{string\_bite.cpp} have been modified more
recently than the timestamp on the \var{string\_bite} executable, \cmd{make}
will re-execute this rule.

\vspace{0.1in}

%=======================================================================
\refstepcounter{exercise}
\label{ex_makedumb}
\subsection{Exercise \ref{ex_makedumb}: Replacing our Build Script with a Simple Makefile}

Replace the \var{build} script created in Exercise \ref{ex_buildapps}
with a \var{Makefile} containing a rule for each of the five
executables. It should contain a first rule, \var{all}, that
ensures that all five executables are built when the user simply types
\cmd{make} in the lab06 directory. It should also contain a rule, \var{clean}, 
that removes all executables. For now, the rules corresponding to 
executables can be super-simple, having no prerequisites along the lines
of the \var{string\_bite} example above. While simple, it has serious
drawbacks that we will improve on in the next exercise.

\pskip
\noindent
The Makefile should of course be in a file called \var{Makefile}. If
this filename is used, \cmd{make} will automatically use it and the
filename doesn't have to be passed in as an argument to
\cmd{make}. FYI, if the lowercase \var{makefile} name is used instead,
this also works, but the uppercase version takes precedent if both
exist. Your \var{Makefile} with the seven rules discussed above should
support the below command line invocations:

\vspace{0.08in}
\begin{consoleverb}
 $ make                       // Builds everything (the "all" rule)
 $ make string_split          // Builds just the string_split executable
 $ make string_split_v2       // Builds just the string_split_v2 executable
 $ make string_bite           // Builds just the string_bite executable
 $ make string_parse          // Builds just the string_parse executable
 $ make string_deserial       // Builds just the string_deserial executable
 $ make clean
\end{consoleverb}
\vspace{0.08in}

\noindent
The first time \cmd{make} is run, you will likely see every line of every 
recipe in every rule echoed on the screen like:

\vspace{0.08in}
\begin{consoleverb}
 $ make
 g++ -o string_split string_split.cpp
 g++ -o string_split_v2 string_split_v2.cpp
 g++ -I../lib_strings -L../lib_strings -lstrings -o string_bite string_bite.cpp
 g++ -I../lib_strings -L../lib_strings -lstrings -o string_parse string_parse.cpp
 g++ -I../lib_geometry -I../lib_strings -L../lib_strings -L../lib_geometry \
      -lgeometry -lstrings -o string_deserial string_deserial.cpp
\end{consoleverb}
\vspace{0.08in}

\noindent
If \cmd{make} is invoked immediately again, all executables have already
been made and you may see a message like:

\vspace{0.08in}
\begin{consoleverb}
 $ make
 make: Nothing to be done for `all'.
\end{consoleverb}
\vspace{0.08in}

\noindent
The solution to this exercise is in Section \ref{sol_makedumb}.
%-------------------------------------------+


%===================================================================
\subsection{Connecting the Makefiles - Building a Top-Level Makefile}

The \var{Makefile} produced in Exercise \ref{ex_makedumb} only
concerns the source code for Lab 06. However, note that one of the
rules contains a prerequisite that references an archive file in the
\var{lib\_strings} directory:

\vspace{0.08in}
\begin{fileverb}
string_bite : ../lib_strings/libstrings.a string_bite.cpp
      g++ -I../lib_strings -L../lib_strings -o string_bite string_bite.cpp -lstrings 
\end{fileverb}
\vspace{0.08in}

\noindent
This implies that the \var{libstrings.a} prerequisite will have had a
chance to be built or updated prior to this \var{Makefile}
execution. Presumably if you had a \var{Makefile} in each subdirectory, 
you could proceed in this manner:

\vspace{0.1in}
\begin{consoleverb}
 $ cd lib_strings
 $ make
 $ cd ..
 $ cd lib_geometry
 $ make 
 $ cd ..
 ...
 $ cd lab06
 $ make
 $ cd ..
\end{consoleverb}
\vspace{0.1in}

\noindent
This would work, but as you can see it would be tedious to manually do this
each time source code as changed. As we mentioned before, there are lots of
choices for scripting such tasks, and you can add \cmd{make} to that list. 
The notion of a "top-level" \var{Makefile} is common and described here:

\vspace{0.05in}
\begin{packed_itemize}
 \item \urlx{https://www.gnu.org/software/make/manual/html_node/Recursion.html}
\end{packed_itemize}
\vspace{0.05in}


%=======================================================================
\refstepcounter{exercise}
\label{ex_topmake}
\subsection{Exercise \ref{ex_topmake}: A Full Set of Makefiles with a Top-Level Makefile}

In this exercise we will round out our build system for the full set
of directories constituting our labs so far, up through Lab 06. We
will need to create:

\vspace{0.05in}
\begin{packed_itemize}
 \item A top-level \var{Makefile} in the lab root directory
 \item A \var{Makefile} for the two libraries, \var{lib\_geometry} and \var{lib\_strings}
 \item A \var{Makefile} for the five lab directories, \var{lab02}, ... \var{lab05}.
\end{packed_itemize}
\vspace{0.05in}

\noindent
Verify that everything works by trying the few following steps:

\vspace{0.1in}
\noindent
First, at the top level after typing the following you should see something like:

\vspace{0.1in}
\begin{consoleverb}
 $ make
 make -C lib_geometry
 g++ -c Vertex.cpp VertexSimple.cpp SegList.cpp
 ar cr libgeometry.a Vertex.o VertexSimple.o SegList.o
 make -C lib_strings
 g++ -c BiteString.cpp FileBuffer.cpp ParseString.cpp
 ar cr libstrings.a BiteString.o FileBuffer.o ParseString.o
 make -C lab02
 g++ -o factorial factorial.cpp
 g++ -o factorial_cmdargs factorial_cmdargs.cpp
 g++ -o factorial_longint factorial_longint.cpp
 g++ -o str_search str_search.cpp
 make -C lab03
 g++ -o function_hello function_hello.cpp
 g++ -o function_hellocap function_hellocap.cpp
 g++ -o function_hellocmd function_hellocmd.cpp
 g++ -o function_sepdef function_sepdef.cpp function_main.cpp 
 ...
\end{consoleverb}
\vspace{0.1in}

\noindent
Next, after the initial full \cmd{make}, a subsequent call to \cmd{make}
should result in the following:

\vspace{0.1in}
\begin{consoleverb}
 $ make
 make -C lib_geometry
 make[1]: `libgeometry.a' is up to date.
 make -C lib_strings
 make[1]: `libstrings.a' is up to date.
 make -C lab02
 make[1]: Nothing to be done for `all'.
 make -C lab03
 make[1]: Nothing to be done for `all'.
 make -C lab04
 make[1]: Nothing to be done for `all'.
 make -C lab05
 make[1]: Nothing to be done for `all'.
 make -C lab06
 make[1]: Nothing to be done for `all'.
\end{consoleverb}
\vspace{0.1in}

\noindent
Lastly, try "touching" a file in the \var{lib\_strings} directory, and
seeing how \cmd{make} reacts. (The \cmd{touch} command simply updates
the timestamp for a named file. In effect it tricks \cmd{make} into
regarding the file as having just been edited). After the \cmd{touch}, you
should see something like:

\vspace{0.1in}
\begin{consoleverb}
 $ touch lib_strings/ParseString.h
 $ make
 make -C lib_geometry
 make[1]: `libgeometry.a' is up to date.
 make -C lib_strings
 g++ -c BiteString.cpp FileBuffer.cpp ParseString.cpp
 ar cr libstrings.a BiteString.o FileBuffer.o ParseString.o
 make -C lab02
 make[1]: Nothing to be done for `all'.
 make -C lab03
 make[1]: Nothing to be done for `all'.
 make -C lab04
 g++ -I../lib_strings -L../lib_strings -lstrings -o filebuff filebuff_main.cpp
 make -C lab05
 make[1]: Nothing to be done for `all'.
 make -C lab06
 g++ -I../lib_strings -L../lib_strings -lstrings -o string_bite string_bite.cpp
 g++ -I../lib_strings -L../lib_strings -lstrings -o string_parse string_parse.cpp
 g++ -I../lib_geometry -I../lib_strings -L../lib_strings -L../lib_geometry \
 	-lgeometry -lstrings -o string_deserial string_deserial.cpp
\end{consoleverb}
\vspace{0.1in}

\noindent
Note that only the targets that had \var{ParseString.h} as a dependency were
re-built. Very efficient! Pat yourself on the back!

\pskip
\noindent
You can now safely just type \var{make} in the top-level directory as 
you continue coding and adding to this project. In fact, if you haven't 
yet learned about shell {\em aliases}, this is a good time to do so, and 
make yourself a build alias along the lines of:

\vspace{0.1in}
\begin{fileverb}
 alias mm  'cd ~/my_cpp_files/; make; cd -'
\end{fileverb}
\vspace{0.1in}

\noindent
I chose \var{"mm"} here only as an example. But in this case you could type \var{"mm"}
in any terminal window on your screen and your whole project would be (re-) built, with 
only the required steps given current edits. Very nice indeed. For more on aliases, 
see \urlx{http://oceanai.mit.edu/ivpman/help/cmdline_aliases}.


%===================================================================
\newpage
\section{Solutions to Exercises}
%===================================================================

%===================================================================
\subsection{Solution to Exercise \ref{ex_prepare}}
\label{sol_prepare}

\noindent
After the file structure re-org, in the top level of your directory,
invoking \var{ls *} should produce something like:

\vspace{0.1in}
\begin{consoleverb}
 $ ls *
 attic:
 BiteString.cpp         VertexSimple.cpp         function_hello.cpp       rand_vertices_file.cpp
 BiteString.h           VertexSimple.h           function_hellocap.cpp    rand_vertices_seed.cpp
 FileBuffer.cpp         arrays.cpp               function_hellocmd.cpp    rand_vertices_sleep.cpp
 FileBuffer.h           arrays_nosmall.cpp       function_hellodef.cpp    str_search.cpp
 ParseString.cpp        factorial.cpp            function_main.cpp        string_bite.cpp
 ParseString.h          factorial_cmdargs.cpp    function_sepdef.cpp      string_deserial.cpp
 SegList.cpp            factorial_longint.cpp    function_sepdef.h        string_parse.cpp
 SegList.h              filebuff_main.cpp        rand_seglist.cpp         string_split.cpp
 Vertex.cpp             filein.cpp               rand_vertices.cpp        string_split_v2.cpp
 Vertex.h               fileout.cpp              rand_vertices_class.cpp  vectors_nosmall.cpp

 lab02:
 factorial.cpp          factorial_cmdargs.cpp    factorial_longint.cpp    str_search.cpp

 lab03:
 function_hello.cpp     function_hellocmd.cpp    function_main.cpp        function_sepdef.h
 function_hellocap.cpp  function_hellodef.cpp    function_sepdef.cpp

 lab04:
 arrays.cpp             filebuff_main.cpp        fileout.cpp
 arrays_nosmall.cpp     filein.cpp               vectors_nosmall.cpp

 lab05:
 rand_seglist.cpp       rand_vertices_class.cpp  rand_vertices_seed.cpp
 rand_vertices.cpp      rand_vertices_file.cpp   rand_vertices_sleep.cpp

 lab06:
 string_bite.cpp        string_parse.cpp         string_split_v2.cpp
 string_deserial.cpp    string_split.cpp

 lib_geometry:
 SegList.cpp            Vertex.cpp               VertexSimple.cpp
 SegList.h              Vertex.h                 VertexSimple.h

 lib_strings:
 BiteString.cpp         FileBuffer.cpp           ParseString.cpp
 BiteString.h           FileBuffer.h             ParseString.h
\end{consoleverb}


%===================================================================
\newpage
\subsection{Solution to Exercise \ref{ex_archive}}
\label{sol_archive}

\vspace{0.1in}
\noindent
{\bf The lib\_strings build file:}

\begin{fileverb}
 g++ -c FileBuffer.cpp BiteString.cpp ParseString.cpp
 ar cr libstrings.a FileBuffer.o BiteString.o ParseString.o
 echo Done!
\end{fileverb}

\vspace{0.1in}
\noindent
{\bf The lib\_geometry build file:}

\begin{fileverb}
 g++ -c Vertex.cpp VertexSimple.cpp SegList.cpp
 ar cr libgeometry.a Vertex.o VertexSimple.o SegList.o
 echo Done!
\end{fileverb}

%===================================================================
\subsection{Solution to Exercise \ref{ex_buildapps}}
\label{sol_buildapps}

\vspace{0.1in}
\noindent
{\bf The lab06 build file:}

\begin{fileverb}
 g++ -o string_split string_split.cpp
 echo DONE compiling Exercise 01

 g++ -o string_split_v2 string_split_v2.cpp
 echo DONE compiling Exercise 01V2

 g++ -I../lib_strings -L../lib_strings -o string_bite string_bite.cpp -lstrings 
 echo DONE compiling Exercise 02

 g++ -I../lib_strings -L../lib_strings -o string_parse string_parse.cpp -lstrings 
 echo DONE compiling Exercise 03

 g++ -I../lib_geometry -I../lib_strings -L../lib_strings -L../lib_geometry \
 -lgeometry -lstrings -o string_deserial string_deserial.cpp
 echo DONE compiling Exercise 04
\end{fileverb}
\vspace{0.1in}

\noindent
The \cmd{echo} lines are optional. The order of the command line args is also
optional in most cases.


%===================================================================
\newpage
\subsection{Solution to Exercise \ref{ex_makedumb}}
\label{sol_makedumb}

\vspace{0.1in}
\noindent
{\bf A simple lab06 Makefile}: Compare the below \var{MakefileSimple}
with the buildfile script from previous exercise. This accomplishes
essentially the same thing.  Notice that each \var{MakefileSimple}
rule has no prerequisites (dependencies). After \cmd{make} has been
invoked once on this file (\cmd{make -f MakefileSimple}), subsequent
invocations will do nothing unless the executable has been deleted. It
will not detect that a re-compile is necessary after a source code
edit. Just like our simple build script, it is oblivious to changes in
source code. This can be improved by adding the appropriate
dependencies in the second \var{Makefile} example below.


\begin{fileverb}
# MakefileSimple for Lab06 (Ten Short C++ Labs)    
# wget http://oceanai.mit.edu/cpplabs/lab06/MakefileSimple
# Run: make -f MakefileSimple  

all: string_split string_split_v2 string_bite string_parse string_deserial

string_split :
        g++ -o string_split string_split.cpp

string_split_v2
        g++ -o string_split_v2 string_split_v2.cpp

string_bite : 
        g++ -I../lib_strings -L../lib_strings -lstrings -o string_bite string_bite.cpp

string_parse: 
        g++ -I../lib_strings -L../lib_strings -lstrings -o string_parse string_parse.cpp

string_deserial: 
        g++ -I../lib_geometry -I../lib_strings -L../lib_strings -L../lib_geometry \
        -lgeometry -lstrings -o string_deserial string_deserial.cpp

clean:
        rm -f string_split string_split_v2 string_bite string_parse string_deserial *~
\end{fileverb}
\vspace{0.1in}

\vspace{0.1in}
\noindent
{\bf A Better lab06 Makefile (with Dependencies):}

\begin{fileverb}
# Makefile for Lab06 (Ten Short C++ Labs)    
# wget http://oceanai.mit.edu/cpplabs/lab06/Makefile  

all: string_split string_split_v2 string_bite string_parse string_deserial

string_split : string_split.cpp
        g++ -o string_split string_split.cpp

string_split_v2 : string_split_v2.cpp
        g++ -o string_split_v2 string_split_v2.cpp

string_bite : ../lib_strings/libstrings.a string_bite.cpp
        g++ -I../lib_strings -L../lib_strings -lstrings -o string_bite string_bite.cpp

string_parse: ../lib_strings/libstrings.a string_parse.cpp
        g++ -I../lib_strings -L../lib_strings -lstrings -o string_parse string_parse.cpp

string_deserial: ../lib_strings/libstrings.a ../lib_geometry/libgeometry.a string_deserial.cpp
        g++ -I../lib_geometry -I../lib_strings -L../lib_strings -L../lib_geometry \
        -lgeometry -lstrings -o string_deserial string_deserial.cpp

clean:
        rm -f string_split string_split_v2 string_bite string_parse string_deserial *~
\end{fileverb}
\vspace{0.1in}

%===================================================================
\newpage
\subsection{Solution to Exercise \ref{ex_topmake}}
\label{sol_topmake}

\begin{fileverb}
# Top-Level Make Directory for programs through Lab 06                                                    
# wget http://oceanai.mit.edu/cpplabs/Makefile                                                            

all:
       make -C lib_geometry
       make -C lib_strings
       make -C lab02
       make -C lab03
       make -C lab04
       make -C lab05
       make -C lab06

clean:
       make -C lib_geometry clean
       make -C lib_strings clean
       make -C lab02 clean
       make -C lab03 clean
       make -C lab04 clean
       make -C lab05 clean
       make -C lab06 clean
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for lib_geometry (Ten Short C++ Labs)                                                          
# wget http://oceanai.mit.edu/cpplabs/lib_geometry/Makefile                                               

libgeometry.a : Vertex.cpp Vertex.h VertexSimple.cpp VertexSimple.h SegList.cpp SegList.h
        g++ -c Vertex.cpp VertexSimple.cpp SegList.cpp
	ar cr libgeometry.a Vertex.o VertexSimple.o SegList.o

clean:
	rm -f Vertex.o VertexSimple.o SegList.o libgeometry.a *~
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for lib_strings (Ten Short C++ Labs)                                                           
# wget http://oceanai.mit.edu/cpplabs/lib_strings/Makefile                                                

libstrings.a : BiteString.cpp BiteString.h FileBuffer.cpp FileBuffer.h ParseString.cpp ParseString.h
        g++ -c BiteString.cpp FileBuffer.cpp ParseString.cpp
	ar cr libstrings.a BiteString.o FileBuffer.o ParseString.o

clean:
	rm -f BiteString.o FileBuffer.o ParseString.o libstrings.a *~
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for Lab 02 (Ten short C++ Labs)                                                                
# wget http://oceanai.mit.edu/cpplabs/lab02/Makefile                                                      

all: factorial factorial_cmdargs factorial_longint str_search

factorial: factorial.cpp
        g++ -o factorial factorial.cpp

factorial_cmdargs: factorial_cmdargs.cpp
        g++ -o factorial_cmdargs factorial_cmdargs.cpp

factorial_longint: factorial_longint.cpp
        g++ -o factorial_longint factorial_longint.cpp

str_search: str_search.cpp
	g++ -o str_search str_search.cpp

clean:
      	rm -f factorial factorial_cmdargs factorial_longint str_search *~
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for Lab03 (Ten Short C++ Labs)                                                                 
# wget http://oceanai.mit.edu/cpplabs/lab03/MakeFile                                                      

all: function_hello function_hellocap function_hellocmd function_sepdef

function_hello: function_hello.cpp
	g++ -o function_hello function_hello.cpp

function_hellocap: function_hellocap.cpp
	g++ -o function_hellocap function_hellocap.cpp

function_hellocmd: function_hellocmd.cpp
	g++ -o function_hellocmd function_hellocmd.cpp

function_sepdef: function_sepdef.h function_sepdef.cpp function_main.cpp
	g++ -o function_sepdef function_sepdef.cpp function_main.cpp

clean:
      	rm -f function_hello function_hellocap function_hellocmd
	rm -f function_sepdef *~
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for Lab 04 (Ten short C++ Labs)                                                                
# wget http://oceanai.mit.edu/cpplabs/lab04/Makefile                                                      

all: arrays arrays_nosmall filein fileout vectors_nosmall filebuff

arrays: arrays.cpp
	g++ -o arrays arrays.cpp

arrays_nosmall: arrays_nosmall.cpp
	g++ -o arrays_nosmall arrays_nosmall.cpp

fileout: fileout.cpp
	g++ -o fileout fileout.cpp

filein: filein.cpp
	g++ -o filein filein.cpp

vectors_nosmall: vectors_nosmall.cpp
      	g++ -o vectors_nosmall vectors_nosmall.cpp

filebuff: filebuff_main.cpp ../lib_strings/libstrings.a
	g++ -I../lib_strings -L../lib_strings -lstrings -o filebuff filebuff_main.cpp

clean:
      	rm -f arrays arrays_nosmall fileout filein vectors_nosmall filebuff *~
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for Lab 05 (Ten short C++ Labs)                                                                
# wget http://oceanai.mit.edu/cpplabs/lab05/Makefile                                                      

all: rand_vertices rand_vertices_file rand_vertices_class rand_seglist \
	rand_vertices_sleep rand_vertices_seed

rand_vertices: rand_vertices.cpp
	g++ -o rand_vertices  rand_vertices.cpp

rand_vertices_file: rand_vertices_file.cpp
	g++ -o rand_vertices_file  rand_vertices_file.cpp

rand_vertices_class: ../lib_geometry/libgeometry.a rand_vertices_class.cpp
	g++ -I../lib_geometry -L../lib_geometry -lgeometry -o rand_vertices_class  \
        rand_vertices_class.cpp

rand_seglist: ../lib_geometry/libgeometry.a rand_seglist.cpp
        g++ -I../lib_geometry -L../lib_geometry -lgeometry -o rand_seglist rand_seglist.cpp

rand_vertices_sleep: rand_vertices_sleep.cpp
        g++ -o rand_vertices_sleep  rand_vertices_sleep.cpp

rand_vertices_seed: rand_vertices_seed.cpp
        g++ -o rand_vertices_seed  rand_vertices_seed.cpp

clean:
      	rm -f rand_vertices rand_vertices_file rand_vertices_class rand_seglist 
	rm -f rand_vertices_sleep rand_vertices_seed *~
\end{fileverb}
\vspace{0.1in}

\begin{fileverb}
# Makefile for Lab 06 (Ten Short C++ Labs)                                                                
# wget http://oceanai.mit.edu/cpplabs/lab06/Makefile                                                      

all: string_split string_split_v2 string_bite string_parse string_deserial

string_split : string_split.cpp
        g++ -o string_split string_split.cpp

string_split_v2 : string_split_v2.cpp
        g++ -o string_split_v2 string_split_v2.cpp

string_bite : ../lib_strings/libstrings.a string_bite.cpp
        g++ -I../lib_strings -L../lib_strings -lstrings -o string_bite string_bite.cpp

string_parse: ../lib_strings/libstrings.a string_parse.cpp
	g++ -I../lib_strings -L../lib_strings -lstrings -o string_parse string_parse.cpp

string_deserial: ../lib_strings/libstrings.a ../lib_geometry/libgeometry.a string_deserial.cpp
	g++ -I../lib_geometry -I../lib_strings -L../lib_strings -L../lib_geometry \
        -lgeometry -lstrings -o string_deserial string_deserial.cpp

clean:
        rm -f string_split string_split_v2 string_bite string_parse string_deserial *~
\end{fileverb}
\vspace{0.1in}



\end{document}

</pre></body></html>