Javac

說明

編譯 Java 原始碼樹。

原始碼和目標目錄將會遞迴掃描 Java 原始碼檔案以進行編譯。只有沒有對應的 .class 檔案或 .class 檔案比 .java 檔案舊的 .java 檔案才會被編譯。

注意:Apache Ant 僅使用原始碼和類別檔案的名稱來尋找需要重新建置的類別。它不會掃描原始碼,因此不會知道巢狀類別、名稱與原始碼檔案不同的類別等。請參閱 <depend> 任務,以取得基於其他而非僅存在/修改時間的相依性檢查。

當原始碼檔案是套件的一部分時,原始碼樹的目錄結構應遵循套件階層。

可以精簡要編譯的檔案組。這可以使用 includesincludesfileexcludesexcludesfile 屬性來完成。使用 includesincludesfile 屬性,您可以指定要包含的檔案。excludeexcludesfile 屬性用於指定要排除的檔案。在兩種情況下,檔案清單都可以透過檔案名稱(相對於 srcdir 屬性或巢狀 <src> 元素中指定的目錄)或使用萬用字元模式來指定。請參閱 基於目錄的任務 部分,以取得有關如何包含/排除檔案以及如何撰寫萬用字元模式的資訊。

可以使用不同的編譯器。這可以透過設定全域性 build.compiler 屬性(這會影響建置中的所有 <javac> 任務)、設定特定於目前的 <javac> 任務的 compiler 屬性,或使用任何 typedefcomponentdef 輸入類型(實作 org.apache.tools.ant.taskdefs.compilers.CompilerAdapter)的巢狀元素來指定。build.compiler 屬性或 compiler 屬性的有效值為

預設值為 javacX,其中 X 取決於執行 Ant 時所使用的 JDK 版本。如果您希望使用提供的編譯器介面以外的介面,您可以撰寫一個實作 CompilerAdapter 介面的類別 (套件 org.apache.tools.ant.taskdefs.compilers)。在 build.compiler 屬性或 compiler 屬性中提供完整的類別名稱。

fork 屬性會覆寫 build.compiler 屬性或 compiler 屬性設定,並預期在 JAVA_HOME 中設定 JDK 1.1 或更高版本。

您也可以使用 compiler 屬性來告訴 Ant 在組合命令列開關時應該假設哪個 JDK 版本,即使您設定 fork=true。如果您要在目前的 JDK 為 1.2+ 時執行 JDK 1.1 的編譯器,這會很有用。如果您使用 compiler=javac1.1 且 (例如) depend=true,Ant 會使用命令列開關 -depend,而不是 -Xdepend

此任務會從傳遞給編譯器的類別路徑中移除指向不存在檔案/目錄的所有項目。

分岔執行檔 (如果有) 的工作目錄是專案的基本目錄。

Windows 注意事項:當新式編譯器在 Windows 上以非分岔模式使用時,它會鎖定存在於 <javac> 任務類別路徑中的檔案,且不會釋放它們。這會導致的副作用是您無法在稍後的建置中刪除或移動這些檔案。解決方法是在呼叫編譯器時分岔執行。

如果您的來源包含使用 @Native 註解註解的原生方法或欄位,您可以設定 nativeheaderdir 屬性,以便使用 javac-h 開關來產生原生標頭檔。請注意,Ant 用來判斷要編譯哪些檔案的邏輯不會考量原生標頭,也就是說,如果 .class 比對應的 .java 檔案新,則即使為其產生的原生標頭檔已過時,檔案也不會被編譯。

參數

