When we invoke the java compiler:
Compile command: javac Metric.java
as we have been doing, we are compiling just that class. It can be useful to just compile the one file that you are working on to check if there are any syntax errors.
Since our program involves more than one file (i.e., Driver.java and Metric.java), translating it becomes slightly more complicated. When a program consists of multiple files, the easiest way to coordinate the translation is to use a special UNIX utility named make (where have you seen that before?). To use make, we must prepare a special file called a Makefile. As we shall see, this file coordinates the compilation of the source files and the linking of the object files. You should have already saved a copy of the partial Makefile for this program; the next sections describe how to complete it.
Open the file named Makefile. A simple Makefile consists of a series of pairs of lines, in which the first line of the pair names the file being made (called the target), followed by a colon (:), followed by the files from which it is made (called the components). The second line of the pair consists of a TAB character, followed by a command that makes the target from the components, followed by a Return (or Enter).
For example, our binary executable program Driver.class requires Metric.class (this is the effect of the import) and Driver.java., so the first pair in our Makefile is as follows:
Driver.class: Metric.class Driver.java javac Driver.java
In the same fashion, our Metric classes object file Metric.class is made from Metric.java. Since Metric.class is made by having javac compile Metric.java ,this pair appears as follows:
Metric.class: Metric.java javac Metric.java
(Note: Our browser replaced the TAB character before each javac with spaces. If yours does the same, you will need to delete those spaces and replace them with a TAB.)
Don't forget the TAB at the beginning of the second line, or the Return at the end of the line -- these are the most common errors when creating a Makefile.
To test your Makefile, first remove Metric.class from your working directory. Then translate your program with the compile command, but use make instead of calling javac directly:
Compile command: make
As you can probably deduce, this will invoke a program named make instead of javac. The make program reads your Makefile and tries to make the first target it encounters (Driver.class). However, make cannot create Driver until Metric.class exists, and so it must make it. Since Metric.class is listed first in the component list, make jumps to the pair that tells it how to make Metric.class. Since Metric.class depends on Metric.java and this files exists, make executes the second line in this pair:
which creates Metric.class, if Metric.java contains no syntax errors.
Once Metric.class exists, everything needed to build the target Driver.class is available, and so make returns to the first pair and executes its second line:
This produces the byte code file Driver.class, finishing the translation.
Before we quit, let's learn a bit more about how make works. If you were watching closely when Driver translated, you saw two separate commands execute:
Metric.java compiled, producing Metric.class; and
Driver.java compiled and linked with Metric.class, producing Driver.class.
Using your editor, alter Driver.java in some trivial way (e.g., add a blank line at its beginning). Then use the compile command to invoke make again. Do all two steps occur again? If not, which step is omitted?
UNIX systems associate a "last modified date" with each file. To avoid recompiling a file needlessly, the make program uses these dates to determine what files need to be recompiled. That is, the date of Metric.class was more recent than that of Metric.java. The make program noted this and concluded that Metric.java had not been modified, and so did not waste time recompiling it.
By contrast, when we made our trivial modification to Driver.java and then saved it, the file Driver.java became newer than the file Driver.class. The make program noted this, concluded that Driver.class was outdated, and so re-made Driver.class.
In general, make will only re-make a target if any of that target's components are out of date. To see this, use make to translate Driver one last time (without modifying anything) and note the output.
On a final note, add the following lines at the end of your Makefile:
clean: rm -f *.class *~ *#
Then save your Makefile, go to an xterm, make sure that your working directory is your project directory, and use ls to examine the contents of the directory. Then enter:
% make clean
and you should see make "clean" your directory for you! Use ls again and see how much tidier it is! If you then enter
you will see make rebuild Driver.class for you!
Here is how it works: The added lines specify the name clean as a target to be made, with no components, so "clean" has no dependencies. When you type make clean, the make program searches for the name clean as a target. Finding the lines you just added, it executes the command we specified for making clean, which uses the rm command to remove, all class files, and all of the backup files xemacs creates.
If you always store each of your programming projects in a separate directory, and always supply a Makefile to translate the project, then managing your projects becomes trivial -- you simply cd to the directory where the project resides, enter make, and it will translate your project for you! Then when you are done enter make clean and make will clean up everything except your Makefile and your source files, saving disk space.
The make utility is a very powerful feature, and we have barely scratched the surface of what it can do. For more information about using make, a good book is Mastering Make (2cd Ed.), by Tondo, Nathanson and Yount (Prentice Hall, 1994), which contains information on using it on DOS-based, OS/2 and UNIX systems. A good starting place for online source of information about GNU make is provided by the GNU Project (along with a lot of other free software.)
Back to the Lab
Back to the Table of Contents
Back to the Introduction