Chapter 9. Java
Many Java developers like Integrated
Development Environments (IDEs) such as Eclipse. Given such
well-known alternatives as Java IDEs and Ant,
readers could well ask why they should even think of using
make on Java projects. This chapter explores the
value of make in these situations; in particular,
it presents a generalized makefile that can be
dropped into just about any Java project with minimal modification
and carry out all the standard rebuilding tasks.
Using make with Java raises several
issues and introduces some opportunities.
This is primarily due to three factors: the Java compiler,
javac, is extremely fast; the standard Java
compiler supports the @filename syntax for reading
"command-line parameters" from a
file; and if a Java package is specified, the Java language specifies
a path to the .class file.
Standard Java compilers are very fast. This is primarily due to the
way the import directive works. Similar to a
#include in C, this directive is used to allow
access to externally defined symbols. However, rather than rereading
source code, which then needs to be reparsed and analyzed, Java reads
the class files directly. Because the symbols in a class file cannot
change during the compilation process, the class files are cached by
the compiler. In even medium-sized projects, this means the Java
compiler can avoid rereading, parsing, and analyzing literally
millions of lines of code compared with C. A more modest performance
improvement is due to the bare minimum of optimization performed by
most Java compilers. Instead, Java relies on sophisticated
just-in-time (JIT) optimizations performed by the
Java virtual machine (JVM) itself.
Most large Java projects make
extensive use of Java's
package feature. A class is declared to be
encapsulated in a package that forms a
scope around the symbols defined by the
file. Package names are hierarchical and implicitly define a file
structure. For instance, the package a.b.c would
implicitly define a directory structure a/b/c.
Code declared to be within the a.b.c package would
be compiled to class files in the a/b/c
directory. This means that make's
normal algorithm for associating a binary file with its source fails.
But it also means that there is no need to specify a
-o option to indicate where output files should be
placed. Indicating the root of the output tree, which is the same for
all files, is sufficient. This, in turn, means that source files from
different directories can be compiled with the same command-line
invocation.
The standard Java compilers all support the
@filename syntax that allows command-line
parameters to be read from a file. This is significant in conjunction
with the package feature because it means that the entire Java source
for a project can be compiled with a single execution of the Java
compiler. This is a major performance improvement because the time it
takes to load and execute the compiler is a major contributor to
build times.
In summary, by composing the proper command line, compiling 400,000
lines of Java takes about three minutes on a 2.5-GHz Pentium 4
processor. Compiling an equivalent C++ application would require
hours.
|