編譯 Java 程式碼

JDT 外掛程式包含一個增量和批次的 Java 編譯器,可從程式碼建置 Java .class 檔案。 這個編譯器未提供直接的 API。它會安裝成 Java 專案中的一個建置器。編譯是以標準的平台建置機制來觸發。

有關平台建置機制的詳述,請參閱增量專案建置器

編譯器碼

您可以程式設計的方式使用建置 API 來編譯專案中的 Java 程式檔。

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

對於 Java 專案,這會呼叫 Java 增量專案建置器(以及任何已新增至專案之建置 規格內的其他增量專案建置器)。所產生的 .class 檔會寫到指定的輸出資料夾中。 其他資源檔案可複製到輸出資料夾中。 

如果建置了完整批次,則可以清除輸出資料夾中的所有 .class 檔,以確保沒有過時的檔案。 這是藉由使用「JDT 核心建置器選項」 (CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER) 來控制的。這個選項的預設值是清除輸出資料夾。除非重設這個選項, 不然您必須確定您是將所有 .class 檔(這些檔案沒有對應的程式檔), 放在類別路徑中的個別類別檔資料夾中,而非放在輸出資料夾中。

您可以使用其他控制哪些資源將複製到輸出資料夾的選項, 來配置增量和批次建置器。下列範例顯示如何設定資源過濾器, 以便以 '.ignore' 結尾的檔案和名為 'META-INF' 的資料夾不會被複製到輸出資料夾:

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

當檔案名稱符合所提供的型樣之一,即會加以過濾。如果資料夾的名稱符合所提供的資料夾名稱(尾端為一個路徑分隔字元)之一, 則會過濾整個資料夾。

您也可以將增量和批次式建置器配置成當 .classpath 檔中有錯誤時只產生一個錯誤。 依預設會設定這個選項,而且它會消除大部分的錯誤。 請參閱 JDT 核心建置器選項,以取得建置器相關選項及其預設值的完整清單。

您也可以使用 JavaCore 選項,來配置編譯器。例如,您可以定義應該對不同種類的問題(在編譯期間找到的問題)使用的嚴重性。 請參閱 JDT 核心編譯器選項,以取得編譯器相關選項及其預設值的完整清單。

以程式化的方式配置建置器或編譯器的選項時, 您應該判定選項的範圍。例如,設定資源過濾器僅能套用至特殊專案。 下列範例設定早先顯示的同一資源過濾器,但僅對個別專案設定它。

   
   Hashtable options = myProject.getOptions(false);  // get only the options set up in this project
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   myProject.setOptions(options);

使用批次編譯器

尋找批次編譯器

批次編譯器類別位於 JDT/核心外掛程式的內部類別中。因此,其位於 plugins/org.eclipse.jdt.core 目錄的 jdtcore.jar 檔中。 該類別的名稱為 org.eclipse.jdt.internal.compiler.batch.Main

執行批次編譯器

有哪些可用的選項?

背景為橙色的選項是建議選項。

名稱 用法
類別路徑選項
-bootclasspath <dir 1>;<dir 2>;...;<dir P> 這是用來引導編譯器所使用之類別檔的目錄或 JAR 檔清單。依預設會使用執行中之 VM 的程式庫。這些項目會以平台路徑分隔字元來區隔。
-cp
-classpath <dir 1>;<dir 2>;...;<dir P>
這是用來編譯程式檔的目錄或 JAR 檔清單。預設值是內容 "java.class.path" 的值。這些項目會以平台路徑分隔字元來區隔。
-extdirs <dir 1>;<dir 2>;...;<dir P> 這是用來指定延伸規格 zip/jar 檔之位置的目錄清單。這些項目會以平台路徑分隔字元來區隔。
-sourcepath <dir 1>;<dir 2>;...;<dir P> 這是用來指定程式檔的目錄清單。這些項目會以平台路徑分隔字元來區隔。
-d <dir 1>|none 這是用來指定應在其中傾出產生之 .class 檔的目錄。如果省略,則不會建立任何套件目錄結構。
如果您不要產生 .class 檔,請使用 -d none
-encoding <encoding name> 指定預設來源編碼格式(您也可以對每一個輸入程式檔/資料夾名稱以 [encoding <encoding name>] 加上字尾, 來依每一個檔案指定自訂編碼)。
標準選項
-target 1.1|1.2|1.3|1.4|1.5|5|5.0 這會指定 .class 檔目標設定。 可能的值為:
  • 1.1(主要版本:45 次要:3)
  • 1.2(主要版本:46 次要:0)
  • 1.3(主要版本:47 次要:0)
  • 1.4(主要版本:48 次要:0)
  • 1.555.0(主要版本:49 次要:0)
