Compiling Java with GCJ

January 1st, 2003 by Per Bothner in

Although Java isn't a popular choice for free projects, GJC can make it a viable option.
Your rating: None Average: 4.2 (16 votes)

Java has not become as pervasive as the original hype suggested, but it is a popular language, used a lot for in-house and server-side development and other applications. Java has less mind-share in the free software world, although many projects are now using it. Examples of free projects using Java include Jakarta from the Apache Foundation (jakarta.apache.org), various XML tools from W3C (www.w3.org) and Freenet (freenet.sourceforge.net). See also the FSF's Java page (www.gnu.org/software/java).

One reason relatively few projects use Java has been the real or perceived lack of quality, free implementations of Java. Two free Java implementations, however, have been around since the early days of Java. One is Kaffe (www.kaffe.org), originally written by Tim Wilkinson and still developed by the company he cofounded, Transvirtual. The other is GCJ (the GNU Compiler for the Java language), which I started in 1996 at Cygnus Solutions (and which this article discusses). GCJ has been fully integrated and supported as a GCC language since GCC version 3.0.

Traditional Java Implementation Model

The traditional way to implement Java is a two-step process: a translation phase and an execution phase. (In this respect Java is like C.) A Java program is compiled by javac, which produces one or more files with the extension .class. Each such file is the binary representation of the information in a single class, including the expressions and statements of the class' methods. All of these have been translated into bytecode, which is basically the instruction set for a virtual, stack-based computer. (Because some chips also have a Java bytecode instruction set, it also can be a real instruction set.)

The execution phase is handled by a Java Virtual Machine (JVM) that reads in and executes the .class files. Sun's version is called plain “java”. Think of the JVM as a simulator for a machine whose instruction set is Java bytecodes.

Using an interpreter (simulator) adds quite a bit of execution overhead. A common solution for high-performance JVMs is to use dynamic translation or just-in-time (JIT) compilers. In that case, the runtime system will notice a method has been called enough times to make it worthwhile to generate machine code for that method on the fly. Future calls to the method will execute the machine code directly.

A problem with JITs is startup overhead. It takes time to compile a method, especially if you want to do any optimization, and this compilation is done each time the application is run. If you decide to compile only the methods most often executed, then you have the overhead of measuring those. Another problem is that a good JIT is complex and takes up a fair bit of space (plus the generated code needs space, which may be on top of the space used by the original bytecode). Little of this space can be in shared memory.

Traditional Java implementation techniques also do not interoperate well with other languages. Applications are deployed differently (a Java Archive .jar file, rather than an executable); they require a big runtime system, and calling between Java and C/C++ is slow and inconvenient.

The GCJ Solution: Ahead-of-Time Compilation

The approach of the GCJ Project is radically traditional. We view Java as simply another programming language and implement it the way we implement other compiled languages. As Cygnus had been long involved with GCC, which was already being used to compile a number of different programming languages (C, C++, Pascal, Ada, Modula2, Fortran, Chill), it made sense to think about compiling Java to native code using GCC.

On the whole, compiling a Java program is actually much simpler than compiling a C++ program, because Java has no templates and no preprocessor. The type system, object model and exception-handling model are also simpler. In order to compile a Java program, the program basically is represented as an abstract syntax tree, using the same data structure GCC uses for all of its languages. For each Java construct, we use the same internal representation as the equivalent C++ would use, and GCC takes care of the rest.

GCJ can then make use of all the optimizations and tools already built for the GNU tools. Examples of optimizations are common sub-expression elimination, strength reduction, loop optimization and register allocation. Additionally, GCJ can do more sophisticated and time-consuming optimizations than a just-in-time compiler can. Some people argue, however, that a JIT can do more tailored and adaptive optimizations (for example, change the code depending on actual execution). In fact, Sun's HotSpot technology is based on this premise, and it certainly does an impressive job. Truthfully, running a program compiled by GCJ is not always noticeably faster than running it on a JIT-based Java implementation; sometimes it even may be slower, but that usually is because we have not had time to implement Java-specific optimizations and tuning in GCJ, rather than any inherent advantage of HotSpot technology. GCJ is often significantly faster than alternative JVMs, and it is getting faster as people improve it.