屬性 說明 需要
srcdir Java 檔案的位置。(請參閱以下的 註解。) 是,除非有嵌套的 <src> 元素或 modulesourcepath 屬性或對應元素
destdir 儲存類別檔案的位置。
includes 必須包含的檔案模式的逗號或空格分隔清單。 否;預設為所有 .java 檔案
includesfile 檔案名稱。此檔案的每一行都視為包含模式。
excludes 必須排除的檔案模式的逗號或空格分隔清單。 否;如果 defaultexcludesno,則預設為預設排除或無
excludesfile 檔案名稱。此檔案的每一行都視為排除模式。
defaultexcludes 表示是否應使用預設排除 (yes|no)。 否;預設為 yes
classpath 要使用的類別路徑。
sourcepath 要使用的來源路徑。若要取消 sourcepath 開關,請使用 sourcepath= 否;除非指定嵌套的 <src> 元素,否則預設為 srcdir
bootclasspath 引導類別檔案的位置。(請參閱 下方 了解如何使用 -X-J-X 參數指定引導類別路徑)。
classpathref 要使用的 classpath,指定為對其他地方定義的路徑的 參照
sourcepathref 要使用的 sourcepath,指定為對其他地方定義的路徑的 參照
bootclasspathref 要使用的 bootstrapclasspath,指定為對其他地方定義的路徑的 參照
extdirs 已安裝擴充功能的位置。
encoding 來源檔案的編碼。(注意gcj 尚未支援此選項。)
nowarn 表示是否應將 -nowarn 開關傳遞給編譯器。 否;預設為 off
debug 指出是否應編譯原始碼並附上偵錯資訊。若設為 off,則會在支援的編譯器中傳遞 -g:none 至命令列(對於其他編譯器,則不會使用任何命令列參數)。若設為 true,則 debuglevel 屬性的值會決定命令列參數。 否;預設為 off
debuglevel 要附加至 -g 命令列開關的關鍵字清單。合法值為 none 或下列關鍵字以逗號分隔的清單:linesvarssource 否;當 debugfalse 或任何實作(modernjavac1.2jikes 除外)時,會忽略;預設情況下,不會附加任何內容至 -g
optimize 指出是否應編譯原始碼並進行最佳化。注意,自 JDK 1.3 起,Sun 的 javac 會忽略此旗標(因為編譯時期最佳化並非必要)。 否;預設為 off
deprecation 指出是否應編譯原始碼並附上不建議使用的資訊。 否;預設為 off
verbose 要求編譯器提供詳細的輸出。 否;預設為 no
depend 為支援此功能的編譯器(jikesclassic)啟用相依性追蹤。
includeAntRuntime 是否在類別路徑中包含 Ant 執行時期函式庫。通常最好將此設為 false,如此一來,指令碼的行為就不會受到執行環境的影響。 否;預設為 yes,除非已設定 build.sysclasspath 屬性
includeJavaRuntime 是否在類別路徑中包含執行 JVM 的預設執行時期函式庫。
注意:在某些設定中,執行時期函式庫可能是「Ant 執行時期函式庫」的一部分,因此您可能需要明確將 includeAntRuntime 設為 false,以確保不包含 Java 執行時期函式庫。
否;預設為 no
fork 是否使用 JDK 編譯器外部執行 javac 否;預設為 no
executable forkyes,則完整路徑為 javac 可執行的檔案。
自 Ant 1.6 起,此屬性也可在使用 jikesjvcgcjsj 時,用於指定可執行檔案的路徑。
否;預設為目前 JDK 的編譯器,如果 forkno 則忽略
memoryInitialSize 如果 javac 在外部執行,則為底層 JVM 的記憶體初始大小。(範例:8388608081920k80m 否;預設為標準 JVM 記憶體設定,如果 forkno 則忽略
memoryMaximumSize 如果 javac 在外部執行,則為底層 JVM 的記憶體最大大小;否則忽略。(範例:8388608081920k80m 否;預設為標準 JVM 記憶體設定,如果 forkno 則忽略
failonerror 表示編譯錯誤是否會導致建置失敗。 否;預設為 true
errorProperty 如果編譯失敗,則設定為 true 的屬性。自 Ant 1.7.1 起
source 編譯器接受的 Java 語言功能,如 -source 命令列開關所指定。有效的語言版本為 1.31.41.55 等。在 javac1.4(或當 Ant 未在 JVM 1.3 中執行時為 modern)、gcjjikes 之前的版本中,所有實作都會忽略此屬性。
如果您將此屬性與 gcjjikes 搭配使用,您必須確保您的版本支援 -source(或 -fsource,適用於 gcj)開關。
否;預設情況下,除非設定神奇的 ant.build.javac.source 屬性,否則完全不會使用 -source 參數
請注意,預設值取決於執行 Ant 的 JDK。我們強烈建議您務必指定此屬性。
target 為特定 JVM 版本產生類別檔(交叉編譯)。 否;預設情況下,除非設定神奇的 ant.build.javac.target 屬性,否則完全不會使用 -target 參數
請注意,預設值取決於執行 Ant 的 JDK 以及 source(請參閱 交叉編譯選項)。我們強烈建議您務必指定此屬性。
compiler 要使用的編譯器實作。請參閱上方 清單 中的有效編譯器。 否;預設為 build.compiler 屬性的值(如果已設定),否則預設為目前 JDK 的編譯器
listfiles 指示是否列出要編譯的原始檔。 否;預設為 no
tempdir Ant 應放置暫存檔的位置。僅在分岔任務且命令列引數長度超過 4 kB 時使用。自 Ant 1.6 起 否;預設為 java.io.tmpdir
updatedProperty 如果編譯已執行且成功,則設定為 true 的屬性。自 Ant 1.7.1 起
includeDestClasses 此屬性控制是否在提供給編譯器的類別路徑中包含目標類別目錄。如果設定為 true(預設),先前編譯的類別會在編譯器的類別路徑中。這表示「貪婪」的編譯器不會重新編譯已編譯的相依類別。一般來說,這很好,因為它會阻止編譯器執行不必要的作業。然而,對於某些涉及泛型的邊緣案例,javac 編譯器需要編譯相依類別才能取得泛型資訊。其中一個範例記載於錯誤報告中:錯誤 40776 - 編譯包含泛型的 Java 5 專案時發生問題。將屬性設定為 false 會導致編譯器重新編譯相依類別。自 Ant 1.7.1 起 否;預設為 true
createMissingPackageInfoClass package-info.java 檔中的一些封裝層註解不會建立任何 package-info.class 檔,因此 Ant 會每次重新編譯同一個檔。
自 Ant 1.8 起,如果編譯器未建立任何 package-info.class,則會為每個 package-info.java 建立一個空的 package-info.class
在某些設定中,這個額外的類別會造成問題,可以透過將此屬性設定為 false 來抑制。自 Ant 1.8.3 起
否;預設為 true
modulepath 指定尋找應用程式模組的位置。模組、模組檔或已展開模組的目錄清單。自 Ant 1.9.7 起
modulepathref 要使用的 modulepath,以 參考 形式提供,參考其他地方定義的路徑。自 Ant 1.9.7 起
modulesourcepath 指定尋找多個模組編譯的輸入原始檔的位置。自 Ant 1.9.7 起 是,除非存在 srcdir 屬性或巢狀 <src> 元素
modulesourcepathref 要使用的 modulesourcepath,以 參考 形式提供,參考其他地方定義的路徑。自 Ant 1.9.7 起
upgrademodulepath 指定在執行時期映像中取代可升級模組的模組位置。自 Ant 1.9.7 起
upgrademodulepathref 要使用的 upgrademodulepath,以 參考 形式提供,參考其他地方定義的路徑。自 Ant 1.9.7 起
nativeheaderdir 指定放置產生的原生標頭檔案的位置。自 Ant 1.9.8 起否,在 JDK 7 或更早版本編譯時會忽略
release 指定 --release 開關的值。
當設定並在 JDK 9+ 上執行時,sourcetarget 屬性以及 bootclasspath 將會被忽略。自 Ant 1.9.8 起
否,在 JDK 8 或更早版本編譯時會忽略

以巢狀元素指定的參數

此任務形成一個隱含的 FileSet,並支援大多數 <fileset> 的屬性(dir 變成 srcdir),以及巢狀的 <include><exclude><patternset> 元素。

srcdirclasspathsourcepathbootclasspathmodulepathmodulesourcepathupgrademodulepathextdirs

<javac>srcdirclasspathsourcepathbootclasspathextdirsmodulepathmodulesourcepathupgrademodulepath 屬性是 類別路徑結構,也可以透過巢狀的 <src>(注意名稱不同!)、<classpath><sourcepath><bootclasspath><extdirs><modulepath><modulesourcepath><upgrademodulepath> 元素分別設定。

compilerarg

您可以使用巢狀的 <compilerarg> 元素,為編譯器指定額外的命令列引數。這些元素的指定方式類似於 命令列引數,但有一個額外的屬性,可用於僅在使用特定編譯器實作時啟用引數。

屬性 說明 需要
value 請參閱 命令列引數 其中之一
line
file
path
prefix 請參閱 命令列引數自 Ant 1.8 起
suffix
compiler 僅在所選的編譯器實作與此屬性的值相符時,才傳遞指定的引數。合法值與上述 清單 中有效的編譯器相同。)

compilerclasspath

自 Ant 1.8.0 起

載入編譯器實作時,若已指定自訂類別,則持有要使用的類別路徑的 類別路徑結構。使用內建編譯器之一時,不會有任何影響。

實作 CompilerAdapter 型別的任何巢狀元素

自 Ant 1.8.0 起

如果已定義的型別實作 CompilerAdapter 介面,則可將該型別的巢狀元素用作 compiler 屬性的替代方案。

範例

編譯 .java 目錄下的所有檔案,並將 .class 檔案儲存在 .build 目錄中。所使用的類別路徑包含 xyz.jar,且已開啟使用偵錯資訊進行編譯。來源層級為 1.4,因此您可以使用 assert 陳述式。

<javac srcdir="${src}"
       destdir="${build}"
       classpath="xyz.jar"
       debug="on"
       source="1.4"/>

編譯 .java 目錄下的所有檔案,並將 .class 檔案儲存在 .build 目錄中。使用預設 javac 可執行檔分岔 Java 編譯器。來源層級為 1.2(類似於 1.11.3),且類別檔案也應該可以在 JDK 1.2+ 中執行。

<javac srcdir="${src}"
       destdir="${build}"
       fork="true"
       source="1.2"
       target="1.2"/>

編譯 .java 目錄下的所有檔案,並將 .class 檔案儲存在 .build 目錄中。使用名為 java$javac.exe 的可執行檔分岔 Java 編譯器。請注意,$ 符號需要用另一個符號進行跳脫。來源層級為 1.5,因此您可以使用泛型。

<javac srcdir="${src}"
       destdir="${build}"
       fork="java$$javac.exe"
       source="1.5"/>

編譯 .java 目錄下的檔案,並將 .class 檔案儲存在 ${build} 目錄中。所使用的類別路徑包含 xyz.jar,且已開啟偵錯資訊。僅使用 mypackage/p1mypackage/p2 下的檔案。mypackage/p1/testpackage 目錄中及以下的所有檔案都從編譯中排除。您未指定來源或目標層級,因此實際使用的值會取決於您使用 Ant 執行 JDK。

<javac srcdir="${src}"
       destdir="${build}"
       includes="mypackage/p1/**,mypackage/p2/**"
       excludes="mypackage/p1/testpackage/**"
       classpath="xyz.jar"
       debug="on"/>

這與前一個範例相同,但增加了第二個來源路徑,由屬性 src2 定義。也可以使用巢狀 <src> 元素來表示,如下所示

<javac destdir="${build}"
       classpath="xyz.jar"
       debug="on">
  <src path="${src}"/>
  <src path="${src2}"/>
  <include name="mypackage/p1/**"/>
  <include name="mypackage/p2/**"/>
  <exclude name="mypackage/p1/testpackage/**"/>
</javac>

如果您想執行不同 JDK 的 javac 編譯器,您應該告訴 Ant 在哪裡可以找到編譯器以及您將使用哪個版本的 JDK,以便它可以選擇正確的命令列開關。下列範例在新的程序中執行 JDK 1.1 javac,並使用正確的命令列開關,即使 Ant 在不同版本的 JVM 中執行

<javac srcdir="${src}"
       destdir="${build}"
       fork="yes"
       executable="/opt/java/jdk1.1/bin/javac"
       compiler="javac1.1"/>

注意:如果您只想編譯位於共用根目錄下特定套件中的來源檔案,請使用 include/exclude 屬性或 <include>/<exclude> 內嵌元素來過濾這些套件。請勿在 srcdir 屬性(或內嵌 <src> 元素)中包含套件結構的一部分,否則每次執行編譯目標時,Ant 都會重新編譯您的來源檔案。請參閱 Ant 常見問答集 以取得更多資訊。

如果您只想編譯明確指定的檔案並停用 javac 的預設搜尋機制,則可以取消設定 sourcepath 屬性

<javac sourcepath="" srcdir="${src}"
       destdir="${build}" >
  <include name="**/*.java"/>
  <exclude name="**/Example.java"/>
</javac>

這樣,javac 將會編譯 ${src} 目錄下的所有 Java 來源檔案,但會略過範例。如果某些非範例檔案參照範例檔案,編譯器甚至會產生錯誤。

如果您想使用特殊 JDK(與 Ant 目前使用的 JDK 不同)編譯,請設定 executablefork 屬性。使用 taskname 可以顯示在記錄中,這些設定是固定的。

<javac srcdir=""
       destdir=""
       executable="path-to-java14-home/bin/javac"
       fork="true"
       taskname="javac1.4"/>

如果您想啟用其他編譯器選項,例如 lint,您可以使用 <compilerarg> 元素

<javac srcdir="${src.dir}"
       destdir="${classes.dir}"
       classpathref="libraries">
  <compilerarg value="-Xlint"/>
</javac>

如果您想使用自訂 CompilerAdapter org.example.MyAdapter,您可以使用 compiler 屬性

<javac srcdir="${src.dir}"
       destdir="${classes.dir}"
       compiler="org.example.MyAdapter"/>

或定義一個類型並將其內嵌到任務中,如下所示

<componentdef classname="org.example.MyAdapter"
              name="myadapter"/>
<javac srcdir="${src.dir}"
       destdir="${classes.dir}">
  <myadapter/>
</javac>

在這種情況下,您的編譯器適配器可以支援自己的屬性和內嵌元素。

下列範例示範如何使用 Java 9+ 模組。

${src} 目錄下的單一模組中編譯所有 .java 檔案,並將 .class 檔案儲存在 ${build} 目錄中。編譯使用位於 modules 資料夾中的應用程式模組。來源層級為 9 以啟用模組。

<javac srcdir="${src}"
       destdir="${build}"
       includeantruntime="false"
       modulepath="modules"
       source="9"/>

編譯 .java 檔案在 gen/classeslin32/classeslin64/classes${src} 目錄下的所有原始碼模組。在 ${build} 目錄產生模組目錄。每個在 ${build} 目錄下產生的模組目錄包含 .class 檔案從對應的原始碼模組。* 是代表編譯模組集中任何模組名稱的代碼。{ ... , ... } 表示擴充的替代。編譯使用位於 modules 資料夾的應用程式模組。原始碼層級是 9 以啟用模組。

<javac modulesourcepath="${src}/*/{gen,lin{32,64}}/classes"
       destdir="${build}"
       includeantruntime="false"
       modulepath="modules"
       source="9"/>

Jikes 筆記

你需要 Jikes 1.15 或更新版本。

Jikes 支援一些額外的選項,可以在呼叫任務之前定義顯示在下面的屬性來設定。每個屬性的設定會在整個建置中對所有 <javac> 任務生效。Ant 開發人員知道這很醜陋而且不靈活 – 預期未來會有更好的解決方案。所有選項都是布林值,而且必須設定為 trueyes 才能解釋為除了 false 之外的任何東西。預設值,build.compiler.warningstrue,而其他都是 false

屬性 說明 預設值
build.compiler.emacs 啟用相容 emacs 的錯誤訊息。 false
build.compiler.fulldepend 啟用完整依賴性檢查;請參閱
Jikes 手冊中的 +F 開關。
false
build.compiler.pedantic 啟用嚴格警告。 false
build.compiler.warnings
已過時。改用 <javac>nowarn 屬性。
不要停用警告訊息。 true

Jvc 筆記

Jvc 會啟用 Microsoft 擴充,除非你在呼叫 <javac> 之前將屬性 build.compiler.jvc.extensions 設定為 false

Bootstrap 選項

Sun javac 編譯器有一個 -bootclasspath 命令列選項—這對應到 <javac> 任務的 bootclasspath 屬性/元素。Sun 編譯器也允許使用 -X-J-X 屬性對引導類別路徑進行更多控制。可以透過使用 <compilerarg> 來設定這些。自 Ant 1.6.0 起,有一個捷徑可以將路徑參照轉換成字串,可以在作業系統獨立的方式中使用(請參閱 pathshortcut)。例如

<path id="lib.path.ref">
  <fileset dir="lib" includes="*.jar"/>
</path>
<javac srcdir="src" destdir="classes">
  <compilerarg arg="-Xbootclasspath/p:${toString:lib.path.ref}"/>
</javac>

OpenJDK 筆記

javac 編譯器OpenJDK 專案提供,是一個開源專案。此專案的輸出為包含 javac 編譯器的 javac.jar。此編譯器可用於 <javac> 任務,並搭配 -Xbootclasspath/p Java 參數使用。參數必須提供給 javac 可執行檔的執行時期系統,因此需要加上 -J 前綴,例如

<property name="patched.javac.jar"
          location="${my.patched.compiler}/dist/lib/javac.jar"/>

<presetdef name="patched.javac">
  <javac fork="yes">
    <compilerarg value="-J-Xbootclasspath/p:${patched.javac.jar}"/>
  </javac>
</presetdef>


<patched.javac srcdir="src/java" destdir="build/classes"
               debug="yes"/>

package-info.java 注意事項

package-info.java 檔案在 Java 5 中引入,用於允許套件層級註解。在編譯時,如果 .java 檔案不包含執行時期註解,則不會有對應的 .class 檔案。在 Ant 1.7.1 之前,當 <javac> 任務再次執行時,任務會嘗試再次編譯 package-info.java 檔案。

在 Ant 1.7.1 中,引入了不同的邏輯,其中涉及通常會包含 .class 檔案的目錄的時間戳記。此邏輯導致 Ant 在某些設定中無法重新編譯 package-info.java

自 Ant 1.8.0 起,如果 Ant 編譯 package-info.java,且編譯器本身未建立 package-info.class 檔案,則會建立「空的」package-info.class 檔案。