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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
martin@martin:~/gcj/test$ <strong>gcj -v</strong> 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 <strong>gcc version 4.8.1</strong> (Ubuntu/Linaro 4.8.1-10ubuntu9) martin@martin:~/gcj/test$ <strong>java -version</strong> java version "<strong>1.8.0_20</strong>" 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
martin@martin:~/gcj/test$ <strong>cat HelloWorld.java</strong> public class HelloWorld { public static void main(String[] args) { Pozdrav pozdrav = new Pozdrav("Hello, world!"); pozdrav.print(); } } martin@martin:~/gcj/test$ <strong>cat Pozdrav.java</strong> 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:
1 2 3 4 |
martin@martin:~/gcj/test$ <strong>ls -lh</strong> 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:
1 2 3 4 5 6 7 8 9 |
martin@martin:~/gcj/test$ <strong>time javac HelloWorld.java</strong> real 0m0.793s user 0m1.528s sys 0m0.076s martin@martin:~/gcj/test$ <strong>time gcj -O2 -g -Wall --main=HelloWorld -o HelloWorldGCJ HelloWorld.java Pozdrav.java</strong> real 0m0.597s user 0m0.515s sys 0m0.081s |
Velikosti vystupnich souboru:
1 2 3 4 5 6 7 |
martin@martin:~/gcj/test$ <strong>ls -lh</strong> celkem 40K -rw-r--r-- 1 martin martin <strong>371</strong> říj 13 23:12 HelloWorld.class -rwxr-xr-x 1 martin martin <strong>22K</strong> říj 13 23:15 HelloWorldGCJ -rw-r--r-- 1 martin martin 160 říj 13 23:12 HelloWorld.java -rw-r--r-- 1 martin martin <strong>525</strong> ří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:
1 2 3 4 5 6 7 8 9 |
martin@martin:~/gcj/test$ <strong>strip HelloWorldGCJ</strong> martin@martin:~/gcj/test$ <strong>ls -lh</strong> celkem 28K -rw-r--r-- 1 martin martin <strong>371</strong> říj 13 23:12 HelloWorld.class -rwxr-xr-x 1 martin martin <strong>12K</strong> říj 13 23:15 HelloWorldGCJ -rw-r--r-- 1 martin martin 160 říj 13 23:12 HelloWorld.java -rw-r--r-- 1 martin martin <strong>525</strong> říj 13 23:12 Pozdrav.class -rw-r--r-- 1 martin martin 250 říj 13 23:12 Pozdrav.java |
Informace o zkompilovanych souborech:
1 2 3 4 5 6 7 8 |
martin@martin:~/gcj/test$ <strong>file HelloWorldGCJ</strong> HelloWorldGCJ: <strong>ELF 64-bit LSB executable</strong>, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x8a4bf227c54ab5357c44b2b9e5d2d11fc1e7d1d6, stripped martin@martin:~/gcj/test$ <strong>file HelloWorld.class</strong> HelloWorld.class: <strong>compiled Java class data</strong>, version 52.0 martin@martin:~/gcj/test$ <strong>file Pozdrav.class</strong> Pozdrav.class: compiled Java class data, version 52.0 |
Porovnani rychlosti provedeni programu z Oracle Javy a GCJ binarky:
1 2 3 4 5 6 7 8 9 10 11 |
martin@martin:~/gcj/test$ <strong>time java HelloWorld</strong> Hello, world! real 0m0.073s user 0m0.067s sys 0m0.019s martin@martin:~/gcj/test$ time <strong>./HelloWorldGCJ</strong> 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.