A big advantage of GCJ is startup speed and modest memory usage. Originally, people claimed that bytecode was more space-efficient than native instruction sets. This is true to some extent, but remember that about half the space in a .class file is taken up by symbolic (non-instruction) information. These symbols are duplicated for each .class file, while ELF executables or libraries can do much more sharing. But where bytecodes really lose out to native code is in terms of memory inside a JVM with a JIT. Starting up Sun's JVM and JIT compiling and applications' classes take a huge amount of time and memory. For example, Sun's IDE Forte for Java (available in the NetBeans open-source version) is huge. Starting up NetBeans takes 74MB (as reported by the top command) before you actually start doing anything. The amount of main memory used by Java applications complicates their deployment. An illustration is JEmacs (JEmacs.sourceforge.net), a (not very active) project of mine to implement Emacs in Java using Swing (and Kawa, discussed below, for Emacs Lisp support). Starting up a simple editor window using Sun's JDK1.3.1 takes 26MB (according to top). XEmacs, in contrast, takes 8MB.

Running the Kawa test suite using GCJ vs. JDK1.3.1, GCJ is about twice as fast, causes about half the page faults (according to the time command) and uses about 25% less memory (according to top). The test suite is a script that starts the Java environment multiple times and runs too many different things for a JIT to help (which penalizes JDK). It also loads Scheme code interactively, so GCJ has to run it using its interpreter (which penalizes GCJ). This experiment is not a real benchmark, but it does indicate that even in its current status you can get improved performance using GCJ. (As always, if you are concerned about performance, run your own benchmark based on your expected job mix.)

GCJ has other advantages, such as debugging with GDB and interfacing with C/C++ (mentioned below). Finally, GCJ is free software, based on the industry-standard GCC, allowing it to be freely modified, ported and distributed.

Some have complained that ahead-of-time compilation loses the big write-once, run-anywhere portability advantage of bytecodes. However, that argument ignores the distinction between distribution and installation. We do not propose native executables as a distribution format, expect perhaps as prebuilt packages (e.g., RPMs) for a particular architecture. You still can use Java bytecodes as a distribution format, even though they don't have any major advantages over Java source code. (Java source code tends to have fewer portability problems than C or C++ source.) We suggest that when you install a Java application, you should compile it to native code if it isn't already so compiled.

Compiling a Java Program with GCJ

Using GCC to run a Java program is familiar to anyone who has used it for C or C++ programs. To compile the Java program MyJavaProg.java, type:

gcj -c -g -O MyJavaProg.java

To link it, use the command:

gcj --main=MyJavaProg -o MyJavaProg MyJavaProg.o
This is just like compiling a C++ program mycxxprog.cc:
g++ -c -g -O mycxxprog.cc
and then linking to create an executable mycxxprog:
g++ -o mycxxprog mycxxprog.o
The only new aspect is the option --main=MyJavaProg. This is needed because it is common to write Java classes containing a main method that can be used for testing or small utilities. Thus, if you link a bunch of Java-compiled classes together, there may be many main methods, and you need to tell the linker which one should be called when the application starts.

You also have the option of compiling a set of Java classes into a shared library (.so file). In fact, the GCJ runtime system is compiled to a .so file. While the details of this belong in another article, if you are curious you can look at the Makefiles of Kawa (discussed below) to see how this works.

Features and Limitations of GCJ

GCJ is not only a compiler. It is intended to be a complete Java environment with features similar to Sun's JDK. If you specify the -C option to gcj it will compile to standard .class files. Specifically, the goal is that gcj -C should be a plugin replacement for Sun's javac command.

GCJ comes with a bytecode interpreter (contributed by Kresten Krab Thorup) and has a fully functional ClassLoader. The standalone gij program works as a plugin replacement for Sun's java command.

GCJ works with libgcj, which is included in GCC 3.0. This runtime library includes the core runtime support, Hans Boehm's well-regarded conservative garbage collector, the bytecode interpreter and a large library of classes. For legal and technical reasons, GCJ cannot ship Sun's class library, so it has its own. The GNU Classpath Project now uses the same license and FSF copyright that libgcj and libstdc++ use, and classes are being merged between the two projects. We use the GPL but with the special exception that if you link libgcj with other files to produce an executable, this does not by itself cause the executable to be compiled by the GPL. Thus, even proprietary programs can be linked with the standard C++ or Java; runtime libraries.

The libgcj library includes most of the standard Java classes needed to run non-GUI applications, including all or most of the classes in the java.lang, java.io, java.util, java.net, java.security, java.sql and java.math packages. The major missing components are classes for doing graphics using AWT or Swing. Most of the higher-level AWT classes are implemented, but the lower-level peer classes are not complete enough to be useful. Volunteers are needed to help out.

Interoperating with C/C++

Although you can do a lot using Java, sometimes you want to call libraries written in another language. This could be because you need to access low-level code that cannot be written to Java, an existing library provides functionality that you need and don't want to rewrite, or you need to do low-level performance hacks for speed. You can do all of these by declaring some Java methods to be native and, instead of writing a method body, provide an implementation in some other language. In 1997, Sun released the Java Native Interface (JNI), which is a standard for writing native methods in either C or C++. The main goal of JNI is portability in the sense that native methods written for one Java implementation should work with another Java implementation, without recompiling. This was designed for a closed-source, distributed-binaries world and is less valuable in a free-software context, especially because you do have to recompile if you change chips or the OS type.

