The front-end for Java is the GNU Java Compiler, gcj
. Not
all of the classes for Java have been implemented, which isn't
surprising due to the impressive amount of classes that Java
contains. In particular, support for the Abstract Windowing
Toolkit
and Swing
components have not yet been
implemented1, and there is no support for Remote Method Invocation
either. The Java FAQ <http://gcc.gnu.org/java/faq.html
> details the
reasons for current extent of support. It is worth visiting this site
because new developments are made all the time as new classes and
features are added. Also, the current status of the gcj
compiler can be viewed at <http://gcc.gnu.org/java
>.
The gcj
compiler can take input files in the form of .java
or
.class
files. If a .java
source file is passed in, then it can
either be passed to gcj
and compiled into a .class
file or
compiled into native machine code. If gcj
is passed a .class
file, then it can only produce native machine code.
To view the machine-dependant classes in object-file format, supported
by gcj
, locate the libgcj.a
archive library (mine is
located in /usr/lib/
) and perform an ar t
libgcj.a
on it2. The results should be something like this:
...
EnumerationChain.o | BufferedInputStream.o
|
BufferedOutputStream.o | BufferedReader.o
|
BufferedWriter.o | ByteArrayInputStream.o
|
ByteArrayOutputStream.o | CharArrayReader.o
|
CharArrayWriter.o | CharConversionException.o
|
DataInput.o | DataInputStream.o
|
DataOutput.o | DataOutputStream.o
|
EOFException.o | File.o
|
FileDescriptor.o | FileInputStream.o
|
FileNotFoundException.o | FileOutputStream.o
|
FileReader.o | FileWriter.o
|
FilenameFilter.o | FilterInputStream.o
|
FilterOutputStream.o | FilterReader.o
|
FilterWriter.o | IOException.o
|
InputStream.o | InputStreamReader.o
|
InterruptedIOException.o | LineNumberInputStream.o
|
LineNumberReader.o | OutputStream.o
|
OutputStreamWriter.o | PipedInputStream.o
|
PipedOutputStream.o | PipedReader.o
|
which shows the output of a small section of the archive library. The
Java-equivalent files are in object file format, obviously, since gcj
takes java source code (or class files) and can convert the information into
machine-dependent binary files.
GCJ Options
Let's look at some of the commands first, and then focus on a few relatively simple examples.
gcj
is invoked as follows:
gcj [options] file1 [[file2] ...
[file
n]]
There are a number of different options available.
-C
| takes the .java file and produce a corresponding .class
file. The .class file is in (machine independent) byte code, so
it can be run with the JVM as normal. This option cannot be used
with --main=File (see below), because no machine-dependent
code is being produced. Thus, the command gcj -C SomeClass.java
will produce a file named SomeClass.class which can be run with
the java command as normal.
|
--main=File
| specifies the file to be used when searching for the file that would
normally be invoked with java [filename].java for the file named
[filename].class where the main method is specified. Cannot be
used with -C . You must specify this when
creating a binary produced in native format, because the usual
main stub cannot be found unless we tell it where to look;
remember that Java can specify a public static void main(...)
method in any of its classes, so we need some way of telling the
compiler where main will be located.
|
-o file
| creates the executable named file instead of the default
a.out . This flag cannot be used in conjuction with -C ,
because you cannot rename the class file (Java .class files are named
according to their corresponding .java source files).
|
-d dir
| places class files in directory dir . Only used when
compiling byte-code using -C .
|
-v
| As with gcc , print verbose output to stdout .
|
-g
| Produce debugging information, when creating machine dependent code; this
is useful since it enables you to use (for example) gdb or
ddd to debug java source files that have been made into
machine-dependent binaries - see Debugging with gdb and DDD.
|
Compiling a simple Java source file
The following example utilises two Java source files.
$ cat Main.java /* Main.java */ import helloworld.HelloWorld; public class Main { public static void main(String args[]) { HelloWorld helloWorld = new HelloWorld(); System.out.println(helloWorld.toString()); } } $
and our HelloWorld package
file located in the directory
helloworld
in the same directory that Main.java
is in:
$ cat helloworld/HelloWorld.java /* HelloWorld.java */ package helloworld; public class HelloWorld { String helloWorld; public HelloWorld() { helloWorld = "Hello, world!"; } public String toString() { return helloWorld; } } $
Compiling this program with the command
$ gcj --main=Main Main.java helloworld/HelloWorld.java
-o HelloWorld
yields the following output (if any problems occur, it may be because your
classpath may not be set. If you can't fix it by using any of the
options already given, try looking at the FAQ at the gcj
homepage at <http://gcc.gnu.org/java/faq.html
> for answers to
many common problems when trying to compile java programs):
$ ./HellowWorld Hello, world! $
Helloworld
is our machine-dependent binary. If we wanted, we
could have simply produced a .class
file
$ gcj -C Main.java helloworld/HelloWorld.java
Which produces Main.class
and HelloWorld/HelloWorld.class
,
which can be ran using the command java Main
:
$ java Main Hello, world! $