預設值為:
  • 1.1-1.3 模式)
  • 1.2-1.4 模式)
  • 1.5-1.5 模式)
-1.3 將標準層次設為 1.3。隱含表示 -source 1.3 -target 1.1。
-1.4 將標準層次設為 1.4(預設值)。隱含表示 -source 1.3 -target 1.2。
-1.5 將標準層次設為 1.5。隱含表示 -source 1.5 -target 1.5。
-source 1.3|1.4|1.5|5|5.0 這是用來啟用編譯器的來源層次。
可能的值為:
  • 1.3
  • 1.4
  • 1.555.0
預設值為:
  • 1.3-1.3 模式)
  • 1.4-1.4 模式)
  • 1.5-1.5 模式)
1.4 中,assert 會視為關鍵字。在 1.5enumassert 會視為關鍵字。
警告選項
-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
設定警告層次。
例如:-warn:unusedLocals,deprecation

紅色項目為預設值。

    -warn:<以 , 區隔的警告>    確實啟用列出的警告
    -warn:+<以 , 區隔的警告>   啟用其他的警告
    -warn:-<以 , 區隔的警告>   停用特定的警告
allDeprecation 棄用,即使在已棄用的程式碼內亦同
allJavadoc 無效或遺漏的 javadoc
assertIdentifier 用來作為 ID 的 assert
boxing autoboxing 轉換
charConcat 字元陣列用於字串連接,而不需明確轉換成字串的時機
conditionAssign 可能的意外 Boolean 指派
constructorName 含有建構子名稱的方法
dep-ann 遺漏 @Deprecated 註釋
deprecation 在已棄用的程式碼之外,已棄用之類型或成員的用法
emptyBlock 未記載的空區塊
enumSwitch,
incomplete-switch
不完整的 enum 切換選項
fieldHiding 欄位隱藏了另一個變數
finalBound 含有最終界限的類型參數
finally finally block 未正常完成
hiding fieldHiding、localHiding、typeHiding 和 maskedCatchBlock 的巨集
indirectStatic 靜態成員的間接參照
intfAnnotation 用來作為超介面的註釋類型
intfNonInherited 介面非繼承方法的相容性
javadoc 無效的 javadoc
localHiding 區域變數隱藏了另一個變數
maskedCatchBlocks 隱藏的 catch 區塊
nls 非 nls 字串文字(缺少 //$NON-NLS-<n> 標示)
noEffectAssign 表示沒有影響的指派
null 遺漏或冗餘的空值檢查
over-ann 遺漏 @Override 註釋
pkgDefaultMethod 嘗試置換套件預設方法
serial 遺漏 serialVersionUID
semicolon 不必要的分號或空的陳述式
specialParamHiding 建構子或設定元參數隱藏了另一個欄位
static-access indirectStatic 和 staticReceiver 的巨集
staticReceiver 非 static 接收端是否用來取得 static 欄位或呼叫 static 方法
suppress 啟用 @SuppressWarnings
syntheticAccess,
synthetic-access
對內部類別執行綜合存取的時機
tasks 在程式碼中啟用 tasks 標示的支援
typeHiding 類型參數隱藏了另一個類型
unchecked 未檢查的 type 作業
unnecessaryElse 不必要的 else 子句
unqualified-field-access,
unqualifiedField
欄位的未限定參照
unused unusedArgument、unusedImport、unusedLocal、unusedPrivate 和 unusedThrown 的巨集
unusedArgument 未使用的方法引數
unusedImport 未使用的匯入參照
unusedLocal 未使用的區域變數
unusedPrivate 未使用的私密成員宣告
unusedThrown 未使用的已宣告擲出異常狀況
uselessTypeCheck 不必要的 cast/instanceof 作業
varargsCast varargs 引數需要明確強制轉型
warningToken @SuppressWarningsb 中有未處理的 warning 記號

-nowarn 沒有警告(相當於 -warn:none
-deprecation 相當於 -warn:deprecation
除錯選項
-g[:none|:lines,vars,source] 設定除錯屬性層次
-g 所有除錯資訊(相當於 -g:lines,vars,source
-g:none 沒有除錯資訊
-g:[lines,vars,source] 選擇性的除錯資訊
-preserveAllLocals 明確要求編譯器保留所有區域變數(用於除錯)。如果省略,編譯器會移除未使用的區域項目。
進階選項
@<file> 從檔案讀取指令行引數
-maxProblems <n> 每一編譯單元的問題數上限(預設值為 100)
-log <filename> 指定會在其中傾出來自編譯器的所有輸出的日誌檔。如果您要除錯批次編譯器,或取得含有來自批次建置之所有錯誤和警告的檔案, 這真的非常有用。如果副檔名為 .xml,則產生的日誌會是 xml 檔。
-proceedOnError 錯誤時繼續編譯,並傾出含有問題方法或問題類型的類別檔。只有在您要即使有其它的錯誤,還是要能夠執行應用程式時, 才建議這樣做。
-verbose 列印主控台或日誌檔(如果指定)中,已存取/已處理的編譯單元。
-referenceInfo 計算參照資訊。這只有在連接到建置器時才有用。否則參照資訊並沒有用。
-progress 顯示進度(只適用於 -log 模式)
-time 顯示速度資訊
-noExit 編譯結束時不要呼叫 System.exit(n)(如果沒有錯誤,則 n=0
-repeat <n> 重複編譯程序 <n> 次(效能分析)。
-inlineJSR 列入 JSR 位元組碼(如果目標 >= 1.5 則隱含表示)
-enableJavadoc 考慮 javadoc 內的參照
說明選項
-? -help 顯示說明訊息
-v -version 顯示編譯器的建置號碼。這對報告錯誤非常有用。
-showversion 顯示編譯器的建置號碼並繼續進行。這對報告錯誤非常有用。

範例

d:\temp -classpath rt.jar -time -g -d d:/tmp 這會編譯 d:\temp 和其子資料夾中的所有程式檔。類別路徑只是 rt.jar。其會產生所有除錯屬性, 且所有產生的 .class 檔都會傾出至 d:\tmp 中。在批次程序完成後,即會顯示編譯器的速度。
d:\temp\Test.java -classpath d:\temp;rt.jar -g:none 這只會編譯 Test.java,且會從 d:\temp 中擷取任何相依的檔案。其類別路徑為 rt.jar 和 d:\temp,這表示會先搜尋 d:\temp 中所有必要的類別,再搜尋 rt.jar。其不會產生任何除錯屬性, 且所有產生的 .class 檔都會傾出至 d:\tmp 中。

使用 ant javac 配接器

您可使用 javac 配接器,而在 Ant Script 內使用 Eclipse 編譯器。 如果要使用 Eclipse 編譯器,您只需在 Script 中定義 build.compiler 內容即可。請見下列的小範例。
<?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>
有關 javac Ant 作業的語法,可在 Ant javac 作業文件中找到。現行配接器支援 Javac Ant 作業 1.4.1 到 1.6.5 版。

如果您使用的是 1.5.0 以上的版本,您可以使用巢狀編譯器引數元素來指定編譯器特定的選項。

...
		<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>		
...

為了避免取得編譯器相依的 Script,建議您使用設為 org.eclipse.jdt.core.JDTCompilerAdapter 的編譯器引數。 如果未如此設定,該 Script 只能用於 Eclipse 編譯器。如果設定,且其名稱與 build.compiler 內容所指定的編譯器名稱不同,則會忽略巢狀編譯器引數。

問題判斷

JDT Core 會定義一個 private 的標記(標記類型 "org.eclipse.jdt.core.problem"), 來表示編譯問題。如果要以程式設計的方式發掘編譯器所偵測到的問題,則應使用標準平台標記通訊協定 。 有關使用標記的概觀,請參閱資源標記

下列片段尋找一個編譯單元中的所有 Java 問題標記。

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

Java 問題標記由 Java 專案建置器所維護, 且會在解決問題和重新編譯 Java 程式檔之後自動移除。

問題 ID 值是使用 IProblem 中的一個常數來設定。 問題 ID 雖然可用, 但因訊息已區域化, 因此您可根據預設的語言環境加以變更。 定義在 IProblem 中的常數採自我說明方式。

您應定義 IProblemRequestor 的實作,以便在 Java 作業期間收集所發現的問題。 如果在建立工作副本期間有提供 IProblemRequestor, 則工作副本可和問題偵測維持一致。如果要如此做, 您可以使用 reconcile 方法。其範例如下:

  ICompilationUnit unit = ..; // get some compilation unit
			
  // create requestor for accumulating discovered problems
  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; } // will detect problems if active
  };
    
  // use working copy to hold source with error
  ICompilationUnit workingCopy = unit.getWorkingCopy(new WorkingCopyOwner() {}, problemRequestor, null);
  ((IOpenable)workingCopy).getBuffer().setContents("public class X extends Zork {}");

  // trigger reconciliation			
  workingCopy.reconcile(NO_AST, true, null, null);
您可以在 acceptProblem(IProblem) 方法中針對所報告的問題新增一項動作。在本例中, 所報告的問題為 Zork 無法解析,或不是有效的 Super 類別, 且其 ID 為 IProblem.SuperclassNotFound