HomeC&C++WainTutorialsSamplesTip & TrickTools


This page contains a guide to create projects with more than one cpp file.
We have a class, CalculatorClass, which we want to use in one cpp filen and define in another, so we put it into a header file, say calc.h, which could look like:
#ifndef CALC_H_INC
#define CALC_H_INC
#include <string>

class CalculatorClass
{
public:
   double Add(const std::string &aS1, const std::string &aS2);
};
#endif
The #ifndef/#define/#endif is a "include-guard", which insures that the header can be included more than once in the same cpp file without problems.
We implements the Add function in calc.cpp:
#include <string>
#include <sstream>
#include "calc.h"

template <typename T>
bool FromString(T &aValue, const std::string &aStr)
{
   std::stringstream ss(aStr);
   return ss >> aValue;
}

double CalculatorClass::Add(const std::string &aS1,
                            const std::string &aS2)
{
   double N1, N2;
   FromString(N1, aS1);
   FromString(N2, aS2);
   return N1 + N2;
}
We include our calc.h file to know the CalculatorClass.
Then we create a main.cpp which is a small test-application:
#include <iostream>
#include <string>
#include "calc.h"

int main()
{
   std::string S1, S2;

   std::cout << "Enter first number: ";
   std::getline(std::cin, S1);
   std::cout << "Enter second number: ";
   std::getline(std::cin, S2);

   CalculatorClass Calculator;
   double Result = Calculator.Add(S1, S2);

   std::cout << S1 << " + " << S2 << " Is: "
             << Result << std::endl;
}
Now to compile it all to a program use one of these, depending of your compiler:
bcc32 calc.cpp main.cpp
g++ calc.cpp main.cpp -o calc.exe
cl calc.cpp main.cpp
dmc calc.cpp main.cpp
The result will in all four cases be calc.exe

These are the things to put into header-files:
- #define
- types and class's
- prototypes for functions
- external variable defenitions
- template functions
- inline functions
But not:
- functions
- variables
When your projects grow it will take time to compile everything whenever you make a small change in one file.
Makefiles are a handy way to control the compiler and ensure that only what needs to be compiled is.
We reuse the code from above.
A makefile is file with rules of how to build a application, the makefile is read by a make program.
Most compilers has there own make program, so the syntax used differs a bit.
The main building block in a makefile is:
target: dependencies
   command
Note that some make (gcc) programs has the strange request that the indention before command must be a tab character, not spaces.
A simple example could be:
main.exe: main.cpp
   g++ main.cpp -o main.exe
Here main.exe is the target, if main.exe does not exist or is older than main.cpp (the only dependency) the command (g++ ...) will be executed.
If we have more than one file we could use:
calc.exe: main.cpp calc.cpp calc.h
   bcc32 calc.cpp main.cpp
Then, if any of the dependencies are changed, calc.exe will be build.
But if you have a project with hundreds of .cpp and .h files it is inconvenient to build everything if you only changed a bit in a single cpp-file. It is exactly here makefile show there strength, as they will know what to build, if we tell it.
The project could be build with these commands, if Digital Mars compiler is used:
dmc -c main.cpp
dmc -c calc.cpp
dmc -L/SI/DELEXECUTABLE main.obj calc.obj calc.exe
The first two lines will compile the .cpp file into a .obj file, because we used the -c switch.
The last line will link the two .obj files into the executeable.
Then, if we change main.cpp we just have to execute two of the tree lines; we don't have to compile calc.cpp.
If we put this into a makefile it will be:
calc.exe: main.obj calc.obj
   dmc -L/SI/DELEXECUTABLE main.obj calc.obj calc.exe

main.obj: main.cpp
   dmc -c main.cpp

calc.obj: calc.cpp
   dmc -c calc.cpp
