ANT 使用指南 第一章入门 ................................................................................................. 2 本教程所讲述的内容 ................................................................................................................. 2 谁应该学习本教程? ...................................................................................................................... 2 关于作者 ........................................................................................................................................ 2 基础知识 ........................................................................................................................................ 2 简介 ................................................................................................................................................. 3 ANT 是什么? ............................................................................................................................ 3 ANT 简史...................................................................................................................................... 3 安装 ANT ......................................................................................................................................... 4 系统需求 ........................................................................................................................................ 4 BUILDING ANT ............................................................................................................................... 5 ANT 生成文件剖析 ................................................................................................................... 5 第一章入门 本教程所讲述的内容 在本教程中,您将学习 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。 关于作者 基础知识 在使用 Ant 的时候应当了解 xml,至少要了解 Html。 第二章 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.6,它支持 1.1 以后的所有 JDK 版本。下一个版本(即 1.7 版)的 beta 版也已经可用,这些版本需要 JDK1.2 或 更高版本。未来的 2.0 版也正在计划之中,它将涉及一次重大的体系结构重新 设计。Ant 2.0 将以改进的一致性和增强的功能为特色,同时仍然保持 Ant 的简 单性、易于理解性和可扩展性等核心目标。 安装 Ant 由于 Ant 是一个 Open Source 的软件,所以有两种安装 Ant 的方式,一种是 用已编译好的 binary 文件安装 Ant,另一种是用源代码自己 build Ant。binary 形式的 Ant 可以从 http://jakarta.apache.org/builds/ant/release/v1.4.1/bin 下载。如果你希望你能自己编译 Ant ,则可从 http://jakarta.apache.org/builds/ant/release/v1.4.1/src。 注意所列出的连接都是最新发行版的 Ant。如果你读到此文时,发现已经有 了更新的版本,那么请用新版本。如果你是一个疯狂的技术追求者,你也可以从 Ant CVS repository 下载最新版本的 Ant。 系统需求 要想自己 build Ant。你需要一个 JAXP 兼容的 XML 解析器(parser)放在 你的 CLASSPATH 系统变量中。binary 形式的 Ant 包括最新版的 Apache Crimson XML 解析器。你可以从 http://java.sun.com/xml/ 得到更多的关于 JAXP 的信息。如果 你希望使用其他的 JAXP 兼容的解析器。你要从 Ant 的 lib 目录中删掉 jaxp.jar 以及 crimson.jar。然后你可将你心爱的解析器的 jar 文件放到 Ant 的 lib 目录 中或放在你的 CLASSPATH 系统变量中。 对于当前版本的 Ant,需要你的系统中有 JDK。 binary 版的 Ant 包括三个目录:bin, docs 和 lib。只有 bin 和 lib 目录是 运行 Ant 所需的。要想安装 Ant,选择一个目录并将发行版的文件拷贝到该目录 下。这个目录被称作 ANT_HOME。在你运行 Ant 之前需要做一些配置工作。将 bin 目录加入 PATH 环境变量。 设定 ANT_HOME 环境变量,指向你安装 Ant 的目录。 在一些 OS 上,Ant 的脚本可以猜测 ANT_HOME(Unix 和 Windos NT/2000)-但最 好不要依赖这一特性。 可选地,设定 JAVA_HOME 环境变量(参考下面的高级小 节),该变量应该指向你安装 JDK 的目录。 注意:不要将 Ant 的 ant.jar 文件放到 JDK/JRE 的 lib/ext 目录下。Ant 是 个应用程序,而 lib/ext 目录是为 JDK 扩展使用的(如 JCE,JSSE 扩展)。而且 通过扩展装入的类会有安全方面的限制。 要想运行 Ant 必须使用很多的变量。你至少参考需要下面的内容:Ant 的 CLASSPATH 必须包含 ant.jar 以及你所选的 JAXP 兼容的 XML 解析器的 jar 文件。 当你需要JDK的功能(如javac或rmic task)时,对于JDK 1.1,JDK的classes.zip 文件必须放入 CLASSPATH 中;对于 JDK 1.2 或 JDK 1.3,则必须加入 tools.jar。 如果设定了正确的 JAVA_HOME 环境变量,Ant 所带的脚本,在 bin 目录下,会自 动加入所需的 JDK 类。 当你执行特定平台的程序(如 exec task 或 cvs task) 时,必须设定 ant.home 属性指向 Ant 的安装目录。同样,Ant 所带的脚本利用 ANT_HOME 环境变量自动设置该属性。 Building Ant 要想从源代码build Ant,你要先安装Ant源代码发行版或从CVS中checkout jakarta-ant 模块。安装好源代码后,进入安装目录。设定 JAVA_HOME 环境变量 指向 JDK 的安装目录。要想知道怎么做请参看安装 Ant 小节。 确保你已下载了任何辅助 jar 文件,以便 build 你所感兴趣的 task。这些 jar 文件可以放在 CLASSPATH 中,也可以放在 lib/optional 目录下。参看依赖库小 节可知不同的 task 需要那些 jar 文件。注意这些 jar 文件只是用作 build Ant 之用。 Ant 生成文件剖析 Ant 没有定义它自己的自定义语法;相反,它的生成文件是用 XML 编写 的。存在一组 Ant 能够理解的预定义 XML 元素,而且就像您将在下一节中看 到的一样,还可以定义新的元素来扩展 Ant 的功能。每个生成文件由单个 project 元素组成,该元素又包含一个或多个 target 元素。一个目标(target)是生成过 程中已定义的一个步骤,它执行任意数量的操作,比如编译一组源文件。这些操 作本身是由其他专用任务标签执行的,我们将在后面看到这一点。然后这些任务 将根据需要被分组到各个 target 元素中。一次生成过程所必需的所有操作可以 放入单个 target 元素中,但是那样会降低灵活性。将那些操作划分为逻辑生成步 骤,每个步骤包含在它自己的 target 元素中,这样通常更为可取。这样可以执 行整体生成过程的单独部分,却不一定要执行其他部分。例如,通过仅调用某些 目标,您可以编译项目的源代码,却不必创建可安装的项目映像。 顶级 project 元素需要包含一个 default 属性,如果在 Ant 被调用时没有指 定目标,这个属性将指定要执行的目标。然后需要使用 target 元素来定义该目 标本身。下面是一个最基本的生成文件: 注意这是一个结构良好的 XML 文档,其中一个 XML 声明指定了所使用 的 XML 的版本(这不是当前的 Ant 所必需的,但是这样做是一个好习惯),而 且每个元素都正确地关闭了。一次性打开和关闭一个元素也是可以做到的。因此, 与其像上面那样对 target 元素使用单独的起始和结束标签, 我们可以将它写为如下形式: 当元素没有包含任何内容时,更简练的形式会更清晰。 添加描述: 我们在前一小节中看到的生成文件是优雅简练的,但它并没有包含多少关于 正在生成的实际项目的信息。可以通过许多方式来使它更具描述性,同时无需改 变其功能。下面是一个例子: A simple project introducing the use of descriptive tags in Ant build files. 可以看出,XML 注释可以使用在整个生成文件中以提高清晰性。而且,Ant 定义了它自己的 description 元素和 description 属性,它们可用于提供更结构化 的注释。 属性 Ant 中的属性类似编程语言中的变量,它们都具有名称和值。然而与通常的 变量不同,一经设置,Ant 中的属性就不可更改;它们是不可变的,就像 Java 语 言中的 String 对象。这起初看来似乎很有限制性,但这样是为了遵循 Ant 的简 单原则:毕竟,它是一个生成工具,而不是一种编程语言。如果尝试给某个现有 属性赋予一个新的值,这不会被看作是一个错误,但是该属性仍然会保留其现有 值。 基于元素的描述性名称和到目前为止所见到的属性,在 Ant 中用于设置属 性的机制看起来如下就没有什么奇怪了: 为了在生成文件的其他部分引用这个属性,您会使用以下语法: ${metal} 例如,为了使用这样一个值,它是另一个属性的值的组成部分,您会将标签写为 下面这样: Ant 中有许多预定义的属性。首先,Java 环境设置用于运行 Ant 的所有系 统属性,均可作为 Ant 属性使用,比如 ${user.home} 。除了这些属性之外, Ant 还定义了它自己的一小组属性,包括${ant.version} ,这个属性包含 Ant 的 版本;以及${basedir},这个属性是项目目录的绝对路径(由包含生成文件的目 录所定义,或者由 project 元素的可选 basedir 属性所定义)。 属性经常用于引用文件系统上的文件或目录,但是对于使用不同路径分隔符 (例如,/ 与 \)的平台来说,这样可能在跨越不同平台时导致问题。Ant 的 location 属性专门设计用于以平台无关的方式包含文件系统路径。您会像下面这 样使用 location 来代替 value: 用于 location 属性的路径分隔字符将被转换为当前平台的正确格式;而且 由于文件名是相对的,它被认为是相对于项目的基目录。我们同样可以容易地写 为下面这样: 这个标签的两个版本都会在不同的平台具有相同的行为。如果可移植性是必 需的,唯一要避免的内容就是文件名中的 DOS 风格的驱动器号。在可能的地方 使用相对路径名称而不是绝对路径名称,这样还会更加灵活。 定义依赖关系 生成一个项目一般需要许多步骤—— 例如首先要编译源代码,然后将它打包为 Java 归档文件 (Java Archive File,JAR)。这其中许多步骤都具有清楚定义的顺序—— 例如,在编译器从源代码生成类文件之前,您不能打包类文件。与顺序指定 target 所不同的是,Ant 采用一种更灵活的方法来定义依赖关系,就像 make 和 类似的生成工具所做的那样。每个目标的定义依据的是在它在能够执行之前必须 完成的其他所有目标。这是使用 target 元素的 depends 属性来实现的。例如: 这种方法允许您执行项目任何阶段的生成过程;Ant 会首先执行已定义的先 决阶段。在上面的例子中,如果让 Ant 完成 compile 步骤,它将判断出需要首 先执行 init 和 preprocess 这两个目标。init 目标不依赖其他任何目标,因此它将 首先被执行。然后 Ant 检查 preprocesstarget ,发现它依赖 init 目标;由于已 经执行了后者,Ant 不会再次执行它,因而开始执行 preprocess 目标。最后可 以执行 compile 任务本身。注意目标出现在生成文件中的顺序并不重要:执行 顺序是由 depends 属性唯一确定的。 Projects project 有下面的属性: AttributeDescriptionRequired name 项目名称.No default 当没有指定 target 时使用的缺省 targetYes basedir 用于计算所有其他路径的基路径。该属性可以被 basedir property 覆盖。当覆盖时,该属性被忽略。如果属性和 basedir property 都没有设定, 就使用 buildfile 文件的父目录。项目的描述以一个顶级的元素 的形式出现一个项目可以定义一个或多个 target。一个 target 是一系列你想要 执行的。执行 Ant 时,你可以选择执行那个 target。 当没有给定 target 时,使用 project 的 default 属性所确定的 target。 Targets 一个 target 可以依赖于其他的 target。例如,你可能会有一个 target 用 于编译程序,一个 target 用于生成可执行文件。你在生成可执行文件 之前必须先编译通过,所以生成可执行文件的 target 依赖于编译 target。Ant 会处理这种依赖关系然而,应当注意到,Ant 的 depends 属性只指定了 target 应该被执行的顺序-如果被依赖的 target 无法运行,这种 depends 对于指定了 依赖关系的 target 就没有影响。Ant 会依照 depends 属性中 target 出现的顺序 (从左到右)依次执行每个 target。然而,要记住的是只要某个 target 依赖于 一个 target,后者就会被先执行。 假定我们要执行 target D。从它的依赖属性来看,你可能认为先执行 C,然 后 B,最后 A 被执行。错了,C 依赖于 B,B 依赖于 A,所以先执行 A, 然后 B,然后 C,最后 D 被执行。一个 target 只能被执行一次,即时有多个 target 依赖于它(看上面的例子)。如果(或如果不)某些属性被设定,才执行某个 target。这样,允许根据系统的状态(java version, OS, 命令行属性定义等等) 来更好地控制 build 的过程。要想让一个 target 这样做,你就应该在 target 元素中,加入 if(或 unless)属性,带上 target 因该有所判断的属性。例如: 如果没有 if 或 unless 属性,target 总会被执行。可选的 description 属 性可用来提供关于 target 的一行描述,这些描述可由-projecthelp 命令行选项 输出。将你的 tstamp task 在一个所谓的初始化 target 是很好的做法,其他的 target 依赖这个初始化 target。要确保初始化 target 是出现在其 他 target 依赖表中的第一个 target。在本手册中大多数的初始化 target 的名 字是"init"。 target 有下面的属性: AttributeDescriptionRequired nametarget 的名字 Yes depends 用逗号分隔的 target 的名字列表,也就是依赖表。 if 执行 target 所需要设定的属性名。 unless 执行 target 需要清除设定的属性名。 description 关于 target 功能的简短描述。 Tasks 一个 task 是一段可执行的代码。一个 task 可以有多个属性(如果你愿意的 话,可以将其称之为变量)。属性只可能包含对 property 的引用。这些引用会在 task 执行前被解析。下面是 Task 的一般构造形式: 这里 name 是 task 的名字,attributeN 是属性名,valueN 是属性值。有一 套内置的(built-in)task,以及一些可选 task,但你也可以编写自己的 task。 所有的 task 都有一个 task 名字属性。Ant 用属性值来产生日志信息。 可以给 task 赋一个 id 属性: 这里 taskname 是 task 的名字,而 taskID 是这个 task 的唯一标识符。通过 这个标识符,你可以在脚本中引用相应的 task。例如,在脚本中你可以这样: 设定某个 task 实例的 foo 属性。在另一个 task 中(用 java 编写),你可以 利用下面的语句存取相应的实例。 project.getReference("task1"). 注意 1:如果 task1 还没有运行,就不会被生效(例如:不设定属性),如 果你在随后配置它,你所作的一切都会被覆盖。 注意 2:未来的 Ant 版本可能不会兼容这里所提的属性,因为很有可能根本 没有 task 实例,只有 proxies。 Properties 一个 project 可以有很多的 properties。可以在 buildfile 中用 property task 来设定,或在 Ant 之外设定。一个 property 有一个名字和一个值。property 可用于 task 的属性值。这是通过将属性名放在"{"和"}"之间并放在属性值的位 置来实现的。例如如果有一个 property builddir 的值是"build",这个 property 就可用于属性值:{builddir}/classes。这个值就可被解析为 build/classes。 内置属性 如果你使用了 task 定义了所有的系统属性,Ant 允许你使用这 些属性。例如,{os.name}对应操作系统的名字。要想得到系统属性的列表可参 考 the Javadoc of System.getProperties。除了 Java 的系统属性,Ant 还定义 了一些自己的内置属性:basedir project 基目录的绝对路径 (与的 basedir 属性一样)。 ant.file buildfile 的绝对路径。 ant.version Ant 的版本。 ant.project.name 当前执行的 project 的名字;由的 name 属性 设定. ant.java.version Ant 检测到的 JVM 的版本;目前的值有"1.1", "1.2", "1.3" and "1.4". 例子 Path-like Structures 你可以用":"和";"作为分隔符,指定类似 PATH 和 CLASSPATH 的引用。Ant 会把分隔符转换为当前系统所用的分隔符。当需要指定类似路径的值时,可以使 用嵌套元素。一般的形式是 location 属性指定了相对于 project 基目录的一个文件和目录,而 path 属 性接受逗号或分号分隔的一个位置列表。path 属性一般用作预定义的路径-- 其他情况下,应该用多个 location 属性。为简洁起见,classpath 标签支持自 己的 path 和 location 属性。所以: 可以被简写作: 也可通过元素指定路径。构成一个 fileset 的多个文件加入 path-like structure 的顺序是未定的。 上面的例子构造了一个路径值包括:{classpath}的路径,跟着 lib 目录下 的所有 jar 文件,接着是 classes 目录。如果你想在多个 task 中使用相同的 path-like structure,你可以用元素定义他们(与 target 同级),然后 通过 id 属性引用--参考 Referencs 例子。 path-like structure 可能包括对另一个 path-like structurede 的引用(通 过嵌套元素): 前面所提的关于的简洁写法对于也是有效的,如: 可写成: 命令行变量 有些 task 可接受参数,并将其传递给另一个进程。为了能在变量中包含空 格字符,可使用嵌套的 arg 元素。 AttributeDescriptionRequired value 一个命令行变量;可包含空格字符。只能用一个 line 空格分隔的命令行变量列表。 file 作为命令行变量的文件名;会被文件的绝对名替代。 path 一个作为单个命令行变量的 path-like 的字符串;或作为分隔符,Ant 会将其转变为特定平台的分隔符。 例子 是一个含有空格的单个的命令行变量。 是两个空格分隔的命令行变量。 是一个命令行变量,其值在 DOS 系统上为\dir;\dir2;\dir3;在 Unix 系统 上为/dir:/dir2:/dir3 。 References buildfile 元素的 id 属性可用来引用这些元素。如果你需要一遍遍的复制 相同的 XML 代码块,这一属性就很有用--如多次使用 结构。 下面的例子: 可以写成如下形式: 所有使用 PatternSets, FileSets 或 path-like structures 嵌套元素的 task 也接受这种类型的引用。 第三章运行 ANT 简介 ApacheAnt 可通过各种不同的方式来调用。就其本身而言,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 参数(-f 是其简写形式)。 另一个有用的选项是-D,它用于设置随后可以在生成文件中使用的属性。这 对于配置您想要以某种方式开始的生成过程是非常有用的。例如,为了将 name 属性设置为某个特定的值,您会使用一个类似下面这样的选项: -Dmetal=beryllium 这个功能可用于覆盖生成文件中的初始属性设置。正如前面指出过的,属性 的值一经设置就不能改变。-D 标志在读取生成文件中的任何信息之前设置某个 属性;由于生成文件中的指派落在这个初始指派之后,因此它不会改变其值。 命令行选项总结: ant [options] [target [target2 [target3] ...]] Options: -help print this message -projecthelp print project help information -version print the version information and exit -quiet be extra quiet -verbose be extra verbose -debug print debugging information -emacs produce logging information without adornments -logfile file use given file for log output -logger classname the class that is to perform logging -listener classname add an instance of class as a project listener -buildfile file use specified buildfile -find file search for buildfile towards the root of the filesystem and use the first one found -Dproperty=value set property to value 例子 ant 使用当前目录下的 build.xml 运行 Ant,执行缺省的 target。 ant -buildfile test.xml 使用当前目录下的 test.xml 运行 Ant,执行缺省的 target。 ant -buildfile test.xml dist 使用当前目录下的 test.xml 运行 Ant,执行一个叫做 dist 的 target。 ant -buildfile test.xml -Dbuild=build/classes dist 使用当前目录下的 test.xml 运行 Ant,执行一个叫做 dist 的 target,并设定 build 属性的值为 build/classes。 第四章生成一个简单的 JAVA 项目 简介 现在我们已经清楚了 Ant 生成文件的格式,并了解了如何定义属性和依赖 关系以及如何运行 Ant, 下面可以开始为一个基本的 Java 项目构建一个生成 环境了。这将包括学习用于编译源代码和组合 JAR 文件的 Ant 任务。 编译源代码 由于 Ant 的主要目标是生成 Java 应用程序,它能够内在地、出色地支持调 用 javac 编译器以及其他 Java 相关任务就毫不奇怪了。下面是编译 Java 代码 的任务的编写方式: 这个标签寻找 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 可执行文件,并向它传递一个最大内存设 置,您可以像下面这样做: 甚至可以将 Ant 配置为使用某种不同的编译器。受支持的编译器包括开放 源代码的 Jikes 编译器和来自 GNU 编译器集(GNU Compiler Collection,GCC) 的 GCI 编译器。(请参阅参考资料以了解关于这两种编译器的更多信息。)可以 通过两种方式指定这些编译器:可以设置 build.compiler 属性,这将应用于使用 javac 任务的所有场合;或根据需要设置每个 javac 任务中的 compiler 属性。 javac 任务还支持其他许多选项。请参考 Ant 手册以了解更多细节(请参 阅参考资料)。 创建 JAR 文件 在编译 Java 源文件之后,结果类文件通常被打包到一个 JAR 文件中,这 个文件类似 zip 归档文件。每个 JAR 文件都包含一个清单文件,它可以指定该 JAR 文件的属性。 下面是 Ant 中 jar 任务的一个简单使用例子: 这将创建一个名为 package.jar 的 JAR 文件,并把 classes 目录中的所有 文件添加到其中(JAR 文件能够包含任意类型的文件,而不只是类文件)。此处 没有指定清单文件,因此 Ant 将提供一个基本的清单文件。manifest 属性允许 指定一个用作该 JAR 文件的清单的文件。清单文件的内容还可以使用 manifest 任务在生成文件中指定。这个任务能够像文件系统写入一个清单文件,或者能够 实际嵌套在 jar 之内,以便一次性地创建清单文件和 JAR 文件。例如: 时间戳生成 在生成环境中使用当前时间和日期,以某种方式标记某个生成任务的输出, 以便记录它是何时生成的,这经常是可取的。这可能涉及编辑一个文件,以便插 入一个字符串来指定日期和时间,或将这个信息合并到 JAR 或 zip 文件的文件 名中。这种需要是通过简单但是非常有用的 tstamp 任务来解决的。这个任务通 常在某次生成过程开始时调用,比如在一个 init 目标中。这个任务不需要属性, 许多情况下只需 就足够了。tstamp 不产生任何输出;相反,它根据当 前系统时间和日期设置 Ant 属性。下面是 tstamp 设置的一些属性、对每个属 性的说明,以及这些属性可被设置到的值的例子: 属性说明例子 DSTAMP 设置为当前日期,默认格式为 yyyymmdd 20031217 TSTAMP 设置为当前时间,默认格式为 hhmm 1603 TODAY 设置为当前日期,带完整的月份 2003 年 12 月 17 日 例如,在前一小节中,我们按如下方式创建了一个 JAR 文件: 在调用 tstamp 任务之后,我们能够根据日期命名该 JAR 文件,如下所示: 因此,如果这个任务在 2003 年 12 月 17 日调用,该 JAR 文件将被命名 为 package-20031217.jar 。 还可以配置 tstamp 任务来设置不同的属性,应用一个当前时间之前或之后 的时间偏移,或以不同的方式格式化该字符串。所有这些都是使用一个嵌套的 format 元素来完成的,如下所示: 上面的清单将 OFFSET_TIME 属性设置为距离当前时间 10 分钟之后的小 时数、分钟数和秒数。用于定义格式字符串的字符与 java.text.SimpleDateFormat 类所定义的那些格式字符相同。 综合 前面几小节为我们提供了生成简单 Java 项目所需的足够知识。下面将把这 些代码片断组合成一个完整的生成文件,它将编译 src 目录下的所有源代码, 将结果类文件放在 build 目录下,然后把所有类文件打包到 dist 目录中的一个 JAR 文件中。要自己试验这个生成文件,您所需要的就是包含一个或多个 Java 源代码文件的 src 目录—— 这个目录可以包含从简单的“Hell World”程序到来 自某个现有项目的大量源文件的任何内容。如果需要向 Java classpath 添加 JAR 文件或其他任何内容,以便成功地编译源代码,您只需在 javac 任务中为其添 加一个 classpath 属性。该生成文件看起来如下: A simple Java project 下面是使用该文件执行的某次生成过程的示例输出(您得到的输出可能不一 样,具体取决于 src 目录的内容): Buildfile: build.xml init: [mkdir] Created dir: E:\tutorial\javaexample\build [mkdir] Created dir: E:\tutorial\javaexample\dist compile: [javac] Compiling 10 source files to E:\tutorial\javaexample\build dist: [jar] Building jar: E:\tutorial\javaexample\dist\package-20031217.jar [jar] Building jar: E:\tutorial\javaexample\dist\package-src-20031217.jar BUILD SUCCESSFUL Total time: 5 seconds 注意 JAR 文件是根据当前日期来命名的,并且为应用程序的主类设置了一 个清单条目,以便主类能够通过一个简单的命令 java-jarpackage-20031217.jar 来 直接运行。我们还创建了一个 JAR 文件,它仅包含项目的源代码。 第五章文件系统操作 简介 我们了解了关于 Ant 的足够多的知识,现在能够生成一个基本的 Java 项目 了,不过现实中的项目当然很少像我们的例子那样简单。在下面几节中,我们将 考察 Ant 的许多附加功能中的一部分,以及能够使用它们的场合。 在本节中,我们将考察如何执行常见文件操作,比如创建目录和解压缩文件。 Ant 的优秀特性之一在于,执行这些操作的任务一般在所有平台上都是相同的。 创建目录 最基本的文件系统操作之一就是创建目录或文件夹。做这项工作的任务名为 mkdir,毫不奇怪,它非常类似于具有相同名称的 Windows 和 UNIX/Linux 命 令。 首先要注意/ 被用作目录分隔符,这是 UNIX 和 Linux 的惯例。您可能认 为这不是很平台无关的,但是 Ant 知道如何处理它,并针对它运行所在的平台 做恰当的事情,这与我们在前面定义基于位置的属性时所看到的方式相同。我们 能够同样容易地使用 \,而不管平台是什么—— Ant 能够处理任一种形式,甚 至能够处理两种形式的混合。 mkdir 任务的另一个有用特性是它的如下能力:在父目录还不存在时创建它 们。考虑一下上面的清单,设想 archive 目录存在,但是 metals 目录不存在。 如果使用底层平台的 mkdir 命令,您需要首先显式地创建 metals 目录,然后第 二次调用 mkdir 命令来创建 zinc 目录。但是 Ant 任务 比这更加智能,它能够一次性创建这两个目录。类似地,如果目标目录已经 存在,mkdir 任务不会发出错误消息,而只是假设它的工作已经完成,从而什么 也不做。 说明:创建一个目录,如果他的父目录不存在,也会被同时创建 删除目录 这将删除指定的目录连同它包含的所有文件以及子目录。使用 file 属性而 不是 dir 属性可以指定要删除的单个文件。 例子 1.删除一个文件 2.删除指定目录及其子目录 3.删除指定的一组文件 4.删除指定目录及其子目录,包括他自己 复制文件及目录 在 Ant 中制作文件的一份拷贝很简单。例如: 您还可以使用 move 来执行重命名操作而不是拷贝文件: 另一个常用的文件系统操作是将文件复制或移动到另一个目录。做这项工作 的 Ant 语法同样也很简单: 默认情况下,Ant 仅输出它执行的移动和复制操作的摘要,包括诸如已移动 或复制的文件的数量等信息。如果想看到更详细的信息,包括涉及的文件名称等, 您可以将 verbose 属性设置为 true 。 拷贝一个(组)文件、目录 例子: 1.拷贝单个的文件: 2.拷贝单个的文件到指定目录下 3.拷贝一个目录到另外一个目录下 4.拷贝一批文件到指定目录下 5.拷贝一批文件到指定目录下,将文件名后增加。Bak 后缀 6.拷贝一组文件到指定目录下,替换其中的@标签@内容 移动文件及目录 1.移动或重命名一个文件 2.移动或重命名一个文件到另一个文件夹下面 3.将一个目录移到另外一个目录下 4.将一组文件移动到另外的目录下 5.移动文件过程中增加。Bak 后缀 创建和解压缩 zip 及 tar 文件 在前一节中,我们看到了如何创建 JAR 文件。创建其他归档文件的过程几 乎完全相同。下面是创建 zip 文件的 Ant 任务: 相同的语法也可用于创建 tar 文件。还可以使用 GZip 和 BZip 任务来压缩 文件。例如: 解压缩和提取文件 还可以包括 overwrite 属性来控制覆盖行为。默认设置是覆盖与正在被提取 的归档文件中的条目相匹配的所有现有文件。相关的任务名称是 untar、unjar 、 gunzip 和 bunzip2 。 替换文件中的标记 我们将在本节考察的最后一个文件系统操作是 replace 任务,它执行文件中 的查找和替换操作。token 属性指定要查找的字符串,value 属性指定一个新的 字符串,查找到的标记字符串的所有实例都被替换为这个新的字符串。例如: 替换操作将在文件本身之内的适当位置进行。为了提供更详细的输出,可把 summary 属性设置为 true。这将导致该任务输出找到和替换的标记字符串实例的 数目。 第六章其它有用的任务和技术 简介 在考察自定义的任务之前,我们首先介绍一些还没遇到过的有用功能。Ant 标准地附带了大量的功能,因此这里仅经挑选其中几个最有用的功能。模式匹配 和文件选择器是功能强大的机制,它们极大地增强了我们已看到过的一些任务的 功能;将生成任务链接起来以及与 CVS 知识库协同工作,是已发现的这些机制 的两个主要实际应用领域。 模式匹配 在前面考察文件系统任务时,我们仅使用了单独地命名的文件和目录。然而, 一次对一组文件执行那些操作经常是有用的—— 例如对给定目录中以.java 结 尾的所有文件执行操作。正如等价的 DOS 和 UNIX 命令提供了这样的功能一 样,Ant 也提供了这样的功能。这是使用通配符字符来完成的:*,它匹配零个 或多个字符;以及 ?,它仅匹配一个字符。因而匹配以 .java 结尾的所有文件的 模式不过就是 *.java 。也可以对目录执行模式匹配。例如,模式 src*/*.java 将 匹配带 src 前缀的任何目录中的所有 Java 文件。还有另一种模式结构:**,它 匹配任意数量的目录。例如,模式**/*.java 将匹配当前目录结构下的所有Java 文 件。您能够以相当一致的方式对文件系统任务使用模式,比如嵌套的 fileset 元 素。先前,我们使用这个任务来复制单个文件: 如果我们想要使用一个模式,可以将 file 属性替换为一个 fileset 元素,如 下所示: fileset 默认情况下包含指定 src 目录下的所有文件,因此为了仅选择 Java 文件,我们对模式使用一个 include 元素。类似地,我们可以对另一个模式添加 一个 exclude 元素,从而潜在地排除 include 指定的匹配项。甚至可以指定多个 include 和 exclude 元素;这样将得到一组文件和目录, 它们包含 include 模式 的所有匹配项的并集,但排除了 exclude 模式的所有匹配项。 注意还有一个通常很有用的文件集特性,但是对于没有意识到它的人来说,这个 特性偶尔会产生混淆。这个特性称为默认排除:即自动从文件集内容中排除的内 置模式列表。该列表包括与名为 CVS 的目录相匹配的条目,以及以 ~ 字符结 尾的文件,它们可能是备份文件。您通常不想在文件系统操作中包括这类文件和 目录,因此排除这些文件是默认行为。然而,如果确实想无例外地选择所有文件 和目录,可以将文件集的 defaultexcludes 属性设置为 no。 使用选择器 正如我们已经看到的,文件集用于指定一组文件,并且这个组的内容可以使 用 include 和 exclude 模式来指定。也可以结合称为选择器的特殊元素使用 include 和 exclude 来选择文件。下面是对 Ant 可用的核心选择器的列表: size:这个选择器用于根据文件的字节大小选择文件(除非使用 units 属性 来指定了不同的单位)。when 属性用于设置比较的性质(less、more 或者 equal), value 属性定义每 个文件将与之作比较的目标大小。. contains:只有包含给定文本字符串(由 text 属性指定)的文件才匹配这个 选择器。默认情况下,查找操作是大小写敏感的;添加 casesensitive="no" 可以 改变默认设置。. filename:name 属性指定文件名要与之匹配的模式。它本质上与 include 元 素相同,以及与指定了 negate="yes" 时的 exclude 元素相同。. present:从当前目录结构中选择如下文件:它们与指定的 targetdir 目录中 的文件具有相同的名称和相对目录结构。. depend:这个选择器与 present 选择器具有相同的效果,只不过匹配的文件 被限制到相对于 targetdir 位置中的对应文件来说,最近已修改过的那些文件。. date:这个选择器基于其最后修改日期选择文件。when 属性指定作比较的 性质是 before 、after 还是 equal,datetime 属性指定与之作比较的日期和时间, 这个日期和时间具有给定的固定格式 MM/DD/YYYYHH:MMAM_or_PM 。注意 Windows 平台上有一个内置的 2 秒偏移, 以允许底层文件系统的不精确性— — 这 可 能导 致 匹配的 文 件 数量超过预期。允许的回旋时间量可以使用 granularity 属性来更改(以毫秒为单位来指定)。. depth:这个选择器检查每个文件的目录结构层次数目。min 和/或 max 属 性用于选择具有想要的目录层次数目的的文件。 还可以通过在一个选择器容器内嵌套一个或多个选择器来组合选择器。最常 用的选择器容器 and 仅选择它包含的所有选择器都选择了的文件。其他选择其 容器包括 or、not 、none 和 majority 。下面是一个文件集的例子,它仅选择那 些大于 512 字节并且包含字符串“hello”的文件。 将生成文件链接起来 有两种生成大型项目的不同方法。一种是让一个单一的生成文件做所有事 情;另一种是让高级别的生成文件调用其它生成文件以执行特定任务,从而将生 成过程划分为许多较小的部分。使用 ant 任务来从一个 Ant 生成中调用另一个 Ant 生成是很容易的。在简单的情况下,您可以使用 antfile 属性,仅指定那些 要使用的生成文件,Ant 将生成该生成文件中的默认目标。例如: 在父生成文件中定义的任何属性默认将传递给子生成文件,虽然这可以通过 指定 inheritAll="false" 来避免。通过使用 property 元素来传入显式的属性也是可以做 到的— — 即使将 inheritAll 设置为 false ,这些属性也仍然适用于子生成文件。这个 功能很适合用于给子生 成文件传入参数。 让我们来考虑一个例子。下面是我们想要调用的一个生成文件: (我们在前面还没有遇到过 echo 任务—它简单地输出给定的消息。) 下面是调用第一个生成文件的第二生成文件,它还给第一个生成文件传入 message 属性: 运行第二个生成文件所得到的输出如下: Buildfile: build.xml callSub: showMessage: [echo] Message=Hello from parent build BUILD SUCCESSFUL Total time: 0 seconds 使用 CVS 知识库 CVS 是 concurrent versions system (并发版本控制系统的缩写。它是一个 源代码控制系统, 设计用于跟踪许多不同开发人员做出的更改。它非常流行, 在开放源代码项目中特别受欢迎。Ant 提供了与 CVS 的紧密集成。这对于自动 化生成环境是非常有用的,因为单个生成文件也可以从源代码知识库中提取出一 个或多个模块,生成项目,甚至基于自从前次执行生成以来所作的变更生成批处 理文件。注意,为了利用 Ant 中的 cvs 任务,您需要在机器上安装 cvs 命令, 并使其从命令行可用。这个命令包括在大多数 Linux 发行套件中;它也以多种 形式对 Windows 可用—— 例如作为宝贵的 Cygwin 环境的一部分。(请参阅参考资料以了解关于 Cygwin 的更多信 息。) 下面是从 CVS 知识库提取模块的一个例子生成文件: cvs 任务的主要属性是 cvsRoot ,它是对 CVS 知识库的完整引用,包括连 接方法和用户详细信息。这个参数的格式如下: [:method:][[user][:password]@]hostname[:[port]]/path/to/repository 在上面的例子中,我们作为匿名用户连接到 Eclipse 项目的中央知识库。然 后其他属性指定了我们希望提取的模块以及放置提取文件的目的地。提取是 CVS 任务的默认操作;其他操作可通过使用 command 属性来指定。请参阅参 考资料以了解关于 CVS 的更多信息。 编译 java 原代码 例子 1. 编译{src}目录及其子目录下的所有。Java 文件,。Class 文件将放在{build} 指定的目录下,classpath 表示需要用到的类文件或者目录, debug 设置为 on 表示输出 debug 信息 2. 编译{src} 和 {src2} 目录及其子目录下的所有。Java 文件,但是 package/p1/**,mypackage/p2/**将被编译, 而 mypackage/p1/testpackage/**将不会被编译。Class 文件将放在{build}指 定的目录下,classpath 表示需要用到的类文件或者目录, debug 设置为 on 表示输出 debug 信息 3. 路径是在 property 中定义的 java 执行指定的 java 类 例子: 1. classname 中指定要执行的类,classpath 设定要使用的环境变量 2. 打包相关 jar 将一组文件打包 例子: 1. 将{build}/classes 下面的所有文件打包到{dist}/lib/app.jar 中 2. 将{build}/classes 下面的所有文件打包到{dist}/lib/app.jar 中,但是包括 mypackage/test/所有文件不包括所有的 Test.class 3. manifest 属性指定自己的 META-INF/MANIFEST.MF 文件,而不是由系统生成 war 对 Jar 的扩展,用于打包 Web 应用 例子: 假设我们的文件目录如下: thirdparty/libs/jdbc1.jar thirdparty/libs/jdbc2.jar build/main/com/myco/myapp/Servlet.class src/metadata/myapp.xml src/html/myapp/index.html src/jsp/myapp/front.jsp src/graphics/images/gifs/small/logo.gif src/graphics/images/gifs/large/logo.gif 下面是我们的任务的内容: 完成后的结果: WEB-INF/web.xml WEB-INF/lib/jdbc2.jar WEB-INF/classes/com/myco/myapp/Servlet.class META-INF/MANIFEST.MF index.html front.jsp images/small/logo.gif images/large/logo.gif ear 用于打包企业应用 例子 时间戳 在生成环境中使用当前时间和日期,以某种方式标记某个生成任务的输出, 以便记录它是何时生成的,这经常是可取的。这可能涉及编辑一个文件,以便插 入一个字符串来指定日期和时间,或将这个信息合并到 JAR 或 zip 文件的文件 名中。这种需要是通过简单但是非常有用的 tstamp 任务来解决的。这个任务通 常在某次生成过程开始时调用,比如在一个 init 目标中。这个任务不需要属性, 许多情况下只需 就足够了。tstamp 不产生任何输出;相反,它根据 当前系统时间和日期设置 Ant 属性。下面是 tstamp 设置的一些属性、对每个 属性的说明,以及这些属性可被设置到的值的例子: 属性说明例子 DSTAMP 设置为当前日期,默认格式为 yyyymmdd 20031217 TSTAMP 设置为当前时间,默认格式为 hhmm 1603 TODAY 设置为当前日期,带完整的月份 2003 年 12 月 17 日 例如,在前一小节中,我们按如下方式创建了一个 JAR 文件: 在调用 tstamp 任务之后,我们能够根据日期命名该 JAR 文件,如下所示: 因此,如果这个任务在 2003 年 12 月 17 日调用,该 JAR 文件将被命名为 package-20031217.jar。 还可以配置 tstamp 任务来设置不同的属性,应用一个当前时间之前或之后的时 间偏移,或以不同的方式格式化该字符串。所有这些都是使用一个嵌套的 format 元素来完成的,如下所示: 上面的清单将 OFFSET_TIME 属性设置为距离当前时间 10 分钟之后的小时数、 分钟数和秒数。用于定义格式字符串的字符与 java.text.SimpleDateFormat 类 所定义的那些格式字符相同 执行 SQL 语句 通过 jdbc 执行 SQL 语句 例子: 1. 2. 只有在 oracle、版本是 8.1 的时候才执行 发送邮件 使用 SMTP 服务器发送邮件 例子: The {buildname} nightly build has completed mailhost: SMTP 服务器地址 mailport:服务器端口 subject:主题 from:发送人地址 to:接受人地址 message:发送的消息 fileset:设置附件 Ant 常用功能 1,想知道这段时间 CVS 做过哪些改动,CVS 修改记录 这个任务生成 25 Apr 2004 到现在 CVS 的修改记录,其中包括了 style 命令来将 XML 转化为可读性强的 HTML 2,单元测试报告 想看所有的 JUNIT 结果,就这样吧!持续集成,自动测试。 3,生成 todolist 这里要用到 xdoclet 包,是扩展的任务。他会把有 java 代码中 todo 的标签的内容做成文档,格式类似 javadoc。 这只是一种最简单的应用,复杂的还有生成 servlet 的描述符,EJB 描述符, Hibernate 配置文件。 4,java 程序检查 使用 checkstyle 检查一下,这里要去下载 checkstyle 的包放到路径里。