Použití GCJ pro přípravu přímo spustitelných programů z Javy


Zpracoval: Vašek Mikolášek
Vedoucí projektu, korektury, závěrečná revize: Pavel Herout

Obsah:

Úvod - Co to je GCJ ?

GCJ - překladač zdrojových kódů v Javě je součástí projektu GNU Compiler Colection (GCC). Podle tvůrců má GCJ, kromě klasického překladu, umět převádět zdrojový text i bytecode rovnou do strojového kódu, .exe souboru.Tento aspekt by mohl z GCJ udělat velmi užitečný nástroj pro snadnější šíření programů napsaných v Javě. Nicméně právě tyto funkce překladače nefungují zcela bezproblémově -- podrobněji viz níže. Protože je GCJ pod licencí GNU, jde samozřejmě o freeware.


Stručný návod

V dalším textu bude uveden opravdu jen stručný postup, jak GCJ nainstalovat a překládat pomocí něj jak do bytecodu (.class), tak i do strojového kódu (.exe).

Instalace

Instalace GCJ se ukázala jako poněkud komplikovaná. GCJ je totiž distribuován v podobě zdrojových kódů, které je nutné dále přeložit. Vzhledem k velikosti tohoto balíku se mi jej nechtělo stahovat z internetu a sáhl jsem po již přeložené binární podobě GCJ pro platformu Windows. To už ovšem není součást GNU, ale jiných projektů (například: Cygwin nebo MinGW).
S balíkem od Cygwinu (GCJ verze 3.3.1) jsem měl problémy, po instalaci nešel program gcj.exe vůbec spustit. (Má verze Cygwinu: 2.78.2.8). Dobrá zpráva ovšem je, že balíky od MinGW jsou použitené i v Cygwinu, takže byl použit právě balík od MinGW.

Pro správnou funkčnost je nutné, aby balík GCJ byl stejné verze jako GCC i G++. Balíky GCJ, GCC a G++ (verze 3.3.1) si můžete stáhnout jako jeden celek (14 MB). Balík GCJ - 3.3.1 je k dispozici i samostatně (9,5 MB).

Překlad

Samotný překlad (do bytecodu) je vcelku bezproblémový a v podstatě velmi podobný (známému) použití gcc.
Příkazem:
gcj -C NazevTridy.java
dojde k vygenerování (pokud je vše bez problémů) souboru NazevTridy.class.

Za zmínku stojí, že GCJ se dívá po potřebných třídách k překladu jak v aktuálním adresáři, tak i v jeho podadresářích odpovídajících názvu aktuálního balíku. A je jedno, jestli jsou třídy stále jako .java soubory nebo již .class.

V adresáři ./share/java je uložen archiv libgcj-3.3.1.jar, který obsahuje redukovanou verzi JDK 1.2.2 Java Core API, kterou GCJ využívá. Při porovnání obsahu tohoto archivu se jmény všech tříd z API dokumentace JDK 1.2.2 je vidět, že v libgcj-3.3.1.jar nejsou všechny třídy. Můžete si prohléhnout seznam těch, které v libgcj-3.3.1.jar chybějí.

Pozor!

  1. Některé třídy sice v libgcj-3.3.1.jar jsou, ale liší se v implementaci, což už je popsáno přímo v dokumentaci. V libgcj-3.3.1.jar se oproti standardní Java Core API vyskytuje navíc balík gnu, více zde.
  2. Všimněte si, že se mluví o verzi JDK 1.2.2 a v současnosti (červen 2004) je dostupná verze JDK 1.4.2, ve které je samozřejmě knihoven mnohem více.

Java do .exe

Překlad do .exe se provede následujícím příkazem:
gcj --main=balik1.balik2.NazevTridy -o program.exe NazevTridy.java JinaTrida.java
Seznam všech možných přepínačů a voleb při překladu je rozsáhlý, odkazuji proto na
dokumentaci GCJ. Zde uvedu pouze, že přepínač --main specifikuje, ve které třídě je metoda main(), která má být voláná jako první (je to proto, že každá třída může mít svou vlastní metodu main(), například kvůli ladění.) Třída musí být uvedená svým plným jménem, tedy včetně balíků.

Malý příklad:

Na triviální konzolové aplikaci ukážu postup, jak vytvořit ze zdrojového souboru Javy spustitelný .exe soubor. Zdrojový kód programu je v souboru VypisAdresare.java v adresáři: f:/pracovni/java. Program vypíše obsah adresáře předaný jako parametr příkazové řádky, nebo vypíše aktuální adresář. Samotný kód je velmi jednoduchý.
package javatoexe.konsole;  // z cvicnych duvodu dva vnorene baliky

import java.io.*;
import java.util.*;


public class VypisAdresare {
  public static void main(String[] args) {
    File adresar;
    if (args.length >= 1) {
      adresar = new File(args[0]);
      if (!adresar.isDirectory()) {
        System.err.println("Chyba: '" + args[0] + "' neni adresar");
        System.exit(1);
      }
    }
    else {
      adresar = new File(System.getProperty("user.dir"));
    }
    vypisObsahAdresare(adresar);
  }
  
  public static void vypisObsahAdresare(File adresar) {
    File seznam[] = adresar.listFiles();
    ArrayList jmenaPolozek = new ArrayList();
    
    for (int i = 0; i < seznam.length; i++) {
      if (seznam[i].isDirectory()) {
        jmenaPolozek.add("<DIR>\t" + seznam[i].getName().toUpperCase());
      }
      else {
        jmenaPolozek.add(seznam[i].getName());
      }
    }
    Collections.sort(jmenaPolozek);
    for (Iterator it = jmenaPolozek.iterator(); it.hasNext(); ) {
      System.out.println(it.next());
    }
  }
}
V adresáři f:\pracovni\java stačí mít opravdu pouze tento zdrojový soubor. Není potřeba vytvářet žádnou strukturu adresářů odpovídající struktuře balíků (viz
zde). Dalším krokem je spustit například Cygwin, přesunout se do adresáře se zdrojovým souborem, v mém případě tedy f:\pracovni\java, a napsat následující příkaz :
	gcj --main=javatoexe.konsole.VypisAdresare -o vypis VypisAdresare.java	
Poté, jestliže vše proběhlo v pořádku, je výsledný soubor vypis.exe uložen v akutálním adresáři a je možné jej spustit. Všiměte si, že je velký něco přes 2,5 MB! Zde si můžete vypis.exe stáhnout.


Závěr

Tento způsob vytváření .exe souborů ze zdrojových kódů v Javě ale nelze prakticky téměř použít. Nejsou totiž podporovány ani AWT ani Swing, které umožňují vytvářet okénkové aplikace.

Dále není známá existence kompletního seznamu tříd, které lze použít. To prakticky znamená, že pokud použijete třídy z libgcj (viz výše), překlad do .exe sice proběhne, ale může se stát, že použitá třída není v knihovnách vůbec implementována, takže dojde k vyhození vyjímky.

Autoři GCJ na svých stránkách tvrdí, že v tuto chvíli fungují bez problémů "collections", práce se sítí, serializace a některé další třídy. To tedy znamená, že konzolové aplikace pracující se soubory a snad i se sítí, by měly fungovat. I zde je ale nutné po převodu do .exe provést detailní testy.