在本教程中,您将学习
Ant
这个
Java TM
项目生成工具。由于其灵活性和易用性,
Ant
很快在
Java
开发人员中流行开来,因此您有必要了解关于它的更多信息。
在继续学习本教程之前,你不需要具备先前的
Ant
经验或知识。我们将首先查看
Ant
生成文件(
build file
)的基本结构,并学习如何调用这个工具。我们将逐步完成为一个简单
Java
项目编写生成文件的步骤,然后考察
Ant
的其他一些有用功能,包括文件系统操作和模式匹配。最后编写一个扩展
Ant
功能的自己的
Java
类来结束本教程。
在学习本教程的过程中,我们将同时展示如何从命令行以及从其他开放源代码
Eclipse IDE
运行
Ant
。试验本教程中的例子不需要同时具备这两种环境;您可以选择其一,甚至选择某种不同的开发环境,只要该环境支持
Ant
。如果选择从命令行使用
Ant
,并且
Ant
还没有安装到机器上,您需要遵循
Ant
主页上的安装说明(请参阅
参考资料
以获得相关链接)。相反,如果决定仅使用
Eclipse
环境,您不需要单独安装
Ant
,因为
Eclipse
已经包括了它。如果还没有
Eclipse
,您可以从
Eclipse.org
(请参阅
参考资料
)下载
Eclipse
。
入门
谁应该学习本教程?
|
|
如果您正在编写 Java 代码却还没有使用 Ant ,那么本教程就是为您准备的。不管您当前是否在使用某种不同的生成工具,或者根本就没有使用生成工具,了解关于 Ant 的更多知识或许会促使您转而使用它。
如果已经在使用
Ant
,那么您仍然可能在本教程中发现一些有趣的东西。或许您会发现一些预料之外或无法完全理解的
Ant
行为;本教程将会帮助您。或者,也许您熟悉
Ant
的基础,但是还想知道诸如将生成文件链接起来、使用
CVS
知识库或编写自定义任务等高级主题;本教程将会介绍所有这些主题。
Ant
主要是设计用于生成
Java
项目的,但这并不是它唯一的用途。许多人发现它对其他任务也很有帮助。比如以跨平台的方式执行文件系统操作。此外,还有许多可用的第三方
Ant
任务,而编写自定义的
Ant
任务也是相对简单的,因此很容易针对特定的应用程序定制
Ant
。
关于作者
|
|
Matt Chapman 1996
是英国
Hursley
的
IBM Centre for Java Technology
的咨询软件工程师。他过去七年来一直致力于
Java
技术,包括
Java
虚拟机实现和各类平台、用户界面工具包
Swing
和
AWT
,以及近来为
Eclipse
平台所编写的工具。
Matt
拥有计算机科学方面的学位,并且还是一名
Sun
认证的
Java
程序员。可通过
mchapman@uk.ibm.com
与他联系。
Ant
基础
简介
本节将概述
Ant
的功能和优势,并讨论它的历史概况和日渐提高的普及性。然后我们通过考察一个最基础的生成文件的基本结构,直接进入对
Ant
基础的讨论。我们还会介绍
属性
和
依赖关系
的概念。
Ant
是什么?
|
|
Apache Ant
是一个基于
Java
的生成工具。据最初的创始人
James Duncan Davidson
介绍,这个工具的名称是
another neat tool
(另一个整洁的工具)
的首字母缩写。
生 成工具在软件开发中用来将源代码和其他输入文件转换为可执行文件的形式(也有可能转换为可安装的产品映像形式)。随着应用程序的生成过程变得更加复杂,确 保在每次生成期间都使用精确相同的生成步骤,同时实现尽可能多的自动化,以便及时产生一致的生成版本,这就变得更加重要了。
C
或
C++
中的传统项目经常使用
make
工具来做这件事情,其中生成任务是通过调用
shell
命令来执行的,而依赖关系定义在每个生成文件之间,以便它们总是以必需的顺序执行。
Ant
与
make
类似,它也定义生成文件之间的依赖关系;然而,与使用特定于平台的
shell
命令来实现生成过程所不同的是,它使用跨平台的
Java
类。使用
Ant
,您能够编写单个生成文件,这个生成文件在任何
Java
平台上都一致地操作(因为
Ant
本身也是使用
Java
语言来实现的);这就是
Ant
最大的优势。
Ant
的其他关键优势包括其突出的简单性和无缝地使用自定义功能来扩展它的能力。但愿您在完成本教程其余内容的学习之后,会欣赏
Ant
的这些优势。
Ant
简史
|
|
Ant
最初是
Tomcat
的一个内部组件,
Tomcat
是
Java Servlet
和
JavaServer Pages (JSP)
参考实现中使用的
servlet
容器。
Tomcat
代码基被捐赠给了
Apache
软件基金会;在那里它又成了
Apache Jakarta
项目的组成部分,该项目致力于为
Java
平台产生开放源代码的服务器端解决方案。
Ant
的有用性很快得到了认可,对它的使用遍布在其他
Jakarta
子项目中。因而,它自己也成了一个
Jakarta
子项目,其第一个独立版本于
2000
年
7
月发布。
从那以后,
Ant
的普及性已经不断地提高。它赢得了无数的行业大奖,并成为用于生成开放源代码
Java
项目的
事实上
的标准。
2002
年
11
月,这些成功得到了确认,
Ant
被提升为顶级
Apache
项目。
在本文编写之际,
Ant
的当前稳定版本是
1.5.4
,它支持
1.1
以后的所有
JDK
版本。下一个版本(即
1.6
版)的
beta
版也已经可用,这些版本需要
JDK 1.2
或更高版本。未来的
2.0
版也正在计划之中,它将涉及一次重大的体系结构重新设计。
Ant 2.0
将以改进的一致性和增强的功能为特色,同时仍然保持
Ant
的简单性、易于理解性和可扩展性等核心目标。
Ant
生成文件剖析
|
|
Ant 没有定义它自己的自定义语法;相反,它的生成文件是用 XML 编写的(请参阅 参考资料 )。存在一组 Ant 能够理解的预定义 XML 元素,而且就像您将在下一节中看到的一样,还可以定义新的元素来扩展 Ant 的功能。每个生成文件由单个 project 元素组成,该元素又包含一个或多个 target 元素。一个目标( target )是生成过程中已定义的一个步骤,它执行任意数量的操作,比如编译一组源文件。这些操作本身是由其他专用任务标签执行的,我们将在后面看到这一点。然后这些任务将根据需要被分组到各个 target 元素中。一次生成过程所必需的所有操作可以放入单个 target 元素中,但是那样会降低灵活性。将那些操作划分为逻辑生成步骤,每个步骤包含在它自己的 target 元素中,这样通常更为可取。这样可以执行整体生成过程的单独部分,却不一定要执行其他部分。例如,通过仅调用某些目标,您可以编译项目的源代码,却不必创建可安装的项目映像。
顶级
project
元素需要包含一个
default
属性,如果在
Ant
被调用时没有指定目标,这个属性将指定要执行的目标。然后需要使用
target
元素来定义该目标本身。下面是一个最基本的生成文件:
运行
Ant
简介
|
|
Apache Ant
可通过各种不同的方式来调用。就其本身而言,
Ant
是一个命令行形式的工具,通常从
UNIX
或
Linux shell
提示符或者
Windows
命令提示符调用,生成文件则使用您自己选择的文本编辑器来编写。如果要生成的项目是以这种方式开发的,那么这样调用
Ant
很好,但是许多人发现
IDE
更方便。大多数
IDE
都对
Ant
提供了某种程度的支持,因此在使用
IDE
的情况下,最起码,您不必麻烦地离开
IDE
来执行命令行操作就能调用
Ant
生成任务。
在本节中,我们将考察如何从命令行使用
Ant
,并了解一些有用的命令行选项。
然后简要了解一下开放源代码的
Eclipse
平台提供的
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
属性设置为某个特定的值,您会使用一个类似下面这样的选项:
-Dmetal=beryllium
这个功能可用于覆盖生成文件中的初始属性设置。正如前面指出过的,属性的值一经设置就不能改变。
-D
标志在读取生成文件中的任何信息之前设置某个属性;由于生成文件中的指派落在这个初始指派之后,因此它不会改变其值。
IDE
集成
|
|
由于 Ant 的普及性,大多数现代 IDE 现在都集成了对它的支持,其他许多 IDE 则在插件提供对它的支持。受支持的环境列表包括 JEdit 和 Jext 编辑器、 Borland JBuilder 、 IntelliJ IDEA 、 Java Development Environment for Emacs (JDEE) 、 NetBeans IDE 、 Eclipse 以及 WebSphere? Studio Application Developer 。
Eclipse
对
Ant
的支持
|
|
开放源代码的
Eclipse
项目提供了对
Ant
的大量支持。
这些支持的核心是
Eclipse
的
Ant
编辑器,它以语法高亮显示为特色。该编辑器图示如下:
这个编辑器提供内容辅助
――
例如,键入
<pro
然后按
Ctrl-Space
,这样将会显示一个自动完成列表,其中包含
<property>
标签,以及对该任务的简要说明。
您还可以看到一个大纲视图,它显示生成文件的结构,并提供在该文件中导航的便捷方式。此外还有一个
Ant
视图,它允许根据许多不同的
Ant
文件生成目标。
从
Eclipse
内运行
Ant
生成任务
|
|
名为
build.xml
的文件在
Eclipse
的导航程序视图中使用一个
Ant
图标来标识和装饰。(如果您的生成文件具有不同的名称,请参阅
Eclipse 中的文件关联
。)右键单击这些文件会提供一个
Run Ant...
菜单选项,选择这个菜单选项将打开一个类似如下的对话框:
来自该生成文件的所有目标都显示出来了,而默认的目标则处于选中状态。在您决定是否要改变默认目标之后,请按
Run
按钮来运行
Ant
。
Eclipse
将切换到
Console
视图,如下图所示。错误将以不同的颜色显示出来,可以单击输出中的任务名称来跳到生成文件中的对应调用点。
Eclipse
中的文件关联
|
|
默认情况下, Eclipse 仅对名为 build.xml 的文件使用 Ant 编辑器,不过可以容易地配置该编辑器,使其识别具有其他名称的文件。从菜单上选择 Window=>Preferences ,然后展开 Workbench 组,再选择 File Associations 参数设置页面。然后为预期的文件名添加一种新的文件类型。例如,可以为名为 mybuild.xml 的所有文件添加一种新的文件类型。如果想对具有 .xml 后缀的所有文件(特殊文件名除外,比如 plugin.xml ,它在 Eclipse 中覆盖通配符指定)做同样的事情,您甚至可以使用 *.xml 。 最后为这种新的文件类型添加一个关联的编辑器,然后从编辑器列表上选择 Ant editor ,如下所示:
生成一个简单
Java
项目
简介
|
|
现在我们已经清楚了
Ant
生成文件的格式,并了解了如何定义属性和依赖关系以及如何运行
Ant
,下面可以开始为一个基本的
Java
项目构建一个生成环境了。这将包括学习用于编译源代码和组合
JAR
文件的
Ant
任务。
编译源代码
|
|
由于 Ant 的主要目标是生成 Java 应用程序,它能够内在地、出色地支持调用 javac 编译器以及其他 Java 相关任务就毫不奇怪了。下面是编译 Java 代码的任务的编写方式:
<javac srcdir="src"/>
这个标签寻找
src
目录中以
.java
为扩展名的所有文件,并对它们调用
javac
编译器,从而在相同的目录中生成类文件。当然,将类文件放在一个单独的目录结构中通常会更清晰;可以通过添加
destdir
属性来让
Ant
做到这点。其他有用的属性包括:
- classpath:等价于javac的-classpath选项。
- debug="true":指示编译器应该带调试信息编译源文件。
javac
任务的一个重要特点在于,它仅编译那些它认为需要编译的源文件。如果某个类文件已经存在,并且对应的源文件自从该类文件生成以来还没有改变过,那么该源文件就不会被重新编译。
javac
任务的输出显示了实际被编译的源文件的数目。编写一个
clean
目标来从目标目录移除生成的任何类文件是个很好的习惯。如果想要确保所有源文件都已编译,就可以使用这个任务。这种行为刻画了
Ant
的许多任务的特点:如果某个任务能够确定所请求的操作不需要执行,那么该操作就会被跳过。
像
Ant
一样,
javac
编译器本身也是用
Java
语言实现的。这对
Ant
中的
javac
任务的使用来说非常有利,因为它通常调用
Ant
运行所在的相同
Java
虚拟机(
JVM
)中的编译器类。在每次需要编译
Java
代码时,其他生成工具通常需要运行一个新的
javac
进程,从而需要一个新的
JVM
实例。但是在使用
Ant
的情况下,只需要单个
JVM
实例,它既用于运行
Ant
本身,也用于执行所有必需的编译任务(以及其他相关任务,比如处理
JAR
文件)。这是一种高效得多的资源使用方式,能够极大地缩短项目生成时间。
编译器选项
|
|
正如我们从前一小节看到的,
Ant
的
javac
任务的默认行为是调用运行
Ant
本身的任何
JVM
的标准编译器。然而,有时您可能想要单独地调用编译器
――
例如当你希望指定编译器的某些内存选项,或者需要使用一种不同级别的编译器的时候。为实现这个目的,只需将
javac
的
fork
属性设置为
true
,比如像下面这样:
<javac srcdir="src" fork="true"/>
如果想要指定一个不同的
javac
可执行文件,并向它传递一个最大内存设置,您可以像下面这样做:
<javac srcdir="src" fork="true" executable="d:\sdk141\bin\javac"
memoryMaximumSize="128m"/>
甚至可以将
Ant
配置为使用某种不同的编译器。受支持的编译器包括开放源代码的
Jikes
编译器和来自
GNU
编译器集(
GNU Compiler Collection
,
GCC
)的
GCI
编译器。(请参阅
参考资料
以了解关于这两种编译器的更多信息。)可以通过两种方式指定这些编译器:可以设置
build.compiler
属性,这将应用于使用
javac
任务的所有场合;或根据需要设置每个
javac
任务中的
compiler
属性。
创建
JAR
文件
|
|
在编译
Java
源文件之后,结果类文件通常被打包到一个
JAR
文件中,这个文件类似
zip
归档文件。每个
JAR
文件都包含一个清单文件,它可以指定该
JAR
文件的属性。
下面是
Ant
中
jar
任务的一个简单使用例子:
<jar destfile="package.jar" basedir="classes"/>
这将创建一个名为
package.jar
的
JAR
文件,并把
classes
目录中的所有文件添加到其中(
JAR
文件能够包含任意类型的文件,而不只是类文件)。此处没有指定清单文件,因此
Ant
将提供一个基本的清单文件。
manifest
属性允许指定一个用作该
JAR
文件的清单的文件。清单文件的内容还可以使用
manifest
任务在生成文件中指定。这个任务能够像文件系统写入一个清单文件,或者能够实际嵌套在
jar
之内,以便一次性地创建清单文件和
JAR
文件。
例如:
<jar destfile="package.jar" basedir="classes">
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-class" value="package.Main"/>
</manifest>
</jar>
时间戳生成
|
|
在生成环境中使用当前时间和日期,以某种方式标记某个生成任务的输出,以便记录它是何时生成的,这经常是可取的。这可能涉及编辑一个文件,以便插入一个字符串来指定日期和时间,或将这个信息合并到
JAR
或
zip
文件的文件名中。
这种需要是通过简单但是非常有用的
tstamp
任务来解决的。这个任务通常在某次生成过程开始时调用,比如在一个
init
目标中。这个任务不需要属性,许多情况下只需
<tstamp/>
就足够了。
tstamp
不产生任何输出;相反,它根据当前系统时间和日期设置
Ant
属性。下面是
tstamp
设置的一些属性、对每个属性的说明,以及这些属性可被设置到的值的例子:
属性
|
说明
|
例子
|
DSTAMP
|
设
|