Apache Ant 是一个 Java 的生成工具。据最初的创始人 James Duncan Davidson 介绍,这个工具的名称是 another neat tool( 另一个整洁的工具 ) 的首字母缩写。
生成工具在软件开发中用来将源代码和其他输入文件转换为可执行文件的形式 ( 也有可能转化为可安装的产品映像形式 ) 。随着应用程序的生成过程变得更加复杂,确保在每次生成期间都使用精确相同的生成步骤,同时实现尽可能多的自动化,以便几十产生一致的生成版本,这就变得更加重要了。 C 或 C++ 中的传统项目经常使用 make 工具来做这件事情,其中生成任务是通过调用 shell 命令来执行的,而依赖关系定义在每个生成文件之间,以便它们总是以必须的顺序执行。
Ant 和 make 类似,它也定义生成文件之间的依赖关系;然而,与使用特定于平台的 shell 命令来实现生成过程所不同的是,它使用跨平台的 Java 类。使用 Ant ,能够编写单个生成文件,这个生成文件在任何 Java 平台上都一致地操作 ( 因为 Ant 本身也是使用 Java 语言来实现的 ) ;这就是 Ant 最大的优势。
Ant 没有定义它自己的自定义语法;相反,它的生成文件是用 XML 编写的。存在一组 Ant 能够理解的预定义 XML 元素,而且还可以定义新的元素来扩展 Ant 的功能。每个生成文件由单个 project 元素组成,该元素又包含一个或者多个 target 元素。一个目标 (target) 是生成过程中已定义的一个步骤,它执行任意数量的操作,比如编译一组源文件。这些操作本身是由其它专有任务标签执行的,然后这些任务将根据需要被分组到各个 target 元素中。一次生成过程所必需的所有操作可以放入单个 target 元素中,这样通常更为可取。这样可以执行整体生成过程的单独部分,却不一定要执行其他部分。例如,通过仅调用某些目标,就可以编译项目的源代码,却不必创建可安装的项目映像。
顶级 project 元素需要包含一个 default 属性,如果在 Ant 被调用时没有指定目标,这个属性将指定要执行的目标。然后需要使用 target 元素来定义该目标本身。下面是一个最基本的生成文件:
<?xml version="1.0"?>
<project default="init">
<target name="init">
</target>
</project>
注意这是一个结构良好的 XML 文档,其中一个 XML 声明制订了所使用的 XML 版本 ( 这不是当前的 Ant 所必需的,但是这样做是一个好习惯 ) ,而且每个元素都正确地关闭了。一次性打开和关闭一个元素也是可以做到的。因此,与其像上面那样对 target 元素使用单独的起始和结束标签,我们可以将它写为如下形式:
<target name=”init”/>
当元素没有包含任何内容时,跟简练的形式会更清晰。
上一小节中的生成文件是优雅简练的,但它并没有包含多少关于正在生成的实际项目的信息。可以通过许多方式来使它更具描述性,同时无需改变其功能。下面是一个例子:
<?xml version="1.0"?>
<project default="init" name="Project Argon">
<description>
A simple project introducing the use of descriptive tags in Ant build files.
</description>
<!-- XML comments can also be used -->
<target name="init" description="Initialize Argon database">
<!-- perform initialization steps here -->
</target>
</project>
可以看出, XML 注释可以使用在整个生成文件中以提高清晰性。而且, Ant 定义了它自己的 Description 元素和 Description 属性,它们可用于提供更结构化的注释。
Ant 中的属性类似编程语言中的变量,它们都具有名称和值。然而与通常的变量不同,一经设置, Ant 中的属性就不可更改;它们是不可变的,就是 Java 语言中的 String 对象。这起初看是似乎很有限制性,但这样是为了遵循 Ant 的简单原则:毕竟,它是一个生成工具,而不是一种编程语言。如果尝试给某个现有属性赋予一个新的值,这不会被看作是一个错误,但是该属性仍然会保留其现有值。
基于元素的描述性名称和到现在位置所看多的属性,在 Ant 中用于设置属性的机制看起来如下就没有什么奇怪了:
<property name="metal" value="beryllium"/>
为了在生成文件的其它部分引用这个属性,可以使用以下语法:
${metal}
例如,为了使用这样一个值,它是另一个属性的值的组成部分,则标签将写为下面这样:
<property name="metal-database" value="${metal}.db"/>
Ant 中有很多预定义的属性。首先, Java 环境设置用于运行 Ant 的所有系统属性,均可作为 Ant 属性使用,比如 ${user.home}. 除了这些属性之外, Ant 还定义了它自己的一小组属性,包括 ${ant.version} ,这个属性包括 Ant 的版本;以及 ${basedir} ,这个属性是项目目录的绝对路径 ( 由包含生成文件的目录所定义,或者由 project 元素的可选 basedir 属性所定义 ) 。
属性经常用于引用文件系统上的文件和目录,但是对于使用不同路径分隔符 ( 例如, / 与 \) 的平台来说,这样可能在跨域不同平台时导致问题。 Ant 的 location 属性专门设计用于以平台无关的方式包含文件系统路径。可以使用 location 来代替 value :
<property name="database-file" location="archive/databases/${metal}.db"/>
用于 location 属性的路径分隔字符将被转换为当前平台的正确形式;而且由于文件名是相对的,它被认为是相对于项目的基目录。也可以写为下面这样:
<property name="database-file" location="archive\databases\${metal}.db"/>
这个标签的两个版本都会在不同的平台具有相同的行为。如果可移植性是必需的,唯一要避免的内容就是文件名中的 DOS 风格的驱动器号。在可能的地方使用相对路径名称而不是绝对路径名称,这样还会更加灵活。
生成一个项目一般需要许多步骤 ---- 例如首先要编译源代码,然后将它打包为 Java 归档文件 (Java Archive File , JAR) 。这其中许多步骤都具有清楚定义的顺序 ----- 例如,在编译器从源文件生成类文件之前,你不能打包类文件。与顺序指定的 target 所不同的是, Ant 采用一种更灵活的方式来定义依赖关系,就是 make 和类似的生成工具所做的那样。每个目标的定义依据的是在它在能够执行之前必须完成的其他所有目标。这是使用 target 元素的 depends 属性来实现的。例如:
<target name="init"/>
<target name="preprocess" depends="init"/>
<target name="compile" depends="init,preprocess"/>
<target name="package" depends="compile"/>
这种方法允许执行项目任何阶段的生成过程; Ant 会首先执行已定义的先决阶段。在上面的例子中,如果让 Ant 完成 compile 步骤,它将判断出需要首先执行 init 和 preprocess 这两个目标。 Init 目标不依赖其他任何目标,因此它将首先被执行。然后 Ant 检查 preprocess target ,发现它依赖 init 目标;由于已经执行了后者, Ant 不会再次执行它,因而开始执行 preprocess 目标。最后可以执行 compile 任务本身。注意目标出现在生成文件中的顺序并不重要:执行顺序是由 depends 属性唯一确定的。
Apache Ant 可通过各种不同的方式来调用。就其本身而言, Ant 是一个命令行形式的工具,通常从 UNIX 或 Linux shell 提示符或者 Windows 命令提示符调用,生成文件可使用文本编辑器来编写。如果要生成的项目是以这种方式开发的,那么这样调用 Ant 很好,但是许多人发现 IDE 更方便。大多数 IDE 都对 Ant 提供了某种程度的支持,因此在使用 IDE 的情况下,最起码,不必麻烦地离开 IDE 来执行命令行操作就能调用 Ant 生成任务。
在本节中,我们将考察如何从命令行使用 Ant ,并了解一些有用的命令行选项。然后简要了解一下开放源代码的 Eclipse 平台提供的 Ant 支持。
从命令提示符调用 Ant 可以简单得只需键入单独的 ant 、如果这样做, Ant 将使用默认的生成文件;该生成文件中指定的默认目标就是 Ant 尝试要生成的目标。还可以指定许多命令行选项,后面跟着任意数量的声明目标, Ant 将按顺序生成这其中的每个目标,并在此过程中解决所有依赖关系。下面是从命令行执行 Ant 生成任务的一些典型输出:
Buildfile: build.xml
init:
[mkdir] Created dir: E:\tutorials\ant\example\build
[mkdir] Created dir: E:\tutorials\ant\example\dist
compile:
[javac] Compiling 8 source files to E:\tutorials\ant\example\build
dist:
[jar] Building jar: E:\tutorials\ant\example\dist\example.jar
BUILD SUCCESSFUL
Total time: 2 seconds
随着我们继续本教程的学习,我们将弄明白所有这些输出意味着什么。
就像 make 工具默认情况下需找一个名为 makefile 的生成文件一样, Ant 需找一个名为 build.xml 的文件。因此,如果在生成文件使用这个名称,就不需在命令行指定它。当然,有时使用具有其他名称的生成文件更方便,在那样的情况下,需要对 Ant 使用 –buildfile<file> 参数 (-f<file> 是其简写形式 ) 。
另一个有用的选项是 -D ,它用于设置随后可以在生成文件中使用的属性。这对于配置想要以某种方式开始的生成过程是非常有用的。例如,为了将 name 属性设置为某个特定的值,那就会使用一个类似下面这样的选项:
-D metal=beryllium
这个功能可用于覆盖生成文件中初始属性设置。正如前面指出过的,属性的值已经设置就不能改动。 -D 标志在读取生成文件中的任何信息之前设置某个属性;由于生成文件中的指派落在这个初始指派之后,因此它不会改变其值。
由于 Ant 的普及性。大多数现代 IDE 现在都集成了对它的支持,其他许多 IDE 则在插件提供对它的支持。受支持的环境列表包括 JEdit 和 Jext 编辑器、 Borland JBuilder 、 IntelliJ IDEA 、 Java Development Environment for Emacs (JDEE) 、 NetBeans IDE 、 Eclipse 以及 WebSphere® Studio Application Developer 。