目标

目标是任务和数据类型的容器,它们在构建过程中协同工作以达到所需状态。

目标可以依赖于其他目标,Apache Ant 确保这些其他目标在当前目标执行之前已执行。例如,您可能有一个用于编译的目标和一个用于创建可分发文件的目标。只有在先编译之后才能构建可分发文件,因此分发目标 *依赖于* 编译目标。

Ant 尝试按 depends 属性中出现的顺序(从左到右)执行目标。请记住,当较早的目标依赖于它时,目标可能会更早执行。

<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>

假设我们要执行目标 D。从它的 depends 属性来看,您可能认为首先执行目标 C,然后是 B,最后是 A。错了!C 依赖于 B,B 依赖于 A,所以首先执行 A,然后是 B,然后是 C,最后是 D。

Call-Graph:  A → B → C → D

在从给定目标(如上面的 D)向后延伸的依赖链中,每个目标只执行一次,即使多个目标依赖于它。因此,执行 D 目标将首先导致调用 C,C 又将首先调用 B,B 又将首先调用 A。在 A、B 和 C 执行后,执行将返回到 D 的依赖列表,它 **不会** 调用 B 和 A,因为它们已经在处理 C 和 B 的依赖关系(分别作为 D 的依赖关系)时被调用了。如果在处理 C 和 B 时没有发现此类依赖关系,则在处理 D 的依赖列表时,B 和 A 将在 C 之后执行。

目标还具有在设置(或未设置)属性的情况下执行其执行的能力。例如,这允许根据系统状态(Java 版本、操作系统、命令行属性定义等)更好地控制构建过程。要使目标 *感知* 此属性,您应该添加 if(或 unless)属性,其中包含目标应该响应的属性的名称。**注意:**在最简单的情况下,Ant 只会检查属性是否已设置,值无关紧要,但使用属性扩展,您可以构建更复杂的条件。有关更多详细信息,请参阅 属性页面。例如

<target name="build-module-A" if="module-A-present"/>
<target name="build-own-fake-module-A" unless="module-A-present"/>

在第一个示例中,如果 module-A-present 属性已设置(设置为任何值,例如 false),则将运行目标。在第二个示例中,如果 module-A-present 属性已设置(同样,设置为任何值),则不会运行目标。

if/unless 属性中只能指定一个属性名称。如果您想检查多个条件,可以使用依赖目标来计算检查结果。

<target name="myTarget" depends="myTarget.check" if="myTarget.run">
    <echo>Files foo.txt and bar.txt are present.</echo>
</target>

<target name="myTarget.check">
    <condition property="myTarget.run">
        <and>
            <available file="foo.txt"/>
            <available file="bar.txt"/>
        </and>
    </condition>
</target>
Call-Graph:  myTarget.check → maybe(myTarget)

如果没有 ifunless 属性,目标将始终执行。

**重要:**ifunless 属性仅启用或禁用它们所附加的目标。它们不控制条件目标所依赖的目标是否执行。事实上,它们甚至不会在目标即将执行并且所有其前身都已运行之前进行评估。

可选的 description 属性可用于提供此目标的单行描述,该描述由 -projecthelp 命令行选项打印。没有此类描述的目标被视为内部目标,不会列出,除非使用 -verbose-debug 选项。

将您的 tstamp 任务放在所谓的 *初始化* 目标中是一个好习惯,所有其他目标都依赖于它。确保该目标始终是其他目标依赖列表中的第一个目标。在本手册中,大多数初始化目标的名称为 "init"

<project>
    <target name="init">
        <tstamp/>
    </target>
    <target name="otherTarget" depends="init">
        ...
    </target>
</project>

特别是如果您只有几个任务,您也可以将这些任务直接放在项目标签下(*从 Ant 1.6.0 开始*)。

<project>
    <tstamp/>
</project>

如果设置了 depends 属性和 if/unless 属性,则首先执行 depends 属性。

目标具有以下属性

属性 描述 必需
name 目标的名称。
depends 此目标依赖的目标名称的逗号分隔列表。
if 必须设置的属性的名称,以便此目标执行,或 评估为 true 的内容
unless 必须未设置的属性的名称,以便此目标执行,或 评估为 false 的内容
description 此目标功能的简短描述。
extensionOf 将当前目标添加到命名 扩展点 的依赖列表中。*从 Ant 1.8.0 开始*。
onMissingExtensionPoint 如果此目标尝试扩展缺少的 扩展点,该怎么办。(failwarnignore)。*从 Ant 1.8.2 开始*。 否;除非存在 extensionOf,否则不允许,默认为 fail

目标名称可以是 XML 文件编码中有效的任何字母数字字符串。空字符串 属于此集合,逗号 , 和空格   也是如此。请避免使用它们,因为它们在未来的 Ant 版本中将不受支持,因为它们在命令行和 IDE 上会导致混淆。IDE 对不寻常的目标名称或包含空格的任何目标名称的支持因 IDE 而异。

以连字符开头的目标,例如 -restart 是有效的,可以用来命名不应该直接从命令行调用的目标。
对于 Ant 的主类,每个以连字符开头的选项都是 Ant 本身的选项,而不是目标。因此,无法从命令行调用这些目标。另一方面,IDE 通常不使用 Ant 的主类作为入口点,因此通常可以从 IDE 调用它们。

扩展点

从 Ant 1.8.0 开始.

扩展点类似于目标,它们具有名称和 depends 列表,可以从命令行执行。就像目标一样,它们代表构建过程中的一个状态。

与目标不同,它们不包含任何任务,它们的主要目的是收集在它们的 depends 列表中为所需状态做出贡献的目标。

目标可以通过它们的 extensionOf 属性将自己添加到扩展点的 depends 列表中。添加自己的目标将在扩展点的显式 depends 属性的目标之后添加,如果多个目标添加自己,它们的相对顺序未定义。

扩展点的主要目的是充当为 导入 而设计的构建文件的扩展点。在导入的文件中,扩展点定义了一个必须达到的状态,来自其他构建文件中的目标可以加入该扩展点的 depends 列表,以贡献该状态。

例如,您的导入构建文件可能需要编译代码,它可能看起来像

<target name="create-directory-layout">
   ...
</target>
<extension-point name="ready-to-compile"
              depends="create-directory-layout"/>
<target name="compile" depends="ready-to-compile">
   ...
</target>
Call-Graph:  create-directory-layout → 'empty slot' → compile

并且您需要在编译之前生成一些源代码,然后在您的主构建文件中,您可能会使用类似的东西

<target name="generate-sources"
        extensionOf="ready-to-compile">
   ...
</target>
Call-Graph:  create-directory-layout → generate-sources  → compile

这将确保在 compile 目标之前执行 generate-sources 目标。

不要依赖于 depends 列表的顺序,如果 generate-sources 依赖于 create-directory-layout,那么它必须通过自己的 depends 属性显式依赖于它。