Kompilace kódu v jazyce Java

Mezi moduly plug-in JDT patří přírůstkový a dávkový kompilátor Java určený k vytváření souborů .class prostředí Java ze zdrojového kódu. Kompilátor neposkytuje žádné přímé rozhraní API. Instaluje se jako tvůrce do projektů Java. Kompilace se spouští standardními mechanizmy platformy.

Mechanizmus, který platforma používá k sestavení, je podrobně popsán v tématu Přírůstkoví tvůrci projektů.

Kompilace kódu

Zdrojové soubory Java projektů můžete kompilovat v rámci programu s použitím rozhraní API sestavení.

   IProject myProject;
   IProgressMonitor myProgressMonitor;
   myProject.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, myProgressMonitor);

Pro projekt Java tento kód volá přírůstkového tvůrce projektu Java (společně s ostatními přírůstkovými tvůrci projektu, jež byly přidány do konfigurace sestavení projektu). Vygenerované soubory .class se zapisují do určené výstupní složky. Do výstupní složky se kopírují rovněž soubory dalších prostředků. 

V případě plně dávkového sestavení může dojít k vymazání všech stávajících souborů .class za účelem odstranění případných zastaralých souborů. Tuto funkci ovládá volba sestavení JDT Core (CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER).  Výchozím nastavením této volby je čištění výstupních složek.  Nemá-li tato volba výchozí nastavení, musíte zajistit ukládání všech souborů .class, pro které nemáte příslušné zdrojové soubory, do samostatné složky souborů tříd v cestě ke třídě, tj. nikoli do výstupní složky.

Přírůstkové a dávkové tvůrce lze konfigurovat ostatními volbami, jež určují, které prostředky se kopírují do výstupní složky.  Následující příklad objasňuje způsob vytvoření filtru prostředků, který do výstupní složky nezkopíruje soubory s příponou názvu '.ignore' a složky s názvem 'META-INF':

      Hashtable options = JavaCore.getOptions();
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   JavaCore.setOptions(options);

Názvy souborů jsou filtrovány porovnáváním se zadanými obecnými názvy. Pokud se název složky shoduje s některým ze zadaných názvů složek, který končí oddělovacím znakem cesty, je tato složka odfiltrována.

Přírůstkové a dávkové tvůrce lze nastavit rovněž tak, aby při výskytu chyb v souboru .classpath generovali pouze jediné chybové hlášení. Jde o standardní volbu, jež umožňuje potlačení velkého počtu chybových hlášení.  Kompletní seznam voleb tvůrce s jejich výchozími hodnotami viz Volby tvůrce JDT Core.

Kompilátor lze konfigurovat rovněž s použitím voleb JavaCore.  Například můžete definovat závažnost, která by měla být použita pro různé typy problémů rozpoznávaných během kompilace. Kompletní seznam voleb kompilátoru s jejich výchozími hodnotami   viz Volby kompilátoru JDTCore .

Chcete-li v programu konfigurovat volby tvůrce nebo kompilátoru, měli byste stanovit rozsah této volby.  Například zřízení filtru prostředku má být pravděpodobně uplatněno pouze na určitý projekt.  Následující příklad zřizuje výše uvedený filtr prostředku, nyní však pouze pro určitý projekt.

   
   Hashtable options = myProject.getOptions(false);  // získat pouze volby nastavené v tomto projektu
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   myProject.setOptions(options);

Použití dávkového kompilátoru

Vyhledání dávkového kompilátoru

Třída dávkového kompilátoru je umístěna v interních třídách modulu plug-in jádra JDT/Core. Je tedy v souboru jdtcore.jar v adresáři plugins/org.eclipse.jdt.core. Název třídy je org.eclipse.jdt.internal.compiler.batch.Main.

Spuštění dávkového kompilátoru

Jaké volby jsou k dispozici?

Při oranžovém pozadí jsou navrženy tyto volby.

