To do anything but the smallest `hello world' program, it is good programming style to break your program into several pieces (files) and compile and test them separately before compiling the final program (in reality, there is no final program). This meshes very well with the way we do mathematical research, or solve mathematical problems at any level -- we break the problem into smaller problems which we solve separately and then construct the solution to the original problem from the pieces.
We are using the gnu compiler gcc to
compile our C++ programs, mainly because it is freely available and it
is very satisfactory for our purposes.
The compiler options -c and -o file
The gnu compiler gcc (or g++) has two options that we use a lot when compiling our program in pieces.
The compile option -c This is used on a single source (.cpp) file to construct an objective file (.o) with the same name. If we have a source file called bisect.cpp (implementing the bisection method for solving an equation) that we want to compile, the command
will set the compiler off on the task of trying to create a compiled version which it calls bisect.o . (Note: If you are using the C++ compiler from the Chisel disk, the gnu compiler name is gcc, rather than g++.) Of course, there will probably be errors in the program the first time. But with persistence, you will soon have a bisect.o . Then what? Well, you need a main.cpp to test out bisect.o . This would be compiled separately with the command
You only compile one .cpp file at a time with the -c option.
Now the second option comes in when you want to compile an executable file:
The compile option -o file : Use this option to link your .o files into an excutable file called file . So, to compile an excutable program called roots which tests the bisection method, give the command
There may be compiler errors here too. If you are using the compiler on the Chisel disk, you need to load the library gpp or there will will be errors. So, the command there reads
Now if everything went well, we can just say the word roots to run the program.
Of course, even if the program runs, there probably
will be changes for you to put in. So you will find yourself issuing the
same sequence of commands over and over. This is where the program make
comes in handy.
Using make to manage your project
The program make was written to simplify the development of a program that you are working on. Most programmers use it or something like it to develop projects. A simple makefile to work on the project roots would look something like this.
# a makefile for the project roots
roots : main.o bisect.o
<tab> g++ -o roots main.o bisect.o
main.o : main.cpp
<tab> g++ -c main.cpp
bisect.o : bisect.cpp
<tab> g++ -c bisect.cpp
clean :
<tab> rm roots main.o bisect.o
This would be put in a file makefile
in the directory with the source files, and from
there the command make roots would
compile any files that had been changed since the last time the command
was issued. If you want to start over, you would issue the command make
clean .
Creating libraries of procedures with the program ar
Suppose we have written and tested some other rootfinding methods, say Newton's method ( newton.cpp ) and the secant method ( secant.cpp ). At that point, we might want to start a library of compiled procedures with these three. This can be done with the command
ar is a program which archives procedures, ru is an option meaning replace and update, mylib.a is the name we have chosen for our library, and the three .o files have been compiled already.
Problem . There is a zipfile here called roots.zip which contains files to get you started on building the library mylib.a. Download it and unzip it. Finish the task by writing, compiling, and testing newton.o and secant.o. Then add newton.o and secant.o to the library. Document the source .cpp file with a description of the algorithm and its syntax.