#ifndef
preprocessor directive is the
solution to the first problem; Makefiles are the solution to the
second problem.
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 #endifThe
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
target: list of files the compilation depends on <TAB> command to compile the fileThe target is some name you supply and is used in issuing the make command from the shell prompt:
make targetFor 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:
make
command
to make the substitution).
This makes it easy to change compilers -- if you use
another compiler you only need to change one line in the makefile.
make
to substitute the target
in that place. Hence
with the substitution for $(GCC) and $@ the command will look likeg++ -o TestString TestString.o MyString.owhich is exactly the command you would have issued to the command line at the link stage if you weren't using a makefile.
To use the make command to compile just MyString.cc you would type at the shell prompt
make MyString.oTo compile and link the whole program and create the executable runjobs you would type
make TestStringWhen 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.