< Zurück | Inhalt | Weiter >

7.4.2 Compiling a Multiclass Program

For contrast, Example 7.2 shows compiling a multiclass program that is contained in a package (it is the Payback debt/savings/purchase calculator).12


Example 7.2 Compiling and running a multiclass program

$ cd payback/src

$ gcj -o payback -I. --main=net.multitool.Payback.Payback \ net/multitool/Payback/Payback.java

$ ./payback

Payback -- A savings/credit comparison tool

Copyright (C) 2003 by Carl Albing and Michael Schwarz Released under the GNU/GPL. Free Software.







The -I switch names a directory that is to be prepended to the classpath. In this case, we added “.” which is the source directory for the Payback program.13 Notice the package elements expressed with dots for the --main argument, and with slashes for the filename argument.


The gcj compiler does pick up and use the CLASSPATH environment variable if it is specified. Also, gcj has a number of switches besides -I for classpath manipulation. We won’t cover those here; -I is the preferred method (according to the gcj manpage at any rate).


12. Since this chapter was written, XML features were added to Payback that make it no longer work with gcj.

13. The Payback code can be found at the book’s Web site: http://www.javalinux- book.com/.


7.5 Options and Switches 185


As we have said, gcj is part of the gcc suite of compilers and therefore supports all of the non-language-specific options and switches of that suite.

As with most reference material in this book, we will only cover the highlights. See the gcj manpage or the project’s Web site for full details.14


Add dirname to the classpath ahead of its existing contents.


Add name and optional value to the system properties list. This is only valid with the --main switch.


Specifies which class contains the application’s main(). This gives the starting point for an application.


Disable array bounds checking. Like “real” Java, gcj checks all array oper- ations to ensure that array bounds are not exceeded. Using this switch disables that check. It speeds up array operations but can introduce subtle and hard-to-find bugs. Use at your own risk.


Like -fno-bounds-check, this disables a safety feature on arrays. Normal- ly, when you store an object into an array, a check is made to make sure that the object is assignment-compatible with the array type (in other words, that the object is an instanceof() of the array type). Using this switch disables this test. It speeds up array operations but can introduce subtle and hard-to-find bugs. Use at your own risk.

There are other switches for native methods, bytecode (as opposed to native) compilation, and some switches related to resources. We leave it as an exercise for the reader to learn and use these where needed.


14. http://gcc.gnu.org/java/


You might think that speed would be the primary reason to use gcj, but this is not necessarily the case. Yes, gcj is usually used as a native code compiler (it can compile to Java bytecode as well, and thus can be used as a replacement for javac), but there is a lot more to Java performance than that. First off, both Sun’s and IBM’s JVMs have JIT (“Just-In-Time”) compilers in them, which convert some or all of a class’s bytecode to native code on the fly. In some cases, these compilers may do a better job than the gcj compiler, so as a result, initial runs under a JVM are slower than gcj but later loops or iterations are compara- ble or faster. Also performance of both gcj and JVM code is highly affected by memory, stack, and garbage-collection parameters which may be modified with command-line options or properties files. So speed is not the determining fac- tor. We have not done sufficient testing or measurement to tell you which en- vironment produces “the fastest code” from a given source file. (We’re not even sure exactly what such “sufficient testing” might consist of. All we can suggest is that your try your code in all three environments and then make your own choice.)

It is, perhaps, ironic that one of the main reasons why you might wish to use gcj is portability. You see, you can only run Sun’s and IBM’s JVMs on platforms for which they provide a compiled version. Linux runs on several hardware platforms (such as StrongARM) for which Sun and/or IBM do not provide JVMs. Also, if you are running Linux on some architectures, there may be VMs for the “official” OS, but none for Linux on that architecture. This is the case, for example, for SPARC and Alpha. The cross-compilation that gcj inherits from the GNU Compiler Collection allows you to compile Java to native code for Linux on those platforms.

Another reason to use gcj might be a desire for better integration with code compiled from other languages. gcj has JNI support, but also provides its own inter-language integration system called CNI, for Compiled Native Inter- face. We don’t have space to cover CNI (and, frankly, we haven’t used it enough to be good judges), but its proponents claim that it is both easier to use and more efficient than JNI. You can read up, use it, and judge that for yourself.

Still another reason might be one that we don’t like very much. Again, it is ironic that the only Free Software Java compiler is the one best able to pro- duce proprietary binary code. Code compiled with gcj is as difficult to reverse engineer as compiled C or C++ code. It is subject to the same sort of binary


7.9 What You Still Don’t Know 187

obfuscation as other native compiled code. If you need to make your code closed and proprietary, gcj may be the right tool for you. Naturally, we aren’t very fond of this idea, but it is still a reason one might choose the tool.

Finally, we mentioned that speed wasn’t a certain factor for choosing gcj, but there is an exception. So far,15 Java is particularly slow at starting and shutting down virtual machines. If you have a Java program that is invoked on demand or in a loop and the VM is started and stopped on each invocation, then gcj will give you a huge speed improvement, even if the code executes at the same speed or slightly slower than the JIT JVM code.


We can think of three reasons not to use gcj. First, the compiled binary will run only on the target platform, whereas a Java bytecode binary is portable to any Java runtime without modification or recompilation. Second, gcj is not definitive. Sun still “owns” Java and only Sun’s implementation can be pre- sumed to be “correct.” Third, the gcj API classes are not complete. If you visit the API status page we mentioned earlier, you can see what is provided and what is not. If gcj lacks an API your application requires, then you can be sure gcj is not the tool for you.


The GNU Compiler for Java is part of the GNU Compiler Collection. It is generally used to compile Java source code into native binaries. It provides many of Sun’s API classes, but not all.


You do not know how to interface with C/C++ code using gcj. You do not know how to use SWT from Eclipse to write GUI apps with gcj.


15. Sun claims that Java 5.0 will show considerable improvement in VM initialization speed.


There are a number of resources for gcj, including

• The gcj home page.16

• The gcj FAQ.17

• The gcj documentation page.18

• The JDK1.4 to libgcj comparison page.19 This resource is particularly useful in deciding whether gcj is an appropriate tool for compiling your program.

• Many features of gcj are, in fact, “inherited” from the parent project, the GNU Compiler Collection. You can find your way to a lot of good information from the GCC home page.20


16. http://gcc.gnu.org/java/

17. http://gcc.gnu.org/java/faq.php

18. http://gcc.gnu.org/java/docs.php

19. http://gcc.gnu.org/java/jdk14-libgcj.php

20. http://gcc.gnu.org/