To ensure JNI's portability, everything is done indirectly using a table of functions. This makes JNI very slow. Even worse, writing all these functions and following all the rules is tedious and error-prone. Although GCJ does support JNI, it also provides an alternative. The Compiled Native Interface (CNI, which could also stand for Cygnus Native Interface) is based on the idea that Java is basically a subset of C++ and that GCC uses the same calling convention for C++ and Java. So, what could be more natural than being able to write Java methods using C++ and using standard C++ syntax for access to Java fields and calls to Java methods? Because they use the same calling conventions and data layout, no conversion or magic glue is needed between C++ and Java.

Examples of CNI and JNI will have to wait for a future article. The GCJ manual (gcc.gnu.org/onlinedocs/gcj) covers CNI fairly well, and the libgcj sources include many examples.

Kawa: Compiling Scheme to Native via Java

Java bytecodes are a fairly direct encoding of Java programs not really designed for anything else. However, they have been used to encode programs written in other languages. See grunge.cs.tu-berlin.de/~tolk/vmlanguages.html for a list of other programming languages implemented on top of Java. Most of these are interpreters, but a few actually compile to bytecode. The former could use GCJ as is; the latter potentially can use GCJ to compile to native code.

One such compiler is Kawa, which I have been developing since 1996. Kawa is both a toolkit for implementing languages using Java and an implementation of the Scheme programming language. You can build and run Kawa using GCJ without needing any non-free software. The Kawa home page (www.gnu.org/software/kawa) has instructions for downloading and building Kawa with GCJ.

You can use Kawa in interactive mode. Here, we first define the factorial function and then call it:

$ kawa
#|kawa:1|# (define (factorial x)
#|(---:2|#  (if (< x 2) x (* x (factorial (- x 1)))))
#|kawa:3|# (factorial 30)
265252859812191058636308480000000

An interesting thing to note is the factorial function actually gets compiled by Kawa to bytecode and is immediately loaded as a new class. This process uses Java's ClassLoader mechanism to define a new class at runtime for a byte array containing the bytecodes for the class. The methods of the new class are interpreted by GCJ's bytecode interpreter.

Of course, it is usually more convenient to put the code in a file:

