You are on page 1of 21

VonHagen_5858 C04.

fm  Page 79  Wednesday, June 21, 2006  6:14 AM

CHAPTER 4
� � �

Using GCC’s Java Compiler

T his chapter discusses typical usage of the GNU Compiler Collection’s Java compiler, gcj, focusing 
on the command-line options and constructs that are specific to gcj and the additional tools that are 
provided with gcj.

Java and GCC’s Java Compiler
Java is a popular language for a number of reasons, and the inclusion of a Java compiler in the GNU 
Compiler Collection is a huge step forward for the popularity of Java on Linux systems. This chapter 
of the book is about using gcj, rather than providing a cheerleading session for Java in general. Hundreds 
of other books provide the latter. However, it is important to provide a bit of background about Java, 
and, specifically, about how Java compilers work, in order to understand what gcj does and how best 
to take advantage of its capabilities.
Aside from inherent features of the language, such as its object orientation, security, and network 
awareness, the biggest reason for Java’s popularity is the portability of Java applications. Java source 
code is typically precompiled into system-independent bytecode which can subsequently be executed 
by any Java Virtual Machine (JVM) that is running on a specific target platform. However, this port-
ability and subsequent interpretation has a performance downside—interpretation takes time. Many 
JVMs therefore include what are known as Just-in-Time (JIT) or HotSpot compilers. These compilers 
are internal to the JVM and look for frequently executed portions of the bytecode that they then 
precompile into optimized machine-specific object code at execution time. Commercial examples 
of Linux JVMs that use the JIT approach on Intel platforms include Sun’s HotSpot Client and Server 
JVMs (http://java.sun.com/j2se), BEA’s WebLogic JRockit (http://www.bea.com/framework.
jsp?CNT=index.htm&FP=/content/products/jrockit), and IBM’s Java 2 Runtime Environment 
(http://www-128.ibm.com/developerworks/java/jdk/linux/). The best-known open source JVMs 
using the JIT approach under Linux are Blackdown’s Java Platform 2 for Linux (http://www.
blackdown.org/), Kaffe (http://www.kaffe.org/), and the SableVM (http://sablevm.org/), which 
are also available for non-Intel platforms, thanks to the nature of open source. 
The other common approach to improving Java performance on a specific platform is known as 
Ahead-of-Time (AOT) compilation, which is essentially the traditional approach to compilation 
tweaked slightly for the Java environment. AOT compilers can compile Java source code into tradi-
tional Java bytecode or into platform-specific object code, and can also compile existing bytecode 
into platform-specific object code. GCC’s gcj Java compiler is an AOT compiler that comes with its 
own runtime, libgcj, which provides a bytecode interpreter (a built-in version of the GNU interpreter 
for Java, gij), a set of core class libraries, and a garbage collector. The core class libraries are based on 
the GNU Classpath project (http://www.gnu.org/software/classpath/) and are in the process of 
merging with that project. The built-in interpreter is provided to handle Java code that is not compiled to 
object code ahead of time. Java bytecode typically provides external components or class libraries, 

79
VonHagen_5858 C04.fm  Page 80  Wednesday, June 21, 2006  6:14 AM

80 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

which can also be applications that you simply want to deliver in traditional Java bytecode. Another 
popular AOT compiler for Linux systems is Excelsior JET (http://www.excelsior-usa.com/jet.html), 
though this is not an open source product/project. 

Basic gcj Compiler Usage
Appendix A discusses the options that are common to all of the GCC compilers, and how to customize 
various portions of the compilation process. However, I’m not a big fan of making people jump 
around in a book just to simplify its organization. For that reason, this section provides a quick 
refresher of basic GCC compiler usage as it applies to the gcj Java compiler. For detailed informa-
tion, see Appendix A. If you are new to gcj or the GCC compilers in general and just want to get 
started quickly, you’re in the right place.
The gcj compiler accepts both single-letter options, such as -o, and multiletter options, such as 
--classpath. Because it accepts both types of options you cannot group multiple single-letter options 
together as you may be used to doing in many GNU and Unix/Linux programs. For example, the 
multiletter option -pg is not the same as the two single-letter options -p�-g. The -pg option creates 
extra code in the final binary that outputs profile information for the GNU code profiler, gprof. On 
the other hand, the -p�-g options generate extra code in the resulting binary that produces profiling 
information for use by the prof code profiler (-p) and causes gcj to generate debugging information 
using the operating system’s normal format (-g).
Despite its sensitivity to the grouping of multiple single-letter options, you are generally free to 
mix the order of options and compiler arguments on the gcc command line—that is, invoking gcj as

gcj�-pg�-fno-strength-reduce�-g�myprog.java�-o�myprog�--main=Hello

has the same result as

gcj�myprog.java�--main=Hello�-o�myprog�-g�-fno-strength-reduce�-pg

I say that you are generally free to mix the order of options and compiler arguments because, in 
most cases, the order of options and their arguments does not matter. In some situations, order does 
matter, if you use several options of the same kind. For example, the -I option specifies an additional 
directory or directories to search for jar (Java Archive) files. So, if you specify -I several times, gcj 
searches the listed directories in the order specified.
The following is the classic C language hello, world application, written in Java as a trivial 
example for this section:
class�Hello
{��
��������public�static�void�main(String�args[])
��������{
�����������System.out.println("Hello�World!");
��������}
}
After saving this to a file named hello.java, it is easy to compile it to produce an executable using 
gcj—just invoke gcj, passing the name of the source file as the argument and using the --main option 
to identify the name of the class containing the main method that should be called when the applica-
tion executes.
$�gcj�--main=Hello�hello.java
$�ls�-l
VonHagen_5858 C04.fm  Page 81  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 81

-rwxr-xr-x����1�wvh����users������14256�Oct���5�16:17�a.out
-rw-r--r--����1�wvh����users������134�Oct��5�16:17�hello.java

By default, the result on Linux and Unix systems is an executable file named a.out in the current 
directory, which you execute by typing ./a.out. On Cygwin systems, you will wind up with a file 
named a.exe that you can execute by typing either ./a or ./a.exe. Running the a.out file on a Linux 
system produces the familiar output, as shown in the following example:

$�./a.out

Hello�World!

ERROR MESSAGES FOR MAIN METHODS

An error message like the following is a common message that you may see when attempting to compile a 
Java application:

$�gcj�hello.java

/usr/lib64/gcc/x86_64-suse-linux/4.0.2/../../../../lib64/crt1.o:��
�����In�function�`_start':
../sysdeps/x86_64/elf/start.S:109:�undefined�reference�to�`main'
collect2:�ld�returned�1�exit�status

This message simply means that you’ve forgotten to specify the main method using the --main option, and 
is analogous to the following type of message from an actual Java Virtual Machine:

$�java�Hello.java

Exception�in�thread�"main"�java.lang.NoClassDefFoundError:�Hello

To resolve the gcj compilation message, simply specify the main method using the --main command-line 
option. To resolve the equivalent problem in a Java Virtual Machine, you can simply use gcj to generate a class 
file that contains the appropriate main method information and then run that using the Java interpreter, as in the 
following example:

$�gcj�-C�hello.java
$�java�Hello

Hello�World!
VonHagen_5858 C04.fm  Page 82  Wednesday, June 21, 2006  6:14 AM

82 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

To define the name of the output executable that gcj produces, use the -o option, as illustrated 
in the following example:
$�gcj�hello.java�--main=Hello�-o�runme
$�ls�-l

-rw-r--r--����1�wvh����users�������134�Oct��5�16:17�hello.java
-rwxr-xr-x����1�wvh����users�������14256�Oct��5�16:28�runme

If you are compiling multiple source files using gcj, you can simply specify them all on the gcj 
command line, as in the following example, which leaves the compiled and linked executable in the 
file named showdate:

$�gcj�showdate.java�helper.java�--main=ShowDate�-o�showdate

If you want to compile these files incrementally and eventually link them into a binary, you can 
use the -c option to halt compilation after producing an object file, and then link the object files 
together, as in the following example:
$�gcj�-c�showdate.java
$�gcj�-c�helper.java
$�gcj�showdate.o�helper.o�--main=ShowDate�–o�showdate
$�ls�-l

total�124
-rw-r--r--����1�wvh����users����������210�Oct��5�12:42�helper.java
-rw-r--r--����1�wvh����users���������1104�Oct��5�13:50�helper.o
-rwxr-xr-x����1�wvh����users��������13891�Oct��5�13:51�showdate
-rw-r--r--����1�wvh����users����������208�Oct��5�12:44�showdate.java
-rw-r--r--����1�wvh����users���������1008�Oct��5�13:50�showdate.o

Because gcj also supports compilation into bytecode class files, you could also achieve the same 
thing by first using gcj’s –c option, which tells the compiler to generate class files and then exit, and 
then using the –o and --main options together to generate object code and link the files with the 
correct main method, as in the following example:
$�gcj�-C�showdate.java
$�gcj�-C�helper.java
$�gcj�ShowDate.class�Helper.class�--main=ShowDate�–o�showdate
$�ls�-l

total�124
-rw-r--r--����1�wvh����users����������210�Oct��5�12:42�helper.java
-rw-r--r--����1�wvh����users����������310�Oct��5�13:50�Helper.class
-rwxr-xr-x����1�wvh����users��������13891�Oct��5�13:51�showdate
-rw-r--r--����1�wvh����users����������208�Oct��5�12:44�showdate.java
-rw-r--r--����1�wvh����users����������780�Oct��5�13:50�ShowDate.class

Using bytecode as your intermediate format is most useful either when this is your target 
output format, or when you are compiling multiple Java source files and incrementally testing the 
classes that they contain using the gij. 
VonHagen_5858 C04.fm  Page 83  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 83

�Note  All of the GCC compilers “do the right thing” based on the extensions of the files provided on any GCC 
command line. Mapping file extensions to actions (for example, understanding that files with .o extensions only 
need to be linked) is done via the GCC specs file. Prior to GCC version 4, the specs file was a stand-alone text file 
that could be modified using a text editor; with GCC 4 and later, the specs file is built-in and must be extracted 
before it can be modified. For more information about working with the specs file, see “Customizing GCC Using 
Spec Strings” in Appendix A.

It should be easy to see that a project consisting of more than a few source code files would 
quickly become exceedingly tedious to compile from the command line, especially after you start 
adding search directories, complex dependencies, optimizations, and other gcj options. Most Java 
developers use the Apache project’s Ant utility (http://ant.apache.org/) to solve this problem 
rather than the traditional make utility. This is only natural because Ant is itself based on Java and 
executes Java objects to perform the various tasks required to resolve dependencies in an Ant config-
uration file. Ant’s build.xml configuration files use a modern, easily-understood XML format rather 
than the admittedly voodoolike format of complex Makefiles. Though many people no longer manu-
ally write Makefiles thanks to autoconf and automake (see Chapter 7), not even the most hard-core 
make fan could claim that it is harder to read or write build.xml files than autoconf-generated Makefiles. 
Like discussing make, discussing Ant is also outside the scope of this book, but Ant’s online documen-
tation is excellent, as are various books on Ant, such as Ant: The Definitive Guide, Second Edition, 
Steve Holzner (O’Reilly, 2005. ISBN: 0-596-00609-8).

Demonstrating gcj, javac, and JVM Compatibility
While gcj can clearly compile Java applications into object code that your system can execute with 
the help of libgcj.jar, gcj can also easily be used to compile existing class and jar files into executables 
that your system can execute. While this should be no surprise given the basic design of Java and the 
whole idea of system-independent bytecode, it’s still useful to demonstrate this.
To do so, I’ll use a Java version of the standard Fibonacci sequence application used in all of 
the other precompiler chapters in this book. The sample code for this application, stored in the file 
Fibonacci.java, is the following:
import�java.io.PrintStream;�

public�class�Fibonacci�{
����
����private�int�sequence�=�0;�

����private�int�calcFibonacci(int�n)�{
���������if(n�<=�1)
�������������return�n;
���������else�
�������������return�calcFibonacci(n�-�1)�+�calcFibonacci(n�-�2);
����}

����public�void�calculate(PrintStream�out)�{
��������int�j;
��������for�(j�=�0�;�j�<�sequence�;�j++)
������������out.print(calcFibonacci(j)�+�"�");
��������out.println();
����}
VonHagen_5858 C04.fm  Page 84  Wednesday, June 21, 2006  6:14 AM

84 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

����public�Fibonacci(int�i)�{
��������sequence�=�i;�
����}

����public�static�void�main(String[]�argv)�{
��������if�(�argv.length�==�0)�{
������������System.out.println("Usage:�fibonacci�num-of-sequence-values-to-print");
������������System.exit(0);
��������}�else�
������������new�Fibonacci(new�Integer(argv[0]).intValue()).calculate(System.out);
����}
}
The working directory initially holds just this source code (and a copy of the hello, world appli-
cation in Java):

$�ls�-l

total�8
-rw-r--r--��1�wvh�users�544�2006-02-19�09:39�Fibonacci.java
-rw-r--r--��1�wvh�users�134�2006-02-19�09:39�hello.java

Let’s compile these applications using Sun’s Java compiler, javac (part of the J2SE that you can 
freely download from http://java.sun.com/), using the -verbose option to display the version of the 
JVM libraries used during compilation:
$�javac�Fibonacci.java
$�javac�-verbose�hello.java

[parsing�started�hello.java]
[parsing�completed�63ms]
[loading�/usr/lib/jvm/java…/jre/lib/rt.jar(java/lang/Object.class)]
[loading�/usr/lib/jvm/java…/jre/lib/rt.jar(java/lang/String.class)]
[checking�Hello]
[loading�/usr/lib/jvm/java…/jre/lib/rt.jar(java/lang/System.class)]
[loading�/usr/lib/jvm/java…/jre/lib/rt.jar(java/io/PrintStream.class)]
[loading�/usr/lib/jvm/java…/jre/lib/rt.jar(java/io/FilterOutputStream.class)]
[loading�/usr/lib/jvm/java…/jre/lib/rt.jar(java/io/OutputStream.class)]
[wrote�Hello.class]
[total�316ms]

At this point, the directory only contains the source code and the class files generated by javac:

$�ls�-l

total�20
-rw-r--r--��1�wvh�users�985�2006-02-19�09:52�Fibonacci.class
-rw-r--r--��1�wvh�users�544�2006-02-19�09:39�Fibonacci.java
-rw-r--r--��1�wvh�users�416�2006-02-19�09:52�Hello.class
-rw-r--r--��1�wvh�users�134�2006-02-19�09:39�hello.java
VonHagen_5858 C04.fm  Page 85  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 85

Now, let’s execute these class files using Sun’s 1.5.0 JVM:

$�java�-showversion

java�version�"1.5.0_02"
Java(TM)�2�Runtime�Environment,�Standard�Edition�(build�1.5.0_02-b09)
Java�HotSpot(TM)�Client�VM�(build�1.5.0_02-b09,�mixed�mode,�sharing)
….

$�java�Hello

Hello�World!

$�java�Fibonacci�7

0�1�1�2�3�5�8

Now, I’ll use gcj to compile the Fibonacci.class file produced by javac, demonstrate that the 
output is an actual binary, and then execute that object code:
$�gcj�Fibonacci.class�-o�fibonacci�--main=Fibonacci
$�file�fibonacci

fibonacci:�ELF�64-bit�LSB�executable,�AMD�x86-64,�version�1�(SYSV),��
��������for�GNU/Linux�2.4.1,�
��������dynamically�linked�(uses�shared�libs),�not�stripped

$�./fibonacci�7

0�1�1�2�3�5�8

Just to be completely paranoid, let’s try this in reverse, using gcj to generate a class file and then 
executing that class file using Sun’s JVM:
$�gcj�-C�Fibonacci.java
$�java�Fibonacci�7

0�1�1�2�3�5�8

As mentioned before, none of this should have come as a surprise, but it’s useful to actually 
demonstrate that gcj does indeed hold to standard class file conventions, which makes it possible to 
mix and match class files compiled with gcj with existing class files without recompilation.
VonHagen_5858 C04.fm  Page 86  Wednesday, June 21, 2006  6:14 AM

86 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

Filename Extensions for Java Source Files
As mentioned in the previous section, all GCC compilers evaluate filename suffixes to identify the 
type of compilation that they will perform. Table 4-1 lists the filename suffixes that are relevant to gcj 
and the type of compilation that gcj performs for each.

Table 4-1. GCC Filename Suffixes for Java

Suffix Operation
.class Java bytecode file.
.jar Archive file containing one or more .class files. The archive may or may not 
be compressed.
.java Java source file.
.zip Compressed archive file containing one or more .class files.

A filename specified on the gcj command line with no recognized suffix is considered an object 
file to be linked. A file in a .jar or .zip file with no extension is considered to be a Java resource file 
identifying resources that can be accessed at runtime as core:/resource-name URLs using the core 
protocol handler. 
As with the other GCC compilers, this fixed list of filename suffixes does not mean you are limited to 
using these suffixes to identify source or object files. As discussed in Appendix A, you can use the -x�
lang option to identify the language used in one or more input files if you want to use a nonstandard 
extension. The lang argument tells gcj the input language to use.

�Note  When any GCC compiler encounters a file with one of the suffixes shown in Table 4-1, it treats the file as 
a Java file. Nonetheless, other GCC compilers (such as gcc) do not understand the complete chain of dependencies, 
such as class libraries, that Java programs often require and also do not directly know how to compile Java code. 
You should therefore always use gcj to invoke GCC’s Java compiler directly when compiling Java code rather than 
using the gcc command and hoping for the best.

Command-Line Options for GCC’s Java Compiler
As explained in Appendix A, many command-line options are common to all of the compilers in the 
GCC suite. Table 4-2 shows the command-line options that are specific to the gcj compiler.

Table 4-2. gcj Command-Line Options

Option Description
--bootclasspath=PATH Identifies the location of the standard built-in classes, such as 
java.lang.String. See the next section, “Constructing the 
Java Classpath,” for more information about this option and 
class location.
-c Specifies that all input files are Java source files and compiles 
each of them into Java bytecode .class files. No object code 
(either .o files or a single executable) is produced.
VonHagen_5858 C04.fm  Page 87  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 87

Table 4-2. gcj Command-Line Options

Option Description
--classpath=PATH Sets the classpath to PATH. This does not override the built-in 
boot search path. See the next section, “Constructing the Java 
Classpath,” for more information about this option and the 
classpath in general.
--CLASSPATH=PATH Provides a deprecated synonym for the --classpath option.
-d OUTPUTDIR Provides a synonym for the --output-class-dir option, 
which exists for compatibility with the options used by 
Sun’s javac Java compiler.
-Dname[=value] Defines a system property named name with the value 
value—if no value is specified, the default value of name is 
the empty string. Any system properties defined using this 
option can be retrieved at runtime using the java.lang.
System.getProperty method. This option can only be used 
when linking—in other words, in conjunction with the --main 
or –lgij options.
--encoding=NAME Enables you to manually specify the encoding used in one 
or more Java source files. Ordinarily, gcj first tries to use the 
default encoding specified by your current locale, falling back 
to UTF-8 Unicode encoding if your system does not have 
sufficient locale support. The gcj compiler uses UTF-8 
internally, so this is always safe to use in your source files.
--extdirs=PATH Identifies one or more additional directories that should be 
appended to the end of the classpath. See the next section, 
“Constructing the Java Classpath,” for more information 
about this option and the classpath in general.
-lgij Generates object code that uses the same command-line 
processing mechanism as the GNU interpreter for Java’s gij 
command to identify the name of the class whose main method 
is the entry point for program execution. This command-line 
option is an alternative to using the --main option when 
generating an executable and is ignored if the --main option 
is also specified.
--main=CLASSNAME Identifies the class whose main method is the entry point 
for executing the application. Required when linking a gcj 
executable.
--output-class-dir=OUTPUTDIR Specifies the top-level directory to which .class output files 
should be written. Used with the –c option. The .class files 
generated by gcj’s –c option follow the same directory structure 
as input file. For example, the class file for the input file foo/
bar.java would be written to OUTPUTDIR/foo/bar.class.
--resource�resource-name Tells gcj to compile the contents of the specified file to object 
code so it may be accessed at runtime with the core protocol 
handler as core:/resource-name. This option is typically used 
to compile files with no extension for subsequent inclusion 
into jar or zip archives.
-shared Tells gcj to create a shared library as its output rather than a 
standard executable.
VonHagen_5858 C04.fm  Page 88  Wednesday, June 21, 2006  6:14 AM

88 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

�Note  By default, gcj generates code with a debugging level of 1 (line number information) rather than using the 
standard gcc convention of not including debugging information. This is overridden if you specify a particular debugging 
or optimization level using any –g or –o option. 

The gcj compiler recognizes other options specific to Java warnings, code generation, and opti-
mizations, which are discussed in more detail in the appropriate sections of Appendix A. However, 
for your convenience, Table 4-3 summarizes the gcj-specific options related to warnings, and Table 4-4 
summarizes the gcj-specific options related to code generation and optimization.  

Table 4-3. gcj Warning Option Summary

Option Description
-Wredundant-modifiers Causes gcj to generate a warning when a redundant modifier is 
encountered, such as a public declaration for an interface method.
-Wextraneous-semicolon Causes gcj to generate a warning when an empty statement is 
encountered.
-Wno-out-of-date Suppresses the warning that gcj generates by default when a source 
file is newer than its matching class or object file.
-Wno-deprecated Causes gcj to generate a warning if a deprecated class, method, or 
field is referred to.
-Wall Implies the -Wredundant-modifiers, -Wextraneous-semicolon, and 
–Wunused options.

Table 4-4. gcj Code Generation and Optimization Option Summary

Option Description
--disable-assertions[=class-or-package] Tells gcj not to embed code for checking assertions in the 
compiled code. If no class or package is specified, using 
this option disables assertion code generation for all 
classes and packages, unless a more specific --enable-
assertions option is also specified. If a class or package 
name is specified, this option disables assertion checks 
within the named class and its inner classes or the named 
package and any subpackages. By default, assertions are 
enabled when generating class files (–c) or when not 
optimizing (no –o option), and disabled when generating 
optimized binaries using any –o option.
--enable-assertions[=class-or-package] Tells gcj to embed code for checking assertions in the 
compiled code. As of gcj 4.1, this option is only useful 
to partially override the effects of a more sweeping 
--disable-assertions option.
VonHagen_5858 C04.fm  Page 89  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 89

Table 4-4. gcj Code Generation and Optimization Option Summary

Option Description
-findirect-dispatch Enables a special binary compatibility ABI that honors 
the binary compatibility guarantees in the Java Language 
Specification, causing all dependencies to be looked up 
at runtime. This allows free mixing of interpreted and 
compiled code. At the time this book was written, this 
option could only be used when compiling class files 
whose native methods are written using the Java Native 
Interface (JNI).
-fjni Tells gcj that the native methods in the class(es) being 
compiled are written in the JNI rather than the default 
Compiled Native Interface (CNI), and causes gcj to 
generate stubs that will invoke the underlying JNI methods.
-fno-assert Tells gcj not to recognize the assert keyword. This option 
is provided for compatibility with older versions of the 
language specification.
--no-bounds-check Tells gcj not to automatically embed instructions to check 
at runtime that array indices are within bounds. By default, 
gcj automatically embeds instructions to verify that all 
array indices are within bounds, causing the application 
to throw an ArrayIndexOutOfBoundsException exception 
if they are not.
-fno-optimize-static-class-initialization Tells gcj not to optimize how static classes are initialized, 
regardless of the specified optimization level. By default, 
when the optimization level is –O2 or greater and object 
code is being produced, gcj tries to optimize how the 
runtime initializes static classes the first time that they 
are used.
-fno-store-check Tells gcj not to automatically embed instructions to check 
at runtime that objects stored into an array are compatible 
with the type of that array. With this option, these checks 
are omitted. By default, gcj automatically embeds 
instructions to verify that all code that stores an object 
into an array is assignment-compatible with the type 
of that array, causing the application to throw an 
ArrayStoreException exception if they are not.

Constructing the Java Classpath
Like all Java compilers, gcj uses the notion of a classpath to identify directory locations from which 
to load classes that are included by reference in files that are being compiled. By default, gcj looks in 
libgcj.jar, which is a jar archive containing all of the standard classes provided with gcj and whose 
location is compiled into gcj. The gcj compiler provides the --bootclasspath, --classpath, and 
--extdirs options to identify alternate locations for class or Java source files that are included by 
reference, each of which takes an argument that consists of one or more directories. On Linux systems, 
multiple directories specified as an argument to these options must be separated by a colon; on 
Windows systems, they must be separated by a semicolon. The gcj compiler also uses the standard 
GCC –I option for this purpose. All of these options interact with the CLASSPATH environment variable 
that is used for the same purpose.
VonHagen_5858 C04.fm  Page 90  Wednesday, June 21, 2006  6:14 AM

90 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

The file/directory search order used by gcj during compilation is the following:

• The compiler searches its shared library path for .so files that may contain the requested 
class. For example, if the class foo.bar is requested, gcj will search for shared libraries with the 
names lib-foo-bar.so and lib-foo.so (in that order) before proceeding to the rest of the 
classpath search.
• The compiler next searches any directories specified using the –I option.
• If the --classpath option is specified, the specified directories are searched in order.
• If the --classpath option is not specified and the CLASSPATH environment variable is set, the 
directories specified in the CLASSPATH are searched in order.
• The current directory is searched. 
• Any directory specified using the --bootclasspath option is searched.
• If the --bootclasspath option was not specified, the built-in system class archive, libgcj.jar 
is searched.
• If the --extdirs option was specified, the specified directory is searched in order.
• If the --extdirs option was not specified, the built-in directory in install-location/share/
java/ext is searched.

�Note  The default class file for the class java.lang.Object (stored in libgcj.jar) contains a special zero-length 
attribute gnu.gcj.gcj-compiled. The compiler looks for this attribute when loading java.lang.Object 
and will report an error if this attribute isn't found unless you are compiling Java code to bytecode. The 
fforce-classes-archive-check option can be used to force this checking even when compiling to bytecode.

Creating and Using Jar Files and Shared Libraries
Jar files are compressed archive files in zip format that contain one or more class files and can also 
contain related data, such as images and sound files that are referenced by the classes contained in 
the jar file. Jar files simplify distributing Java applications as a single, compressed file that can be 
directly unpacked and executed by using your Java interpreter’s –jar option and identifying the 
name of the jar file.
Jar files are created using the jar tool that is provided as part of any Java development environ-
ment. The jar utility lets the programmer create a jar file, add files to an existing jar file, list the contents 
of an existing jar file, or extract individual files from a jar archive. With one significant exception, the 
options used for any of the operations are identical to the options used by the standard Unix/Linux tar 
application. For example, the following commands create a class file for the Fibonacci.java example used 
throughout this chapter and then create a jar file called fib.jar that contains this class file:
$�gcj�–C�Fibonacci.java
$�jar�cvf�fib.jar�Fibonacci.class

added�manifest
adding:�Fibonacci.class(in�=�1033)�(out=�639)(deflated�38%)

However, attempting to execute this jar file produces an error message, as shown in the following 
example:
VonHagen_5858 C04.fm  Page 91  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 91

$�java�-jar�fib.jar

Failed�to�load�Main-Class�manifest�attribute�from
fib.jar

This message is the jar file’s equivalent of the “Exception in thread "main" java.lang.
NoClassDefFoundError:” error message that you see when the Java interpreter does not know which 
class contains the main method that it should invoke as discussed in the sidebar titled “Error Messages 
for Main Methods,” earlier in this chapter. To resolve this problem, you must create a Manifest.txt 
file that identifies the class containing the main method and add this to your jar file. A Manifest.txt file 
contains a single entry in the following format:

Main-Class:�package-name.class-name

For our simple example, the corresponding Manifest.txt file would look like the following:

Main-Class:�Fibonacci

A manifest.txt file must end with a carriage return/new line combination. To add a Manifest.txt 
file to a jar file, you identify it using the jar command’s --m option. To specify a Manifest.txt file when 
creating a jar file, you would use a command such as the following:
$�jar�-cvfm�fib.jar�Manifest.txt�Fibonacci.class
added�manifest
adding:�Fibonacci.class(in�=�1033)�(out=�639)(deflated�38%)
When creating a jar file containing a Manifest.txt file, you must make sure that you specify file-
names in the right order. The jar command’s --f option indicates that the next filename is the name 
of the archive file. Similarly, the --m option indicates that the next available filename identifies the 
Manifest.txt file. If you specify the --m option before the --f option, the jar command will misinterpret 
your command-line arguments and think that the name of your jar file is the Manifest.txt file—since 
it does not yet exist, you will see an error message such as the following:

$�jar�-cmvf�fib.jar�Fibonacci.class�Manifest.txt

java.io.FileNotFoundException:�fib.jar�(No�such�file�or�directory)
��������at�java.io.FileInputStream.open(Native�Method)
��������at�java.io.FileInputStream.<init>(FileInputStream.java:106)
��������at�java.io.FileInputStream.<init>(FileInputStream.java:66)
��������at�sun.tools.jar.Main.run(Main.java:123)
��������at�sun.tools.jar.Main.main(Main.java:904)

Specifying your class file(s) and your Manifest.txt file in the wrong order will produce a similar 
error message, as in the following example:

$�jar�-cvfm�fib.jar�Fibonacci.class�Manifest.txt

java.io.IOException:�invalid�header�field
��������at�java.util.jar.Attributes.read(Attributes.java:383)
��������at�java.util.jar.Manifest.read(Manifest.java:167)
��������at�java.util.jar.Manifest.<init>(Manifest.java:52)
��������at�sun.tools.jar.Main.run(Main.java:124)
��������at�sun.tools.jar.Main.main(Main.java:904)
VonHagen_5858 C04.fm  Page 92  Wednesday, June 21, 2006  6:14 AM

92 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

To add the Mainfest.txt file to an existing jar file, you would use a command such as the following:

$�jar�-ufm�fib.jar�Manifest.txt

If you see any error messages, check your Manifest.txt file and make absolutely sure that you 
have specified the arguments in the right order.
Versions 4.0 and greater of gcj provide a runtime tool to enable natively compiled Java code to 
be used as a shared library if that code has been compiled with the new -findirect-dispatch option. 
This resolves problems encountered due to the fact that many Java applications have no provisions 
for handling natively compiled code in the class loader. To create a shared library from a jar file, you 
would use a command such as the following:

$�gcj�-shared�-findirect-dispatch�-fjni�-fPIC�fib.jar�-o�fib.jar.so�

The -shared and -fPIC options are standard options used when creating shared libraries. The 
-findirect-dispatch option enables the new binary compatibility ABI (application binary interface) 
used in gcj 4.0 and better, and the -fjni option tells gcj to use JNI native methods rather than CNI.

�Tip   When creating shared libraries from jar files on ELF platforms, linker options such as -Wl,-Bsymbolic 
(which tell the linker to bind references to global symbols to the definition within the shared library) typically 
increase performance.

Once you have created the shared library file, you must use the gcj-dbtool command to add it 
to the database that maps jar files to shared libraries. To determine the default database used by gcj 
on your system, you use the gcj-dbtool command’s –p option, as in the following example:

�����$�gcj-dbtool�–p

/usr/lib64/gcj-4.2/classmap.db

You must be root to add entries to the global database, which you do using a command such as 
the following:

�����$�gcj-dbtool�-a�/usr/lib64/gcj-4.2/classmap.db�fib.jar�fib.jar.so

You can then access this jar file as a shared library from anywhere on your system. If it contains 
a main routine, you can also execute it directly. 

�Tip  The gcj-dbtool application uses the full pathname for the tar shared library entry. Make sure that any shared 
libraries that you have created from your jar files are built in the location from which you want others to be able to 
permanently access them.

GCC Java Support and Extensions
As mentioned previously, this book is not a tutorial or reference on writing Java applications—there 
are already plenty of books that do that job and do it well. However, when writing Java code that you 
will compile using the GCC Java compiler, you can take advantage of a number of extensions to Java 
VonHagen_5858 C04.fm  Page 93  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 93

through both the compiler itself and the standard Java library used by gcj and libgcj. This section 
highlights the most significant extensions that are provided by both as of the time this book was written 
and discusses some differences in behavior that you may see between Java as defined by the Java 
specification and the compilation and behavior of Java code compiled using the GCC Java compiler. 

Java Language Standard ABI Conformance
An ABI is the binary flipside of the application programming interface (API) defined by the Java 
datatypes, classes, and methods in the include files and libraries that are provided by a Java library 
implementation. A consistent binary interface is required in order for compiled Java applications to 
conform to the binary conventions used in associated Java libraries and related object files for things 
such as physical organization, parameter passing conventions, and naming conventions. This 
consistency is especially critical for specific language support routines, most notably those used for 
throwing or catching exceptions. 
Most recent Java compilers conform to a specific ABI, which effectively determines the execu-
tion environments in which code compiled with that compiler can execute correctly (modulo coding 
errors, of course—perhaps “execute as written” would be a more precise statement). Beginning with 
version 4.0 of the GCC, gcj conforms to the Java ABI as defined in the Java Language Specification.

Runtime Customization 
In addition to the standard Java CLASSPATH environment variable, gcj also uses another environment 
variable, GCJ_PROPERTIES, which is consulted at runtime by any binaries generated using gcj. This 
environment variable is intended to hold a list of assignments to global Java properties, such as 
those that would be set using a JVM’s –D option. The following code example provides a simple 
example of using this environment variable:
public�class�Test�{
�public�static�void�main(String[]�args)�{
���System.out.println("Property�foo.bar�value�is:"�+�System.getProperty("foo.bar"));
�}
}
Compiling this code in the standard manner and executing it with no value for GCJ_PROPERTIES 
does the right thing:
$�gcj�--main=Test�-o�wvhTest�Test.java
$�./wvhTest

Property�foo.bar�value�is:�null

$�export�GCJ_PROPERTIES="foo.bar=42"�
$�./wvhTest

Property�foo.bar�value�is:�42

The GCJ_PROPERTIES environment variable provides a convenient way to set application-specific 
property values when doing iterative testing of your Java applications and can also be used to set 
system properties such as java.version when testing existing applications that behave differently 
depending upon the value of a specific system property. 
VonHagen_5858 C04.fm  Page 94  Wednesday, June 21, 2006  6:14 AM

94 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

Getting Information About Java Source and Bytecode Files
GCC distributions that include gcj also include several other useful binaries. Probably the most 
commonly used of these is the GNU interpreter for Java, gij, which is discussed later in this chapter 
in the section “Using the GNU Interpreter for Java.” But GCC also includes two binaries that you can 
use to get information about Java source and class files. The next two sections provide general infor-
mation about using these utilities.

Getting Information About Java Files Using jv-scan
The jv-scan command provides a number of options that display selected information about a Java 
source file. Table 4-5 summarizes the available options for the jv-scan application.

Table 4-5. jv-scan Command-Line Options
Option Description
--complexity Prints the cyclomatic complexity of the input file, which corresponds to 
the number of paths through the methods in the input file.
--encoding NAME Specifies the encoding used in the input file.
--help Prints a help message that summarizes jv-scan options and then exits.
--list-class Lists all of the classes defined in the input file.
--list-filename Includes the name of the input file when listing class names using the 
--list-class option.
--no-assert Doesn't recognize the assert keyword.
-o FILE Specifies that jv-scan output be directed to the file FILE rather than 
to stdout.
--print-main Prints the name of the class containing a main method.
--version Prints the jv-scan version number and then exits.

Though much of this information can easily be determined by visually scanning your input file, 
the jv-scan utility is useful with complex input files containing multiple subclasses, especially for 
simplifying automated compilation, such as make and Ant compilation rules, as suggested by the 
following two equivalent statements:
$�gcj�Fibonacci.java�--main=Fibonacci–o�Fibonacci
$�gcj�Fibonacci.java�--main=`jv-scan�--print-main�Fibonacci.java`�-o�Fibonacci

Getting Information About Class Files Using jcf-dump
Conceptually similar to the jv-scan command, the jcf-dump application displays information about 
an existing class file containing platform-independent Java bytecode. The jcf-dump command 
provides a number of options that display selected information about a Java class file. Table 4-6 
summarizes the available options for the jcf-dump application.
VonHagen_5858 C04.fm  Page 95  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 95

Table 4-6. jcf-dump Command-Line Options

Option Description
--bootclasspath PATH Overrides the built-in class path, as discussed earlier in this chapter in 
the section titled “Constructing the Java Classpath.”
-c Includes disassembled method bodies in the jcf-dump output.
--classpath PATH Sets path to find .class files, as discussed earlier in this chapter in the 
section titled “Constructing the Java Classpath.”
--extdirs PATH Sets the path to the extensions directory, as discussed earlier in this 
chapter in the section titled “Constructing the Java Classpath.”
--help Prints a help message that summarizes jcf-dump options and then exits.
-IDIR Appends directory to the classpath, as discussed earlier in this chapter 
in the section titled “Constructing the Java Classpath” and more 
generally in Appendix A.
--javap Generates output in the format used by the standard javap Java class 
file disassembler.
-o FILE Specifies that jcf-dump output be directed to the file FILE rather than 
to stdout.
-v, --verbose Print extra information while running.
--version Prints the jcf-dump version number and then exits.

The jcf-dump command can be very useful when you are working with precompiled class files, 
or when you simply need summary information about the class files and methods defined in accom-
panying Java source files. The following is sample output from the jcf-dump application when 
examining the Fibonacci.class file used earlier in this chapter:
$�jcf-dump�Fibonacci.class
Reading�.class�from�Fibonacci.class.
Magic�number:�0xcafebabe,�minor_version:�3,�major_version:�45.

Access�flags:�0x21�public�super
This�class:�Fibonacci,�super:�java.lang.Object
Interfaces�(count:�0):

Fields�(count:�0):

Methods�(count:�3):

Method�name:"calcFibonacci"�Signature:�(int)int
Attribute�"Code",�length:55,�max_stack:5,�max_locals:2,�code_length:23
Attribute�"LineNumberTable",�length:14,�count:�3

Method�name:"<init>"�public�Signature:�(int)void
Attribute�"Code",�length:91,�max_stack:4,�max_locals:3,�code_length:55
Attribute�"LineNumberTable",�length:18,�count:�4
VonHagen_5858 C04.fm  Page 96  Wednesday, June 21, 2006  6:14 AM

96 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

Method�name:"main"�public�static�Signature:�(java.lang.String[])void
Attribute�"Code",�length:76,�max_stack:5,�max_locals:1,�code_length:40
Attribute�"LineNumberTable",�length:18,�count:�4

Attributes�(count:�1):
Attribute�"SourceFile",�length:2,�#67="Fibonacci.java"

Using the GNU Interpreter for Java
The GNU interpreter for Java, gij, is a binary Java interpreter that is included with GCC distributions 
that include Java support. The gij binary is a drop-in replacement for existing JVMs and other Java 
interpreters, modulo differences between the standard Java API and that provided by the Classpath 
project used by all GCC Java tools. In many cases, gij makes it easy for you to test existing class files 
in the gcj environment. For example, popular Java applications such as Eclipse are often executed 
using gij rather than a standard Java VM in order to deliver easily shippable, completely open source 
solutions. 
The gij interpreter provides a number of command-line options that are summarized in Table 4-7. 
In general, using gij from the command line to execute an existing class or jar file works exactly like 
using a standard JVM, as shown in the following example output:
$�javac�hello.java
$�java�Hello

Hello�World!

$�gij�Hello

Hello�World!

The gcj compiler’s –lgij command causes output binaries to link with the gij library, which 
gives those binaries the same execution characteristics used when executing class files with any JVM 
or Java interpreter, as shown in the following example:
$�gcj�-lgij�hello.java�-o�gij_hello
$./gij_hello�Hello

Hello�World!

Table 4-7. gij Command-Line Options
Option Description
-agentlib This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-agentpath This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
VonHagen_5858 C04.fm  Page 97  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 97

Table 4-7. gij Command-Line Options (Continued)

Option Description
-client This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-cp PATH, -classpath PATH These options set the initial classpath used for finding class and 
resource files. If specified, this option overrides any value set 
using the CLASSPATH environment variable. This option is ignored 
if the –jar option is specified. Note that gij does not support any of 
the other options used by gcj to modify the directories and search 
order in the Java classpath, as discussed earlier in this chapter in 
the section titled “Constructing the Java Classpath.”
-d32 This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-d64 This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-Dname[=value] This option defines a global system property named name with 
the value value. If no value is specified, the default value of the 
specified property is the empty string. System properties are 
initialized at the program’s startup and can be retrieved at runtime 
using the java.lang.System.getProperty method.
-debug This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
--fullversion This option causes gij to display detailed version information and 
then exit.
--help, -? . These options cause gij to display a short usage message and 
then exit.
-hotspot This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-jar This option tells gij that the filename specified on the command 
line is the name of a jar file, not a class file.
-javaagent This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-jrockit This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-ms=number This option is equivalent to –Xmsnumber and sets the initial heap 
size allocated by gij to size.
-mx=number This option is equivalent to –Xmxnumber and sets the maximum size 
of the heap that can be allocated by gij to size.
VonHagen_5858 C04.fm  Page 98  Wednesday, June 21, 2006  6:14 AM

98 C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R

Table 4-7. gij Command-Line Options (Continued)

Option Description
-noclassgc This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-noverify This option does not verify types or the compliance of Java 
bytecode with the Java Virtual Machine specification.
-server This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
--showversion This option prints the gij version number and then continues 
execution. This option is useful for capturing version number 
information in scripted test output.
-verbose, -verbose:class These options display a short message on stderr as each class 
is initialized.
-verify This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
-verifyremote This option is accepted but ignored by gij, and is present only for 
compatibility with existing application launch scripts that you 
want to test with gij rather than a JVM or other Java interpreter.
--version This option displays the gij version number and then exits.
-X This option causes gij to list all the supported options for setting 
execution parameters.
-Xmssize This option sets the initial heap size allocated by gij to size.
-Xmxsize This option sets the maximum size of the heap that can be allocated 
by gij to size.

Java and C++ Integration Notes
In addition to the standard JNI defined by the Java specification as a standard for writing native Java 
methods in C or C++, gcj provides an alternative Compiled Native Interface (CNI), which originally 
stood for the Cygnus Native Interface. This interface takes advantage of the fact that much of GCC’s 
Java support is very similar to its support for C++. This interface also makes it easy to call classes and 
methods written in C++, which is especially convenient if you already have access to C++ code that 
does what you want to do. 
Because GCC’s C++ and Java support use the same calling conventions and data layout, interoper-
ability between C++ and Java requires little manual intervention. CNI provides C++ classes for primitive 
Java types, includes functions to work with Java strings and arrays, delivers the gcjh command to 
generate C++ header files to map Java reference types to C++ types, and provides an API for calling 
Java methods from C++ programs. Extensive and detailed CNI documentation is provides online as 
part of the gcj sections of the latest GCC documentation at http://gcc.gnu.org/onlinedocs. 
VonHagen_5858 C04.fm  Page 99  Wednesday, June 21, 2006  6:14 AM

C H A P T E R   4   �    U S I N G   G C C ’ S   J A V A   C O M P I L E R 99

One significant consideration is that the gcj runtime requires a certain amount of initializa-
tion, which you can make sure will happen if your main method is a Java method. If you prefer 
to call Java from C++ main code, you will have to use functions such as JvCreateJavaVM() and 
JvAttachCurrentThread() to manually create a virtual JVM instance and attach to it (which will do 
the necessary initialization) before making Java calls. See the extensive (and excellent) CNI docu-
mentation for additional details.

You might also like