Název Použití
Volby cesty ke třídě
-bootclasspath <dir 1>;<dir 2>;...;<dir P> Toto je výpis adresáře souborů jar, které se používají k samozavádění souborů tříd používaných kompilátorem. Ve výchozím nastavení jsou použity knihovny spuštěného systému VM. Položky jsou odděleny oddělovačem cesty k platformě.
-cp
-classpath <dir 1>;<dir 2>;...;<dir P>
Toto je výpis adresáře souborů jar používaných ke kompilaci zdrojových souborů. Výchozí hodnota je hodnota vlastnosti "java.class.path". Položky jsou odděleny oddělovačem cesty k platformě.
-extdirs <dir 1>;<dir 2>;...;<dir P> Toto je výpis adresáře používaného k určení umístění souborů s příponami zip/jar. Položky jsou odděleny oddělovačem cesty k platformě.
-sourcepath <dir 1>;<dir 2>;...;<dir P> Toto je výpis adresáře používaného k určení umístění zdrojových souborů. Položky jsou odděleny oddělovačem cesty k platformě.
-d <dir 1>|none Používá se k určení, do kterého adresáře by se měly vypisovat vygenerované soubory .class. Pokud to vynecháte, nebude vytvořena adresářová struktura balíčku.
Pokud nechcete generovat soubory .class, použijte -d none.
-encoding <encoding name> Určete výchozí formát kódování zdroje (lze také určit vlastní kódování tak, že ke každému názvu vstupního zdrojového souboru/složky přidáte příponu [encoding <encoding name>]).
Volby shody
-target 1.1|1.2|1.3|1.4|1.5|5|5.0 to určuje cílové nastavení souboru .class. Možné hodnoty jsou:
  • 1.1 (hlavní verze: 45 vedlejší: 3)
  • 1.2 (hlavní verze: 46 vedlejší: 0)
  • 1.3 (hlavní verze: 47 vedlejší: 0)
  • 1.4 (hlavní verze: 48 vedlejší: 0)
  • 1.5, 5 nebo 5.0 (hlavní verze: 49 vedlejší: 0)
Výchozí nastavení jsou:
  • 1.1 v režimu -1.3
  • 1.2 v režimu -1.4
  • 1.5 v režimu -1.5
-1.3 Nastavte úroveň shody na 1.3. Implicitně -zdroj 1.3 -cíl 1.1.
-1.4 Nastavte úroveň shody na 1.4 (výchozí). Implicitně -zdroj 1.3 -cíl 1.2.
-1.5 Nastavte úroveň shody na 1.5. Implicitně -zdroj 1.5 -cíl 1.5.
-zdroj 1.3|1.4|1.5|5|5.0 Používá se k zpřístupnění úrovně zdroje kompilátoru.
Možné hodnoty jsou:
  • 1.3
  • 1.4
  • 1.5, 5 nebo 5.0
Výchozí nastavení jsou:
  • 1.3 v režimu -1.3
  • 1.4 v režimu -1.4
  • 1.5 v režimu -1.5
Ve verzi 1.4, se s assert nakládá jako s klíčovým slovem. Ve verzi 1.5, se s enum a assert nakládá jako s klíčovým slovem.
Volby varování
-warn:
allDeprecation
allJavadoc
assertIdentifier
boxing
charConcat
conditionAssign
constructorName
dep-ann
deprecation
emptyBlock
enumSwitch
fieldHiding
finalBound
finally
hiding
incomplete-switch
indirectStatic
intfAnnotation
intfNonInherited
javadoc
localHiding
maskedCatchBlocks
nls
noEffectAssign
null
over-ann
pkgDefaultMethod
semicolon
serial
specialParamHiding
static-access
staticReceiver
suppress
synthetic-access
syntheticAccess
tasks(<task1>|...|<taskN>)
typeHiding
unchecked
unnecessaryElse
unqualified-field-access
unqualifiedField
uselessTypeCheck
unused
unusedArgument
unusedImport
unusedLocal
unusedPrivate
unusedThrown
varargsCast
warningToken
Nastavte úroveň varování.
Např. -warn:unusedLocals,deprecation

Výchozí nastavení jsou červená.

    -warn:<varování oddělená ,>    zpřístupnit přesně vypsaná varování
    -warn:+<varování oddělená ,>   zpřístupnit dodatečná varování
    -warn:-<varování oddělená ,>   znepřístupnit určitá varování
