Making Compiling Easier:
Makefiles and #ifndef

When programs use several different classes, each in its own header and definition file, two features of C++ (and C) help us manage the files. There are primarily two management concerns. First, we may have several files that include the same .h files. This is not good from an efficiency standpoint and, in some cases, it may cause the compiler or linker to complain about duplicate definitions. The second problem is that it may be hard for us to keep track of which files need to be recompiled. The #ifndef preprocessor directive is the solution to the first problem; Makefiles are the solution to the second problem.

#ifndef ... #define Preprocessor Directives

When you declare a class in a .h file, you can use the #ifndef "if not defined" preprocessor directive, together with the #define directive and an #endif directive. These three directives together allow for conditional compilation; that is, they have the compiler include the portion of code between the #define and #endif only when that code has not already been included. The syntax is as follows:

     #ifndef SOME_NAME
     #define SOME_NAME


        ... your declarations for the class go in here

     #endif

The SOME_NAME is a name you provide. Although it can be any name, the convention used by the C++ library header files derives SOME_NAME from the name of the file as follows: If the file is called Foo.h, the preprocessor directives would be
     #ifndef _FOO_H
     #define _FOO_H

        ... declarations here

     #endif

Makefiles

UNIX has a make command that helps manage the compilation and linking processes during program development. To use the make command, the programmer must prepare a file, called a makefile, that shows the dependence relations among the different files used in a program. Basically, for each file you may want to compile, you will have an entry in the makefile in the following format:
target:   list of files the compilation depends on
<TAB>     command to compile the file

The target is some name you supply and is used in issuing the make command from the shell prompt:
          make target
For example, for the second programming assignment, suppose you have a MyString class in file MyString.h/MyString.cc and a main program in file TestString.cc. In the past you would compile MyString.cc (g++ -c MyString.cc), then compile TestString.cc (g++ -c TestString.cc), then link them into a target executable (g++ -o TestString TestString.o MyString.o). When a .cc file changed, you had to recompile it and relink; when a .h file changed, you had to recompile everything that depended on it. The following is a makefile to do the same thing. It should be typed in a file named Makefile in the directory with the program files (there are other standard names but it's best to stick with this). In this makefile, the target TestString would be the name of the executable (you could call it anything -- it doesn't need to match the name of source file being compiled).
GCC=g++

MyString.o:     MyString.cc MyString.h
                $(GCC) -c MyString.cc

TestString.o:   TestString.cc MyString.h
                $(GCC) -c TestString.cc

TestString:     TestString.o MyString.o
                $(GCC) -o $@ TestString.o MyString.o

REMEMBER to use TABS on the command lines!!! That is, the space before $(GCC) on each line is tabs, not spaces.

This file does the following:

To use the make command to compile just MyString.cc you would type at the shell prompt

         make MyString.o
To compile and link the whole program and create the executable runjobs you would type
         make TestString
When the make executes, it goes to the target and sees what files the target depends on. Some of those may depend on other files, so it recursively checks dependencies and updates targets anytime it finds files that have changed since the target was last created. This removes from the programmer the burden of having to remember which files need to be re-compiled.