$ cat > factorial.scm
(define (factorial x)
(if (< x 2) x (* x (factorial (- x 1)))))
(format #t "Factorial ~d is ~d.~%~!" 30 (factorial 30))
^D
$ kawa -f factorial.scm
Factorial 30 is 265252859812191058636308480000000.

You can increase the performance of Scheme code by using Kawa to compile it ahead of time, creating one or more .class files:

$ kawa --main -C factorial.scm
(compiling factorial.scm)
You can then load the compiled file:
$ kawa -f factorial.class
Factorial 30 is 265252859812191058636308480000000.
To compile the class file to native code, you can use gckawa, a script that sets up appropriate environment variables (LD_LIBRARY_PATH and CLASSPATH) and calls gcj:
$ gckawa -o factorial
--main=factorial -g -O factorial*.class
Using the wildcard in factorial*.class is not needed in this case, but it is a good idea in case Kawa needs to generate multiple .class files.

Then, you can execute the resulting factorial program, which is a normal GNU/Linux ELF executable. It links with the shared libraries libgcj.so (the GCJ runtime library) and libkawa.so (the Kawa runtime library).

The same approach can be used for other languages. For example, I am currently working on implementing XQuery, W3C's new XML-query language, using Kawa.

Other applications that have been built with GCJ include Apache modules, GNU-Paperclips and Jigsaw.

Conclusion

GCJ has seen a lot of activity recently and is a solid platform for many tasks. We hope that you consider Java for your free software project, using GCJ as your preferred Java implementation and that some of you will help make GCJ even better.

email: per@bothner.com

Per Bothner (www.bothner.com/per) has worked on GNU software since the 1980s. At Cygnus he was technical leader of the GCJ Project. He is currently an independent consultant.

__________________________


Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer

Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Jerry McBride's picture

Excellent...

On April 12th, 2009 Jerry McBride says:

Thank you for the mini tutorial. It's been most illuminating. I'm now running all of my java apps "natively"! Couldn't have done it without this!!

Jerry

__________________________

---- Jerry McBride

Anonymous's picture

Excuse for the stupid

On April 9th, 2009 Anonymous (not verified) says:

Excuse for the stupid question, please!

Can you tell me how to compile an operating system with gcj?

Anonymous's picture

This page saves my life! Very

On September 26th, 2005 Anonymous (not verified) says:

This page saves my life! Very nice page!

Mehdi's picture

Dynamic loading

On September 25th, 2005 Mehdi (not verified) says:

GCJ is great, I just need to understand how to achieve "post deployment" dynamic loading.
I mean, doing something like plugins for the eclipse IDE. You can add plugins (mainly jar files) to the eclipse IDE that is already deployed! As long as the plugin implements some Interface, it can be dynamically loaded by eclipse IDE and the functionality provided by that plugin is available to Eclipse users. This is just classic Java.
As far as I can understand, it is perfectly possible to do that with GCJ. However I had a problem.

I tried to use Class.forName("myC"); which worked fine. However the program doesn't see all classes, but only the ones that where there when the main was compiled. If I add some more classes in the right folder that implement the right interface, and re-run the program it doesn't accept those new class files at all (I raise an exception when the object cannot be created).

Has anyone succeeded in making EXE produced by GCJ accept some new classes/jars (either .class, or preferably in some dll,...) after the EXE was deployed.
Anything I should be aware of? any special flag??

Thanks in advance

Anonymous's picture

I able to compiled my java ap

On August 11th, 2005 Anonymous (not verified) says:

I able to compiled my java app with gcj, but unable to run it properly. The app required 4 arguments two of which are required for FileInputStream and FileOutputStream, also has several imports

import javax.crypto.*;
import javax.crypto.spec.*;

if I run with Java command " java MyApp mode inputstream output text", the app run perfectly, but when i ran after compile with GCJ
"MyApp.exe mode inputstream output text" its does not work. It does not produced same result as java commandline. Any ideas?

Thankx

Anonymous's picture

I have just the same

On November 4th, 2005 Anonymous (not verified) says:

I have just the same problem, with FileOutputStream.

Anonymous's picture

ld.exe cannot find -lgdi32

On July 30th, 2005 Anonymous (not verified) says:

Set your PATH with 'start\control panel\System'
Select the Advanced tab, Environment Variables;
Add the System variable GCJ= c:\gcc-4.0
Add the System variable GCJ_BIN= %GCJ%\bin;%GCJ%\i686-pc-mingw32\bin ;%GCJ%\i686-pc-mingw32\ming32\bin;%GCJ%\libexec\gcc\i686-pc-mingw32\4.0.0;

Select the System variable Path and edit it.
Add %GCJ_DIR%;
to the variable.

Restart eclipse.

Anonymous's picture

get a error with GCJ

On June 10th, 2005 Anonymous (not verified) says:

gcj --main=HelloWorld -o HelloWorld.exe obj\HelloWorld.o -Lf:\swt

(this instruction get automatic this)
f:\gcj\thisiscool-gcc\gcc-4.0\bin\..\lib\gcc\i686-pc-mingw32\4.0.0\..\..\..\..\i
686-pc-mingw32\bin\ld.exe: cannot find -lgdi32
and the exe is not there

Anonymous's picture

re: get a error with GCJ

On July 20th, 2005 Anonymous (not verified) says:

The problem seems to be the bundle that you are using for gcj, (ie www.thisiscool.com) Version 4.0.0 is missing elements from the runtime - Download the w32api-3.2 from http://www.mingw.org/download.shtml will resolve this problem.

Nik

Anonymous's picture

get a error with GCJ

On June 21st, 2005 Anonymous (not verified) says:

Install the "Microsoft Platform SDK" and make sure that the /lib directory from the SDK is in your library path.

Anonymous's picture

I get the same error too. :(

On June 16th, 2005 Anonymous (not verified) says:

I get the same error too. :(

Anonymous's picture

Re: Piece of Crap

On July 11th, 2005 Anonymous (not verified) says:

GCJ is a piece of crap!!!

Anonymous's picture

hahahaha what a useless

On November 4th, 2005 Anonymous (not verified) says:

hahahaha what a useless comment.

(not that this is any better)

Nihilist's picture

More information

On June 7th, 2005 Nihilist (not verified) says:

I ran into a few problems while trying to make this work. First of all, I'm using MingW's gcj, not Cygwin. (Cuz I don't like carrying cygwin1.dll around with me.) MingW doesn't come with an iconv implementation, so you have to download the 'binaries' and 'developer files' from here: http://gnuwin32.sourceforge.net/packages/libiconv.htm.

Second problem was the fact that I created my first app with a package. The article doesn't tell you what happens when you do that. Let me try to explain.

You create a Java source file, called Main.java, with the package test.foo. A sample:
package test.foo;

public class Main {
public static void main(String[] args) {
System.out.println("The world says hi!");
}
}

Using GCJ, you turn it into an object using:
gcj -c -g -O Main.java
This step will work without a problem.

However, when you go to turn the object into an executable, the problems will begin. If you try to use the following command:
gcj --main=Main -o Test Main.o
It'll chuck some obnoxious error.

Turns out that you have to tell it the package for the main class:
gcj --main=test.foo.Main -o Test Main.o

Should work fine now.

lofloa's picture

Where to put JDBC jar file when connecting to MySQL

On April 13th, 2005 lofloa (not verified) says:

Hi,

I am trying to use the JDBC connector for MySQL. The java program compiles and links ok with gcj but when I run it is not seeing the jar file where all the classes for the connection are defined.

Where should I put this file?

In the 'standard' java environment I put them in the jre/lib/ext folder.

What's the equivalent under gcj?

Thanks,

Francisco

Anonymous's picture

Is there an official comparison with JDK 5.0 or 1.4.2?

On February 10th, 2005 Anonymous (not verified) says:

There are official comparisons with 1.4.2 when it comes to GNU Classpath. But none for GCJ. Is there a way to make that available? Also, why aren't GNU Classpath APIs distributed as native code using GCJ?

V
Java Technologies

Aanand's picture

MinGW GCJ

On January 17th, 2005 Aanand (not verified) says:

I am using MinGW 3.2. And I tried to compile my java program to native executable.

This is the command i issued. But it said "cannot find -l iconv ". What should i do to compile the program correctly.

$ gcj -g -O MyNewClass.java
d:\MinGW\bin\..\lib\gcc\mingw32\3.4.2\..\..\..\..\mingw32\bin\ld.exe: cannot find -liconv
collect2: ld returned 1 exit status

Thanks in advance.

Anonymous's picture

try: 1. download from http:/

On February 10th, 2005 Anonymous (not verified) says:

try:
1. download from http://gnuwin32.sourceforge.net/packages/libiconv.htm
"Binaries" AND "Developer files"
2. install "Binaries" to directory where is mingw installed (not to proposed GnuWin32 directory), so finally /bin from "Binaries" matches /bin from mingw, /lib to /lib, etc...
3. unpack "Developer files" to mingw directory, /lib to /lib from mingw ..., as above
seems to work...

jishin's picture

It's Worked... thank you

On April 18th, 2006 jishin (not verified) says:

It's Worked... thank you

Anonymous's picture

Re: Compiling Java with GCJ

On October 21st, 2004 Anonymous says:

I can't find out how to get this gcj stuff!

Raj Kumar Sanpui's picture

gcj is a free compiler

On October 16th, 2007 Raj Kumar Sanpui (not verified) says:

gcj is a free compiler available with almost all flavours of linux.
It comes with gcc (GNU collection of compilers).

Raj Kumar Sanpui's picture

gcj is a free compiler

On October 16th, 2007 Raj Kumar Sanpui (not verified) says:

gcj is a free compiler available with almost all flavours of linux.
It comes with gcc (GNU collection of compilers).

Raj Kumar Sanpui's picture

gcj is a free compiler

On October 16th, 2007 Raj Kumar Sanpui (not verified) says:

gcj is a free compiler available with almost all flavours of linux.
It comes with gcc (GNU collection of compilers).

Anonymous's picture

Re: Compiling Java with GCJ

On July 5th, 2004 Anonymous says:

My application needs to set the memory usage. I use
java -jar -Xms256m -Xmx384m myapplication.jar

Is there any way to set these parameters when I compile my application using GCJ?

Anonymous's picture

Re: Compiling Java with GCJ

On May 19th, 2004 Anonymous says:

Can we expect the AWT toolkit for windows will be implemented in future releases?

Anonymous's picture

Re: Compiling Java with GCJ

On June 18th, 2004 Anonymous says:

AWT isn't supported yet but SWT works with GCJ, and I like it MUCH better than AWT or even Swing.

Here's the how-to:
http://www-106.ibm.com/developerworks/java/library/j-nativegui2/

Go to eclipse.org to get SWT.

Anonymous's picture

Re: Compiling Java with GCJ

On April 20th, 2004 Anonymous says:

The real trick is not compiling with gcj, but getting the compiled application to run. I have yet to find documention indicating what classpaths should be used to avoid errors like this:

java.awt.AWTError: Cannot load AWT toolkit: gnu.awt.gtk.GtkToolkit not found in [file:./, core:/]
>
java.awt.AWTError: Cannot load AWT toolkit: gnu.awt.gtk.GtkToolkit not found in [file:./, core:/]
>

Anonymous's picture

Re: Compiling Java with GCJ

On May 28th, 2004 Anonymous says:

Graphical applications are not yet supported. AWT/Swing does not work. Sorry...

--Nathan Chilton

Anonymous's picture

Re: Compiling Java with GCJ

On October 11th, 2004 Anonymous says:

From I've been able to gather so far, is graphical applications are indeed supported. Many applets work out out of the box. But only on some platforms. It seems in the official versions, cygwin is disabled from building libjava all together. Only hacked versions are able to build libjava, and those do not seem to support the graphical components.

However, my search is not complete. Maybe somewhere there is a version gcj source which will build completely for cygwin.

Bill

Anonymous's picture

Re: Compiling Java with GCJ

On September 9th, 2004 Anonymous says:

It looks to me like all the swing components are present and compiles Ok why is it not available and what is stopping it? I have a project I would very much like to use this on and I don't understand if all is present why it is not available. Please explain. This is the very same message I get from the Kaffe VM.

Anonymous's picture

Re: Compiling Java with GCJ

On February 4th, 2005 Anonymous (not verified) says:

The real trick is not compiling with gcj, but getting the compiled application to run. I have yet to find documention indicating what classpaths should be used to avoid errors like this:

java.awt.AWTError: Cannot load AWT toolkit: gnu.awt.gtk.GtkToolkit not found in [file:./, core:/]
>
java.awt.AWTError: Cannot load AWT toolkit: gnu.awt.gtk.GtkToolkit not found in [file:./, girlscore:/]
>

Anonymous's picture

Re: Compiling Java with GCJ

On March 30th, 2004 Anonymous says:

Hi, I'm interested in this utility. But...there seems to be much to do with the libgcj, which provide the gcj version of java libraries.

See, I've used both method String.replaceAll and the java.util.regex package in my project, but found neither is supported by gcj now. I'm using gcj version 3.3.1 under cygwin, on Windows 2000. Though the simplest HelloWorld works well, my real project failed. That's sad news for me.

Are there any available supports for both of these features?

Anonymous's picture

Re: Compiling Java with GCJ

On October 7th, 2003 Anonymous says:

I've tried gcj on a test program and it compiled and ran beautifully ... as long as I ran it with C:cygwinin in my path. Otherwise it couldn't find required dll's ('cywin1.dll', etc).

It doesn't look as though I can give the .exe to someone else and expect them to be able to run it unless they have cygwin installed and in their path - which defeats my purpose.

Is there a way around this?

Thanks, Nathan

Anonymous's picture

Re: Compiling Java with GCJ

On September 1st, 2004 Anonymous says:

yes, there is a way around this. Include -mno-cygwin option when you compile.
Example:

gcj --main=Hello -mno-cygwin -o Hello Hello.java

The main option tells which class file is to be used as the starting file, just in case there are more than one class files that have their own main.

hope this helps.

Anonymous's picture

Re: Compiling Java with GCJ

On February 2nd, 2004 Anonymous says:

You just have to give them the compiled executable plus the cygwin dlls...

Anonymous's picture

Re: Compiling Java with GCJ

On March 14th, 2004 Anonymous says:

just with a -mno-cygwin solves everything

Anonymous's picture

Re: Compiling Java with GCJ

On November 8th, 2003 Anonymous says:

Use the MINGW-version of GCJ, which doesn't require cygwin1.dll. Works very well and can be used in commercial projects. Creates one single self-contained win32-executable.

-- Mattiasw

Ivan R. Ch's picture

I can't compile using the GCJ distribution

On June 10th, 2005 Ivan R. Ch (not verified) says:

I've trying to compile just the hello world, and when I try to link, get this error:
gcj --main=HelloWorld -o HelloWorld.exe obj\HelloWorld.o -Lf:\swt
:\gcj\thisiscool-gcc\gcc-4.0\bin\..\lib\gcc\i686-pc-mingw32\4.0.0\..\..\..\..\i
86-pc-mingw32\bin\ld.exe: cannot find -lgdi32

I dont know why, what I need to make the exe ?

Anonymous's picture

Re: Compiling Java with GCJ

On November 3rd, 2003 Anonymous says:

How about compiling statically? You just get a huge binary

Anonymous's picture

Re: Compiling Java with GCJ

On August 4th, 2003 Anonymous says:

Some questions:

* how well does getClass() work?
ie given an object, o, is this supported?
Class c = o.getClass();

* is instanceof supported?
if (o instanceof MyWidget) {...}

* how well does gcj handle run-time class loading?
eg Class c = Class.forName("com.acme.Widget");

* how well does gcj handle run-time reflection?
eg can code query the methods available on class C?
can they be dynamically invoked?

* are multiple class-loaders supported?
eg: if a class has a static member, and it is explicitly loaded
via two different class-loaders, are there two separate
instances of the static member variable? (there should be).

* is dynamic class generation supported?
Java 1.4 provides "dynamic adapters" as an alternative
to using inner classes as adapters. I believe these
generate (simple) new classes on the fly.

Thanks,

Simon

Anonymous's picture

Re: Compiling Java with GCJ

On September 29th, 2003 Anonymous says:

* how well does getClass() work?
ie given an object, o, is this supported?
Class c = o.getClass();

It works just fine.

* is instanceof supported?
if (o instanceof MyWidget) {...}

Of course. I doubt any non-trivial Java apps would work if this wasn't the case!

* how well does gcj handle run-time class loading?
eg Class c = Class.forName("com.acme.Widget");

Very well. Your class can be in a shared library, which will be automatically loaded by Class.forName(). Alternatively, you can even mix bytecode (.class files) with native compiled Java.

* how well does gcj handle run-time reflection?
eg can code query the methods available on class C?
can they be dynamically invoked?

Reflection and Invocation are fully supported.

* are multiple class-loaders supported?
eg: if a class has a static member, and it is explicitly loaded
via two different class-loaders, are there two separate
instances of the static member variable? (there should be).

Currently there may be bugs in this area, however they are being worked on. There is no fundamental reason why this shouldn't work.

* is dynamic class generation supported?
Java 1.4 provides "dynamic adapters" as an alternative
to using inner classes as adapters. I believe these
generate (simple) new classes on the fly.

Yes, dynamic proxies are supported.

Anonymous's picture

Re: Compiling Java with GCJ

On May 19th, 2003 Anonymous says:

Hi all-,
Am I the only one largely unimpressed by GCJ?
Most of the assumptions (like "not many OS projects") in the
begining of the article are hard to comprehend.
Start up time will improve when the JVM becomes part of the OS (like in Mac OS X) . This will happen in JDK1.5 and there is
no need for compilation to native code.
Speaking of which, how do you plan to transport classes over (let's) RMI in a JINI environment, between different CPUs?

C'mon ... no serious developer should by this! Get real.

Anonymous's picture

Re: Compiling Java with GCJ

On April 20th, 2004 Anonymous says:

I would love to know what OS you are using on your Mac that gives you a built in JVM. My MacOS X 10.3 (Panther) just has the JVM as an application level component, just like other platforms supported by Java. For applets, I actually find the fastest starting JVM that I use regularly is the Microsoft Virtual Machine, but only if I optimize the code to with a few tricks I have learned along the way. However, in most cases it is the time it takes to load and initialize the classes into an applet that is noticable, not the actual time it takes to load the JVM into memory.

On most platforms, Java is just in time compiled. My experience has been this speeds Java by about a factor of 2 to a factor of 6 depending on the application. On platforms where Java is not JIT compiled, such as J2ME or RedHat 7.1 you'll really notice the slowdown.

In theory, J2EE features can be implimented in the same way they are in a JVM. I do not really see a significant difference between "ahead of time compiling" as in "gcj" and "just in time compiling". It would be fairly trivial to compile a class as a shared object for dynamic loading at runtime.

Bill

Anonymous's picture

Re: Compiling Java with GCJ

On July 21st, 2003 Anonymous says:

I agree with the remarks about the beginning of the article. I would go further and criticize the claim that the two phase approach of Java is similar to C - it is much more similar to Basic with an initial compilation to a state that is later interpreted. Some may not like seeing Java compared to Basic or the original implementation of Pascal with p-code, but that is the Java model.

As a former OS internals developer, I wonder exactly what is supposed to be meant by "when the JVM becomes part of the OS" and how that is supposed to improve startup time to any great extent. It is the class load time and the byte code interpretation time that is the big issue here, not how long it takes to start the process running the JVM. Putting the JVM inside the kernel like a device driver would not be at all helpful in a virtual memory environment. Requiring a service trap from the application code to the kernel to get to the JVM would slow things down much more. If the claim is that putting the JVM on the same distribution CD as the OS will somehow speed things up, that does not make any sense. As for the JVM becoming part of the OS in JDK 1.5, I have not seen any announcement at www.java.sun.com about that. Besides, the JDK is irrelevant at runtime because the JRE is what interprets the byte codes in the class file.

As for transporting classes, a better example would be running Java classes inside a web browser for an applet. That is where the portability of Java classes is worth the cost at runtime to interpret everything or use a "not quite Just In Time" compiler that detects when too much time has been wasted and then optimizes code that may not run again.

In a servlet environment, noticing repeatedly executed code can have a payoff for future requests. For a Java application that runs for a while and then exits, the JIT optimizations are too late for any big payoff in performance.

Sun has resisted having Java be a compiled language all along. Whether this has helped them sell faster hardware is unknown but it certainly has slowed acceptance of Java in many cases. GCJ has the potential to be the perfect solution for cases where Java as source is desired but execution speed is important. This would allow source to be in a language that has many advantages, yet allow the installation to be specific to the hardware and OS for execution speed similar to C++.

Anonymous's picture

Re: Compiling Java with GCJ

On August 4th, 2003 Anonymous says:

Java hasn't been "interpreted" for a long while now. It is compiled "just-in-time", which is a totally different thing. The code that runs is real machine code for the actual processor type it is running on, unlike "p-code" or similar.

I don't know what the comment "when the JVM becomes part of the OS" comment means either. However there is a feature in Java1.5 where starting a new java application will *not* start a new JVM intance. Instead, it just loads the classes associated with the new application into an existing JVM. And a JVM can be left "idle in the background" when no java apps at all are running, so that when one is started it starts much quicker.

So whether you are running 1, 2, 5 or 50 java-based apps, there is only one JVM. This is possible because using different class-loaders can totally isolate applications from each other; they aren't aware that they are sharing a JVM.

Possible issues that I can see, though, involve:
* process priority ("nice" etc)
* process killing (kill -9)
* JNI libraries loaded by one app crashing the JVM

In many cases, however, sharing a JVM could be beneficial, particularly if the java standard libraries only need to be loaded once (and JIT'ed once).

Yes, the app itself still needs to be "JIT'ed" when run.

Anonymous's picture

Re: Compiling Java with GCJ

On June 23rd, 2003 Anonymous says:

Most people don't need to use RMI in a JINI environment. They just want something that works, nicely, for writing apps. They want a rich programming environment with overflow detection, garbage collection, and a nice simple, usable object model. You are right that for a lot of things Java is currently used for, gcj probably won't work, but for a lot of things C and C++ are used for, gcj will work *better*.

Anonymous's picture

Re: Compiling Java with GCJ

On June 2nd, 2003 Anonymous says:

Your vision of the uses for Java is very limited. There are times that we want to reuse code for Windows client apps from other types of apps and we don't want to re-write to C++ or VB or something.
GCJ (and other native compilers) are useful in these cases because we want to protect our source code (not all software is free.. some of us need to eat). Platform portability is not needed and not even desirable.
The Java class format and obfuscators are not good at protecting source code well enough. Native compilers are much better.
Also telling a user to copy one file is much easier than telling him to install a JVM, set the classpath, etc..
GCJ + SWT is very attractive.

Anonymous's picture

Re: Compiling Java with GCJ

On May 13th, 2003 Anonymous says:

Hallo ,
Can i import c++ code to java code using the cni interface and compile it to a class file (and how)??
Sbile

Anonymous's picture

Re: Compiling Java with GCJ

On March 12th, 2003 Anonymous says:

"Although Java isn't a popular choice for free projects [...]"

Yeah, sure... Number of projects registered at Sourceforge, by technology:

C (10368)

C++ (9957)

Java (8101)

Perl (4413)

PHP (6103)

Anonymous's picture

Re: Compiling Java with GCJ

On March 25th, 2004 Anonymous says:

Yea but how many of those have made it into a linux distrobution?

Post new comment

Please note that comments may not appear immediately, so there is no need to repost your comment.
The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <pre> <ul> <ol> <li> <dl> <dt> <dd> <i> <b>
  • Lines and paragraphs break automatically.

More information about formatting options

Newsletter

Each week Linux Journal editors will tell you what's hot in the world of Linux. You will receive late breaking news, technical tips and tricks, and links to in-depth stories featured on www.linuxjournal.com.
Sign up for our Email Newsletter

Tech Tip Videos

From the Magazine

July 2009, #183

News Flash: Linux Kernel 3.0 to include an on-the-go Expresso machine interface! Ok, maybe not, but Linux is definitely going mobile, from phones to e-readers. Find out more inside about Android, the Kindle 2, the Western Digital MyBook II, The Bug, and Indamixx (a portable recording studio). And if you've gone mobile and you been wanting more Emacs in your life then check out Conkeror.


To compliment the mobile we've got the stationary: parsing command line options with getopt, checking your Ruby code with metric_fu, and building a secure Squid proxy. How is this stationary you ask? What can we say? It's not. We just wanted to see if anybody actually read this part of the page :) .


All this and more, and all you have to do is get your hot sweaty hands on the latest copy of Linux Journal.





Read this issue