Here main.obj depend on main.cpp, so if main.cpp is modified dmc -c main.cpp will be executed, and main.obj will be created. As calc.exe depends on main.obj the command to build calc.exe will also be executed.
Note that calc.exe is the first target in the file, this is the one which will be executed if no other is specified.
If you just want to compile main.cpp and don't want do link, you can run the command:
make -f makefile.mak main.obj
But if you have lots of .cpp files, it will be boring to write a unique rule for each, but then you can use:
.cpp.obj:
   dmc -c $*.cpp
This is a rule to create a .obj file from a .cpp file, with the same name, $* will expand to the basename of the cpp file. It is a implicit rule, it will be used if there is no normal (explicit) rule.
But what about the headerfile? We have to tell that main.cpp and calc.cpp includes calc.h, that is main.obj and calc.obj depends on calc.h, one way to do it:
main.obj: main.cpp calc.h
   dmc -c main.cpp
Or you can use this method:
main.obj: calc.h
calc.obj: calc.h
That is, put the dependencies on seperate lines. This has the advantage that you can use tools to create these lines, or if you are using gcc/g++ let the compiler create the lines.
You have to use the latter if you use the implicit rule.
Note that if you are using Borland's make and there compiler it will figure out the dependencies on it own.
You can use variables in makefiles:
LinkFlags=-L/SI/DELEXECUTABLE
To use a variable incluse it in $():
calc.exe: main.obj calc.obj
   dmc $(LinkFlags) main.obj calc.obj calc.exe
Or to use it for everything:
#Makefile for Digital Mars
CC=dmc
Link=dmc
CppFlags=-c
ExeFile=calc.exe
ObjectFiles=main.obj calc.obj
LinkFlags=-L/SI/DELEXECUTABLE

$(ExeFile): $(ObjectFiles)
   $(Link) $(LinkFlags) $(ObjectFiles) $(ExeFile)

.cpp.obj:
   $(CC) $(CppFlags) $*.cpp

main.obj: calc.h
calc.obj: calc.h
Now if you add a cpp file to the project you simply add the name of it's .obj file to the ObjectFiles variable.
Note that # is used to denote comments
With VisualC++ the makefile could look like this:
#Makefile for Visual C++
CC=cl
Link=cl
CppFlags=-c
ExeFile=calc.exe
ObjectFiles=main.obj calc.obj

$(ExeFile): $(ObjectFiles)
   $(Link) $(LinkFlags) $(ObjectFiles) /Fe$(ExeFile)

.cpp.obj:
   $(CC) $(CppFlags) $*.cpp

main.obj: calc.h
calc.obj: calc.h
With G++:
#Makefile for G++
CC=g++
Link=g++
CppFlags=-c
ExeFile=calc.exe
ObjectFiles=main.obj calc.obj

$(ExeFile): $(ObjectFiles)
   $(Link) $(LinkFlags) $(ObjectFiles) -o $(ExeFile)

%.obj: %.cpp
   g++ $(CppFlags) -o $@ $<

main.obj: calc.h
calc.obj: calc.h
And finnaly BorlandC:
#Makefile for BorlandC
CC=bcc32
Link=bcc32
CppFlags=-c
ExeFile=calc.exe
ObjectFiles=calc.obj main.obj

$(ExeFile): $(ObjectFiles)
   $(Link) $(ObjectFiles)

.cpp.obj:
   $(CC) $(CppFlags) $*.cpp

main.obj: calc.h
calc.obj: calc.h
If you name the makefile makefile.mak you can run it with:
make -f makefile.mak
Or if you are using Visual Compiler and its make:
nmake -f makefile.mak
It is often handy to cleanup everything, to do that we can add a new target, put it into the end of the makefile:
clean:
   del $(ObjectFiles) $(ExeFile)
If you are using gcc you might have to use rm instead of del, as it for some strange reason, seems to forget that it does know the del command.
Then you can run:
make -f makefile.mak clean
To delete everything.