allDeprecation nepřípustnost i uvnitř nepřípustného kódu
allJavadoc neplatný nebo chybějící dokumentace javadoc
assertIdentifier výskyt assert použit jako identifikátor
boxing konverze automatického uzavírání
charConcat pokud je ve zřetězení řetězce pole char použito bez výslovné konverze na řetězec
conditionAssign možné nechtěné logické přiřazení
constructorName metoda s názvem konstruktoru
dep-ann chybí anotace @Deprecated
deprecation použití nepřípustného typu nebo členu mimo nepřípustný kód
emptyBlock nedokumentovaný prázdný blok
enumSwitch,
incomplete-switch
nekompletní přepínač výčtu
fieldHiding pole zakrývající jinou proměnnou
finalBound parametr typu s konečnou mezí
finally blok finally není normálně ukončen
hiding makro pro fieldHiding, localHiding, typeHiding a maskedCatchBlock
indirectStatic nepřímý odkaz na statický člen
intfAnnotation typ anotace používaný jako nadřazené rozhraní
intfNonInherited kompatibilita metody nezděděné z rozhraní
javadoc neplatná dokumentace javadoc
localHiding lokální proměnná zakrývající jinou proměnnou
maskedCatchBlocks skrytý zachytávací blok
nls řetězcové literály jiné než nls (postrádající značky //$NON-NLS-<n>)
noEffectAssign přiřazení bez efektu
null chybějící nebo nadbytečná kontrola nuly
over-ann chybí anotace @Override
pkgDefaultMethod pokus o vyřazení výchozí metody balíčku
serial chybí serialVersionUID
semicolon nepotřebný středník, prázdný příkaz
specialParamHiding konstruktor nebo parametr metody setter skrývá jiné pole
static-access makro pro indirectStatic a staticReceiver
staticReceiver pokud se nestatický příjemce použije k získání statického pole nebo volání statické metody
suppress zpřístupnit @SuppressWarnings
syntheticAccess,
synthetic-access
při provádění syntetického přístupu pro vnitřní třídu
tasks zpřístupnit podporu pro značky úloh ve zdrojovém kódu
typeHiding parametr typu zakrývá jiný typ
unchecked nekontrolovaná operace s typem
unnecessaryElse nadbytečná klauzule else
unqualified-field-access,
unqualifiedField
nekvalifikovaný odkaz na pole
unused makro pro unusedArgument, unusedImport, unusedLocal, unusedPrivate a unusedThrown
unusedArgument nepřečtený parametr metody
unusedImport nepoužitý odkaz importu
unusedLocal nepřečtená lokální proměnná
unusedPrivate nepoužitá deklarace soukromého členu
unusedThrown nepoužívaná deklarovaná nastalá výjimka
uselessTypeCheck nepotřebná operace cast/instanceof
varargsCast argument varargs vyžaduje explicitní přetypování
warningToken neošetřený token varování v @SuppressWarningsb

-nowarn Bez varování (rovnocenné s -warn:none)
-deprecation Rovnocenné s -warn:deprecation.
Volby ladění
-g[:none|:lines,vars,source] Nastavte úroveň atributů ladění
-g Všechny informace o ladění (rovnocenné s -g:lines,vars,source)
-g:none Žádné informace o ladění
-g:[lines,vars,source] Selektivní informace o ladění
-preserveAllLocals Výslovně požadovat, aby kompilátor zachoval všechny lokální proměnné (pro účely ladění). Pokud je vynecháno, kompilátor odebere nepoužívané lokální.
Rozšířené volby
@<file> Načíst argumenty příkazového řádku ze souboru
-maxProblems <n> Maximální počet problémů na kompilační jednotku (standardně 100)
-log <filename> Určete protokolový soubor, do kterého budou vypisovány veškeré výstupy z kompilátoru. To je skutečně užitečné, pokud chcete ladit dávkový kompilátor nebo získat soubor, který obsahuje všechna chybová hlášení a varování z dávkového sestavení. Je-li přípona .xml, vygenerovaný protokol bude soubor xml.
-proceedOnError Nezastavovat kompilaci při výskytu chyby, vypsat soubory tříd s problémovými metodami nebo typy problémů. To se doporučuje pouze, pokud chcete mít možnost spouštět aplikaci, i když zůstávají chyby.
-verbose V případě určení tisknout kompilační jednotky, ke kterým se přistupuje nebo které se zpracovávají, do konzoly nebo protokolového souboru.
-referenceInfo Určit referenční informace. To je užitečné pouze při připojení k tvůrci. Referenční informace jsou jinak neupotřebitelné.
-progress Zobrazit průběh (pouze v režimu -log)
-time Zobrazit informace o rychlosti
-noExit Nevolat System.exit(n) na konci kompilace (n=0, pokud nedojde k žádné chybě)
-repeat <n> Opakovat proces kompilace <n> krát (analýza perf).
-inlineJSR Otevřený bytekód JSR (implicitně, pokud je cíl >= 1.5)
-enableJavadoc Zvážit odkazy v dokumentaci javadoc
Volby nápovědy
-? -help Zobrazit zprávu nápovědy
-v -version Zobrazit číslo sestavení kompilátoru. To je velmi užitečné při hlášení chyby.
-showversion Zobrazit číslo sestavení kompilátoru a pokračovat. To je velmi užitečné při hlášení chyby.

Příklady

d:\temp -classpath rt.jar -time -g -d d:/tmp Zkompiluje všechny zdrojové soubory v d:\temp a podsložkách. Cesta ke třídě je jednoduše rt.jar. Vygeneruje všechny atributy ladění a všechny vygenerované soubory .class jsou vypsány do d:\tmp. Rychlost kompilátoru se zobrazí po dokončení dávkového procesu.
d:\temp\Test.java -classpath d:\temp;rt.jar -g:none Kompiluje pouze Test.java a načte všechny závislé soubory z d:\temp. Cesta ke třídě je rt.jar a d:\temp, což znamená, že všechny potřebné třídy jsou hledány nejprve v d:\temp a potom v rt.jar. Vygeneruje atributy bez ladění a všechny vygenerované soubory .class jsou vypsány do d:\tmp.

Použití adaptéru Ant javac

Kompilátor Eclipse lze prostřednictvím adaptéru javac použít i uvnitř skriptu Ant. Chcete-li použít kompilátor Eclipse, definujte ve svém skriptu vlastnost build.compiler. Následuje krátký příklad.
<?xml version="1.0" encoding="UTF-8"?>
<project name="compile" default="main" basedir="../.">

	<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>

	<property name="root" value="${basedir}/src"/>

	<property name="destdir" value="d:/temp/bin" />

	<target name="main">
		<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
		    <classpath>
		      <pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
		    </classpath>
		</javac>		
	</target>
</project> 
Syntaxi použitou pro úlohu javac Ant lze nalézt v Dokumentaci úlohy Ant javac. Aktuální adaptér podporuje úlohu Javac Ant verze 1.4.1 až 1.6.5.

Pokud používáte verzi vyšší než 1.5.0, můžete použít vnořený prvek argumentu kompilátoru k určení voleb specifických pro kompilátor.

...
		<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
		    <classpath>
		      <pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
		    </classpath>
    <compilerarg compiler="org.eclipse.jdt.core.JDTCompilerAdapter" line="-1.5 -warn:+boxing"/>
</javac>		
...

Abyste zabránili kompilátoru v načtení závislých skriptů, radíme vám použít argument kompilátoru nastavený na org.eclipse.jdt.core.JDTCompilerAdapter. Pokud nebude toto nastavení provedeno, skript bude možné používat pouze s kompilátorem Eclipse. Pokud bude nastaveno, vnořený argument kompilátoru bude ignorován, pokud se jeho název liší od názvu kompilátoru určeného ve vlastnosti build.compiler.

Určení problému

JDT Core definuje speciální značkovač (typ značkovače "org.eclipse.jdt.core.problem ") pro účely popisu kompilačních problémů. Chcete-li programem zkoumat problémy odhalené kompilátorem, použijte standardní protokol značkovačů platformy. Přehled použitých značkovačů viz Značkovače prostředků.

Následující úsek zdrojového kódu vyhledává všechny značkovače problémů Java v kompilační jednotce.

   public IMarker[] findJavaProblemMarkers(ICompilationUnit cu) 
         throws CoreException {
      IResource javaSourceFile = cu.getUnderlyingResource();
      IMarker[] markers = 
         javaSourceFile.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
            true, IResource.DEPTH_INFINITE);
   }

