Programy v Jave, se na rozdil treba od C nekompiluji primo do nativniho kodu dane platformy, ale do bajt kodu (mezikodu). To muze velka (ne)vyhoda. zalezi na uhlu pohledu. Aplikace je pak multiplatformni, jde spustit na vsech OS, na ktere je portovana Java. Nevyhodnou je mozna trochu mensi rychlost (tohle tema nemam rad ;-)) a relativne snadna moznost dekompilovat zkompilovane class soubory. Malo se to vi a jeste min pouziva, ale i Java se do zkompilovat primo do nativniho kodu.
Nechce se mi psat o teorie, te je plny web. Takze kratce: zdrojak v Jave jde opravdu zkompilovat do nativni binarky. Na Windows se to casto resi pribalenim JRE (Java Runtime Environment) k JAR souboru s aplikaci. Cela obludnost ma pak minimalne 100MB. Navic je tam JRE navzdy neaktualizovane.
Pravdepodobne nejlepsi na kompilaci do nativniho kodu je komercni nastroj Excelsior JET, bohuzel jsem ho vsak nevyzkousel.
Otevrenou alternativou (no dobra, alternativa je mozna silne slovo) je GCJ (GNU ClassPath). Projekt je aktualne asi v mrtve fazi a nic se v nem nedeje. Podle oficialniho webu je podpora na urovni „It has been merged with GNU Classpath and supports most of the 1.4 libraries plus some 1.5 additions.“. Takze skoro cela Java 1.4 a cast Javy 1.5.
Jen pro upresneni, Java 1.4 je z roku 2002 a 1.5 (Java 5.0) z roku 2004. Podpora AWT a Swingu je takova…pochybna, skoro zadna…
Dalsi mytus: vysledna binarka bude obludne velka. V pripade GCJ to u „Hello, world“ neplatilo. Zkouset cokoliv dalsiho jsem povazoval za plytvani casem. GCJ jsem zkousel z jedineho duvodu – dokazit si, ze to jde 🙂
Protoze jsem mel u testovani spustenych X dalsich programu, jsou casy pouze orientacni. Je tak videt, ze vysledna binarka i kompilace trva u Oracle Javy i GCJ +- stejne dlouho.
Na uvod pouzite verze Javy. Pracoval jsem na Linux Mint 16 (Ubuntu 13.10):
########### Verze Javy: Oracle Java 8 64bit; gcc (gcj) 4.8.1 64bit
martin@martin:~/gcj/test$ gcj -v Using built-in specs. Reading specs from /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcj.spec rename spec startfile to startfileorig rename spec lib to liborig COLLECT_GCC=gcj COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.1-10ubuntu9' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9) martin@martin:~/gcj/test$ java -version java version "1.8.0_20" Java(TM) SE Runtime Environment (build 1.8.0_20-b26) Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
Ukazkovy „Hello, world“ program:
martin@martin:~/gcj/test$ cat HelloWorld.java public class HelloWorld { public static void main(String[] args) { Pozdrav pozdrav = new Pozdrav("Hello, world!"); pozdrav.print(); } } martin@martin:~/gcj/test$ cat Pozdrav.java public class Pozdrav { private String text; public Pozdrav(String pozdrav) { text = pozdrav; } private String getText() { return text; } public void print() { System.out.println(getText()); } }
Velikosti souboru pred kompilaci:
martin@martin:~/gcj/test$ ls -lh celkem 8,0K -rw-r--r-- 1 martin martin 160 říj 13 23:12 HelloWorld.java -rw-r--r-- 1 martin martin 250 říj 13 23:12 Pozdrav.java
Kompilace pomoci Oracle Javy a GCJ:
martin@martin:~/gcj/test$ time javac HelloWorld.java real 0m0.793s user 0m1.528s sys 0m0.076s martin@martin:~/gcj/test$ time gcj -O2 -g -Wall --main=HelloWorld -o HelloWorldGCJ HelloWorld.java Pozdrav.java real 0m0.597s user 0m0.515s sys 0m0.081s
Velikosti vystupnich souboru:
martin@martin:~/gcj/test$ ls -lh celkem 40K -rw-r--r-- 1 martin martin 371 říj 13 23:12 HelloWorld.class -rwxr-xr-x 1 martin martin 22K říj 13 23:15 HelloWorldGCJ -rw-r--r-- 1 martin martin 160 říj 13 23:12 HelloWorld.java -rw-r--r-- 1 martin martin 525 říj 13 23:12 Pozdrav.class -rw-r--r-- 1 martin martin 250 říj 13 23:12 Pozdrav.java
Velikosti vystupnich souboru po stripu GCJ binarky:
martin@martin:~/gcj/test$ strip HelloWorldGCJ martin@martin:~/gcj/test$ ls -lh celkem 28K -rw-r--r-- 1 martin martin 371 říj 13 23:12 HelloWorld.class -rwxr-xr-x 1 martin martin 12K říj 13 23:15 HelloWorldGCJ -rw-r--r-- 1 martin martin 160 říj 13 23:12 HelloWorld.java -rw-r--r-- 1 martin martin 525 říj 13 23:12 Pozdrav.class -rw-r--r-- 1 martin martin 250 říj 13 23:12 Pozdrav.java
Informace o zkompilovanych souborech:
martin@martin:~/gcj/test$ file HelloWorldGCJ HelloWorldGCJ: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x8a4bf227c54ab5357c44b2b9e5d2d11fc1e7d1d6, stripped martin@martin:~/gcj/test$ file HelloWorld.class HelloWorld.class: compiled Java class data, version 52.0 martin@martin:~/gcj/test$ file Pozdrav.class Pozdrav.class: compiled Java class data, version 52.0
Porovnani rychlosti provedeni programu z Oracle Javy a GCJ binarky:
martin@martin:~/gcj/test$ time java HelloWorld Hello, world! real 0m0.073s user 0m0.067s sys 0m0.019s martin@martin:~/gcj/test$ time ./HelloWorldGCJ Hello, world! real 0m0.035s user 0m0.022s sys 0m0.013s
Zaver o (ne)pouzitelnosti si kazdy musi udelat sam. Muj test nema prilis velkou vypovidaci hodnotu, na to jsem testoval malo veci. Chtelo by to slozitejsi program. Ale jak rikam, jen jsem si chtel na TODO listu odskrtnout „vytvorit Java ELF binarku“ a to se povedlo.
Mate-li s GCJ nejake blizsi zkusenosti, podelte se prosim v diskuzi pod clankem.