The process of creating and maintaining the list of dependencies is a bit boring, so why not use at tool to do it.
I have found a tool somewhere on the net, forgot where, I have modified it, download the modified version.
With this we can create a new target to our makefile:
MakeDep=makedep.exe

makedepend:
   $(MakeDep) -n $(ObjectFiles)
You can now create a list of dependencies by running:
make -f makefile.ext makedepend
This will create a file called make.dep, so we have to include that into the makefile.
There is one catch here; we should not include make.dep if it does not exist, as we migth just be about to make it.
How to solve this, depends on the make program.
With VisualC++ and nmake it can be done by:
!if exist("make.dep")
!include "make.dep"
!else
!MESSAGE "Dependency file does not exist"
!endif
This will print "Dependency file does not exist" if make.dep does not exist, make.dep will be included otherwice.
GNU make:
ifneq ($(MAKECMDGOALS),makedepend)
include make.dep
endif
$(MAKECMDGOALS) is a variable set by make containing the target you are building, if you are building dependencies it will not include the dependecy file, if you are not building dependencies and make.dep does not exist, make will show an error message and exit.
I have not found a proper way to do this with Borlands make, you could do:
!ifdef SKIP_MAKEDEP
!message make.dep skipped
!else
!include make.dep
!endif
This will requere you to add -DSKIP_MAKEDEP to the command line when running make, if you don't want to include make.dep.
For Digital Mars there does not seem to be any solution at all, you just include the file:
include make.dep
Make will stop if make.dep does not exist, so you have to create a empty make.dep first time.
Don't forget to tell makedep where it is to search for include files.

Now I will show how to add an icon to the program.
For this we need a .ico file and a reseource file.
If the name of the .ico file is calc.ico the reource file should contain this one line:
  129 ICON DISCARDABLE     "calc.ico"
The number is more or less random selected, we don't need it elsewhere.
Now we need to "compile" this resource file and link it with the other .obj files.
For this we need a resource compiler, each compiler has its own, so the syntax for using it differs. For all, if the resource file is called calc.rc the output will be calc.res.
Now we can add two lines to the makefile, to compile the .rc file
First BorlandC:
RC=brc32

.res.rc:
   $(RC) -r -32 $*.rc
Then Digital Mars:
RC=rcc

.rc.res:
   $(RC) -D__NT__ $*.rc
And GCC:
RC=windres
%.res: %.rc
   $(RC) -i $< -I rc -o $@ -O coff
And finally Visual C++:
RC=rc

.rc.res:
   $(RC) $*.rc
Now the calc.res file can be created, so we need to link to it.
First, Borland. Here we need to use ilink32.exe to link and not bcc32.exe, the command line will need to be changed:
Link=ilink32
ResourceFile=calc.res

$(ExeFile): $(ObjectFiles) $(ResourceFile)
   $(Link) c0x32.obj $(ObjectFiles),$(ExeFile),,\
   import32.lib cw32.lib,,$(ResourceFile)
Note this is for a console application, if you are linkling a windows application you need to use c0w32.obj.
The line above starting with $(Link) ends with a \ this will get make to treat this line and the next line as one line. This feature can be used everywhere in the makefile to split long lines.
Next GCC:
ResourceFile=calc.res

$(ExeFile): $(ObjectFiles) $(ResourceFile)
	$(Link) $(LinkFlags) $(ObjectFiles)\
   $(ResourceFile) -o $(ExeFile)
Then Digital Mars:
ResourceFile=calc.res

$(ExeFile): $(ObjectFiles) $(ResourceFile)
   $(Link) $(LinkFlags) $(ObjectFiles) $(ResourceFile) $(ExeFile)
And VisualC++:
ResourceFile=calc.res

$(ExeFile): $(ObjectFiles) $(ResourceFile)
	$(Link) $(LinkFlags) $(ObjectFiles) \
   $(ResourceFile) /Fe$(ExeFile)
I have put everything into a .zip file.