Značkovače problémů Java jsou udržovány tvůrcem projektu Java. Po vyřešení problémů a opětovné kompilaci zdroje Java dochází k jejich odstranění.

Hodnotu ID problému nastavuje některá z konstant v IProblem. ID problému je spolehlivé, avšak zpráva je lokalizována, a proto ji lze měnit v závislosti na výchozím národním prostředí. Konstanty definované v IProblem mají názvy odpovídající obsahu.

Měla by být definována implementace IProblemRequestor pro účely sběru problémů odhalených během činnosti prostředí Java. Pracovní kopie lze srovnávat s detekcí problémů, pokud byl pro vytvoření pracovní kopie poskytnut IProblemRequestor. Pro tento účel můžete použít metodu reconcile. Zde je příklad:

  ICompilationUnit unit = ..; // získat kompilační jednotku
			
  // vytvořit klienta pro sběr zjištěných problémů
  IProblemRequestor problemRequestor = new IProblemRequestor() {
    public void acceptProblem(IProblem problem) {
      System.out.println(problem.getID() + ": " + problem.getMessage());
    }
    public void beginReporting() {}
    public void endReporting() {}
    public boolean isActive() {	return true; } // je-li aktivní, detekuje problémy
  };
    
  // použít pracovní kopii k zachování zdroje s chybou
  ICompilationUnit workingCopy = unit.getWorkingCopy(new WorkingCopyOwner() {}, problemRequestor, null);
  ((IOpenable)workingCopy).getBuffer().setContents("public class X extends Zork {}");

  // odsouhlasení spouštěče
  workingCopy.reconcile(NO_AST, true, null, null);
Do metody acceptProblem(IProblem) můžete přidat akci pro nahlašované problémy. V tomto příkladu bude nahlášen problém Zork nelze interpretovat nebo nejde o platnou supertřídu a ID tohoto problému je IProblem.SuperclassNotFound.