| Name: _____________________ | Class: CET 375 |
| SSN/ID: _____________________ | Section & Group: ____________ |
Compilation
The first thing to remember about compiling, as with all things in
computers, is Don't Panic! This will become second nature all too
soon. The second thing to know about compiling is that when you write a
program, you generally have nothing more than a text file which is no
different to the computer than a letter that you typed to your great
aunt Betsy. The computer has no idea what to do with a text file. To
the computer, the text file is just data. You've got to compile your
program into an executable code which the computer can
understand. (There are such things as interpreted languages —
languages where your code is compiled as it is executed, but they
don't count here since you don't compile them yourself.)
The third thing to know about compiling is that there are generally three distinct steps in compiling some code to an executable. They are:
Example: Suppose the source code for an executable binary file named project.exe is stored in a file named project.cpp. The program #includes a library's header file named lib.h and the library's implementation file is named lib.cpp. Please download source_lab04_project.cpp and rename it to project.cpp. Then, do the same for source_lab04_lib.h and source_lab04_lib.cpp (renaming them to lib.h and lib.cpp, respectively).
The directive #include "lib.h" causes the compiler (actually, the preprocessor) to insert the declaration of the prototype for function doSomething(int x) into project.cpp. However, the definition of doSomething(int x) is in lib.cpp, not in project.cpp.
Translating a program like project.cpp to produce a binary executable program involves three phases:
g++ -c project.cpp
| project.cpp | → | project.o |
g++ -c lib.cpp
| lib.cpp | → | lib.o |
g++ project.o lib.o -o project.exe
| project.o | → | project.exe |
| lib.o | → |
If a program involves several different libraries, it can be very difficult to keep track of which files are out of date, which need to be recompiled, and so on. Single commands like the preceding that do this automatically are very usefull in this regard. With GNU C++, UNIX's make utility can be used to execute a file named Makefile that contains the commands for the compilations and linking.
UNIX's make Utility
Makefiles
make is a system designed to create programs from large source code trees and to maximize the efficiency of doing so. To that effect, make uses a file in each directory called a Makefile. This file contains instructions for make on how to build your program and when.
There are three important parts to a Makefile: the target, the
dependencies, and the instructions. Just so that you
know what this will look like, it's of the form:
target: dependencies
instructions
Using the make utility requires a programmer to create a special file named Makefile, from which the make program reads information. A Makefile consists of pairs of lines (each pair governs the updating of one file).
The first line of each line-pair in a Makefile has the form:
TargetFile: DependencyFile1 DependencyFile2 ... DependencyFilen
where TargetFile is the file that needs to be updated,
and each Dependencyi is a file upon which
TargetFile depends.
The second line of the pair is a UNIX command to make TargetFile. The command must be preceded by a TAB and end with a Return.
To illustrate: The first line-pair in our Makefile appears as follows:
Note that the first line specifies the dependencies of
project.exe, and the second line is the UNIX command to make
project.exe.
project.exe: project.o lib.o
g++ project.o lib.o -o project.exe
Of course, project.o won't exist the first time we compile,
so we should specify a line-pair for it, too:
project.o: project.cpp lib.h
g++ -c project.cpp
We should then do the same thing for lib.o:
lib.o: lib.cpp lib.h
g++ -c lib.cpp
The Makefile thus appears as follows:
project.exe: project.o lib.o
g++ project.o lib.o -o project.exe
project.o: project.cpp lib.h
g++ -c project.cpp
lib.o: lib.cpp lib.h
g++ -c lib.cpp
Now, when a user types
the program reads the Makefile, and:
make
Example: We could write,
This would automatically remove the object files after
project.exe is made.
project.exe: project.o lib.o
g++ project.o lib.o -o project.exe
rm project.o
rm lib.o
uname% make lib.o
will operate using lib.o as its primary
TargetFile instead of project.exe.
Example: Suppose our Makefile contains the following lines:
and the user types
clean:
rm -f project.exe *.o *~ *#
What happens? (This is a fool-proof way to clean up a messy directory.)
uname% make clean
M-x compile
emacs responds with
Compile command: make -k
If a Makefile is in the directory containing the file on
which you are working, then pressing the Return key will execute
make using that Makefile.
Summary
The make utility eliminates the complexity of separate compilation by determining what files are out of date and re-making them. Learning to use it effectively can save a great deal of time, especially on projects that have several files.
Hand In: This lab handout with the answers filled in attached
to a listing of your final Makefile
(use the enscript command from your Programming Style Sheet to print it out:
enscript -E -G -2rj -M Letter -PECT2_PS <filename>. You can also use a2ps as in: a2ps <filename>).