Javac

描述

编译 Java 源代码树。

源代码目录和目标目录将被递归扫描以查找要编译的 Java 源代码文件。只有没有对应 .class 文件或 .class 文件比 .java 文件旧的 .java 文件才会被编译。

注意:Apache Ant 只使用源代码文件和类文件的名称来查找需要重新构建的类。它不会扫描源代码,因此不会了解嵌套类、与源代码文件名称不同的类等。有关基于除存在/修改时间之外的其他因素的依赖项检查,请参阅 <depend> 任务。

当源代码文件是包的一部分时,源代码树的目录结构应遵循包层次结构。

可以细化要编译的文件集。这可以通过 includesincludesfileexcludesexcludesfile 属性来完成。使用 includesincludesfile 属性,您可以指定要包含的文件。使用 excludeexcludesfile 属性来指定要排除的文件。在这两种情况下,文件列表都可以通过文件名来指定,该文件名相对于 srcdir 属性中指定的目录或嵌套的 <src> 元素,或者通过使用通配符模式来指定。有关如何包含/排除文件以及如何编写通配符模式的信息,请参阅有关 基于目录的任务 的部分。

可以使用不同的编译器。这可以通过设置全局 build.compiler 属性来指定,该属性将影响整个构建过程中的所有 <javac> 任务,通过设置特定于当前 <javac> 任务的 compiler 属性来指定,或者通过使用任何 typedeffed 或 componentdeffed 类型的嵌套元素来指定,该类型实现 org.apache.tools.ant.taskdefs.compilers.CompilerAdapterbuild.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。如果您使用 compiler=javac1.1 并且(例如)depend=true,Ant 将使用命令行开关 -depend 而不是 -Xdepend

此任务将从传递给编译器的类路径中删除所有指向不存在的文件/目录的条目。

分叉可执行文件(如果有)的工作目录是项目的基目录。

Windows 注意:当在 Windows 上以非分叉模式使用 modern 编译器时,它会锁定 <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= 否;默认为 srcdir,除非指定了嵌套的 <src> 元素
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(或 gcj-fsource)开关。
否;默认情况下,除非设置了神奇的 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 编译器需要编译依赖类以获取泛型信息。一个示例记录在错误报告中:Bug 40776 - 使用泛型编译 Java 5 项目的问题。将属性设置为 false 将导致编译器重新编译依赖类。自 Ant 1.7.1 起 否;默认值为 true
createMissingPackageInfoClass 一些 package-info.java 文件中的包级注释不会创建任何 package-info.class 文件,因此 Ant 会每次都重新编译同一个文件。
自 Ant 1.8 起,如果编译器没有为每个 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 属性的替代方案。

示例

编译 ${src} 目录下的所有 .java 文件,并将 .class 文件存储在 ${build} 目录中。使用的类路径包括 xyz.jar,并且打开了调试信息。源级别为 1.4,因此可以使用 assert 语句。

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

编译 ${src} 目录下的所有 .java 文件,并将 .class 文件存储在 ${build} 目录中。Java 编译器使用默认的 javac 可执行文件进行分叉。源级别为 1.2(类似于 1.11.3),并且类文件也应该在 JDK 1.2+ 下可运行。

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

编译 ${src} 目录下的所有 .java 文件,并将 .class 文件存储在 ${build} 目录中。Java 编译器使用名为 java$javac.exe 的可执行文件进行分叉。请注意,$ 符号需要用第二个符号进行转义。源级别为 1.5,因此可以使用泛型。

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

编译 ${src} 目录下的 .java 文件,并将 .class 文件存储在 ${build} 目录中。使用的类路径包括 xyz.jar,并且调试信息已打开。仅使用 mypackage/p1mypackage/p2 下的文件。将 mypackage/p1/testpackage 目录及其子目录中的所有文件从编译中排除。您没有指定源级别或目标级别,因此使用的实际值将取决于您使用哪个 JDK 运行 Ant。

<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"/>

编译 ${src} 目录下所有源模块中的 gen/classeslin32/classeslin64/classes 中的所有 .java 文件。在 ${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 说明

除非您在调用 <javac> 之前将属性 build.compiler.jvc.extensions 设置为 false,否则 Jvc 将启用 Microsoft 扩展。

引导选项

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 说明

OpenJDK 项目提供了一个名为 javac 的开源 编译器。该项目输出一个名为 javac.jar 的文件,其中包含 javac 编译器。可以使用 -Xbootclasspath/p Java 参数,将该编译器与 <javac> 任务一起使用。该参数需要传递给 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 文件。