關於Ant的全面瞭解

Ant 官網:http://ant.apache.org/

http://www.iteye.com/topic/78973

Ant基本使用指南
在學習struts+spring+hibernate,尤其是Appfuse的過程中大量涉及到ant的使用,因此我覺得有必要對ant做個比較深入的學習,以下是在學習過程中搜集的材料。比較詳細,很適合沒有接觸過ant的初學者。

1 Ant是什麼?
Apache Ant 是一個基於 Java的生成工具。
生成工具在軟件開發中用來將源代碼和其他輸入文件轉換爲可執行文件的形式(也有可能轉換爲可安裝的產品映像形式)。隨着應用程序的生成過程變得更加複雜,確保在每次生成期間都使用精確相同的生成步驟,同時實現儘可能多的自動化,以便及時產生一致的生成版本
2下載、安裝Ant
安裝Ant
下載.zip文件,解壓縮到c:\ant1.3(後面引用爲%ANT_HOME%)

2.1在你運行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擴展)。而且通過擴展裝入的類會有安全方面的限制。
2.2運行Ant
運行Ant非常簡單,當你正確地安裝Ant後,只要輸入ant就可以了。

沒有指定任何參數時,Ant會在當前目錄下查詢build.xml文件。如果找到了就用該文件作爲buildfile。如果你用 -find 選項。Ant就會在上級目錄中尋找buildfile,直至到達文件系統的根。要想讓Ant使用其他的buildfile,可以用參數 -buildfile file,這裏file指定了你想使用的buildfile。

可以指定執行一個或多個target。當省略target時,Ant使用標籤的default屬性所指定的target。

命令行選項總結:
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 命令行參考
從命令行調用Ant 的語法如下所示:
ant [option [option…]] [target [target…]]
option := {-help
|-projecthelp
|-version
|-quiet
|-verbose
|-debug
|-emacs
|-logfile filename
|-logger classname
|-listener classname
|-buildfile filename
|-Dproperty=value
|-find filename}
語法元素說明如下:
-help
顯示描述Ant 命令及其選項的幫助信息。
-projecthelp
顯示包含在構建文件中的、所有用戶編寫的幫助文檔。即爲各個
中description 屬性的文本,以及包含在元素中的任何文
本。將有description 屬性的目標列爲主目標(“Main target”),沒有此屬
性的目標則列爲子目標(“Subtarget”)。
-version
要求Ant 顯示其版本信息,然後退出。
-quiet
抑制並非由構建文件中的echo 任務所產生的大多數消息。
-verbose
顯示構建過程中每個操作的詳細消息。此選項與-debug 選項只能選其一。
-debug
顯示Ant 和任務開發人員已經標誌爲調試消息的消息。此選項與-verbose 只
能選其一。
-emacs
對日誌消息進行格式化,使它們能夠很容易地由Emacs 的shell 模式(shellmode)
所解析;也就是說,打印任務事件,但並不縮排,在其之前也沒有
[taskname]。
-logfile filename
將日誌輸出重定向到指定文件。
-logger classname
指定一個類來處理Ant 的日誌記錄。所指定的類必須實現了org.apache.
tools.ant.BuildLogger 接口。
-listener classname
爲Ant 聲明一個監聽類,並增加到其監聽者列表中。在Ant與IDE或其他Java
程序集成時,此選項非常有用。可以閱讀第六章以瞭解有關監聽者的更多信
息。必須將所指定的監聽類編寫爲可以處理Ant 的構建消息接發。
-buildfile filename
指定Ant 需要處理的構建文件。默認的構建文件爲build.xml。
-Dproperty=value
在命令行上定義一個特性名-值對。
-find filename
指定Ant 應當處理的構建文件。與-buildfile 選項不同,如果所指定文件在當
前目錄中未找到,-find 就要求Ant 在其父目錄中再進行搜索。這種搜索會繼
續在其祖先目錄中進行,直至達到文件系統的根爲止,在此如果文件還未找
到,則構建失敗。
構建文件輪廓
下面是一個通用的構建文件,它很適合作爲一個模板。構建文件包括
元素,以及其中嵌套的、 和 元素。












關於構建文件有幾點需要記住:
● 所有構建文件都要有元素,而且至少有一個 元素。
● 對於 元素的default 屬性並沒有默認值。
● 構建文件並不一定要被命名爲build.xml。不過build.xml 是Ant 要搜索的默
認文件名。
● 每個構建文件只能有一個 元素。

例子
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。

3編寫build.xml
Ant的buildfile是用XML寫的。每個buildfile含有一個project。

buildfile中每個task元素可以有一個id屬性,可以用這個id值引用指定的任務。這個值必須是唯一的。(詳情請參考下面的Task小節)

3.1Projects

project有下面的屬性:
AttributeDescriptionRequired
name項目名稱.No
default當沒有指定target時使用的缺省targetYes
basedir用於計算所有其他路徑的基路徑。該屬性可以被basedir property覆蓋。當覆蓋時,該屬性被忽略。如果屬性和basedir property都沒有設定,就使用buildfile文件的父目錄。No
項目的描述以一個頂級的元素的形式出現(參看description小節)。

一個項目可以定義一個或多個target。一個target是一系列你想要執行的。執行Ant時,你可以選擇執行那個target。當沒有給定target時,使用project的default屬性所確定的target。

3.2Targets

一個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的名字列表,也就是依賴表。No
if執行target所需要設定的屬性名。No
unless執行target需要清除設定的屬性名。No
description關於target功能的簡短描述。No

3.3Tasks

一個task是一段可執行的代碼。

一個task可以有多個屬性(如果你願意的話,可以將其稱之爲變量)。屬性只可能包含對property的引用。這些引用會在task執行前被解析。

下面是Task的一般構造形式:

<name attribute1="value1" attribute2="value2" ... />

這裏name是task的名字,attributeN是屬性名,valueN是屬性值。

有一套內置的(built-in)task,以及一些可選task,但你也可以編寫自己的task。

所有的task都有一個task名字屬性。Ant用屬性值來產生日誌信息。

可以給task賦一個id屬性:

<taskname id="taskID" ... />

這裏taskname是task的名字,而taskID是這個task的唯一標識符。通過這個標識符,你可以在腳本中引用相應的task。例如,在腳本中你可以這樣:

<script ... >
task1.setFoo("bar");
</script>

設定某個task實例的foo屬性。在另一個task中(用java編寫),你可以利用下面的語句存取相應的實例。
project.getReference(“task1”).
注意1:如果task1還沒有運行,就不會被生效(例如:不設定屬性),如果你在隨後配置它,你所作的一切都會被覆蓋。

注意2:未來的Ant版本可能不會兼容這裏所提的屬性,因爲很有可能根本沒有task實例,只有proxies。

3.4Properties

一個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”.
例子

<project name="MyProject" default="dist" basedir=".">

<!-- set global properties for this build -->
<property name="src" value="."/>
<property name="build" value="build"/>
<property name="dist" value="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="{build}"/>
</target>
<target name="compile" depends="init">
<!-- Compile the java code from {src} into {build} -->
<javac srcdir="{src}" destdir="{build}"/>
</target>
<target name="dist" depends="compile">
<!-- Create the distribution directory -->
<mkdir dir="{dist}/lib"/>
<!-- Put everything in {build} into the MyProject-{DSTAMP}.jar file -->
<jar jarfile="{dist}/lib/MyProject-{DSTAMP}.jar" basedir="{build}"/>
</target>
<target name="clean">
<!-- Delete the {build} and {dist} directory trees -->
<delete dir="{build}"/>
<delete dir="{dist}"/>
</target>
</project>

3.5Path-like Structures
你可以用”:”和”;”作爲分隔符,指定類似PATH和CLASSPATH的引用。Ant會把分隔符轉換爲當前系統所用的分隔符。

當需要指定類似路徑的值時,可以使用嵌套元素。一般的形式是

<classpath>
<pathelement path="{classpath}"/>
<pathelement location="lib/helper.jar"/>
</classpath>

location屬性指定了相對於project基目錄的一個文件和目錄,而path屬性接受逗號或分號分隔的一個位置列表。path屬性一般用作預定義的路徑--其他情況下,應該用多個location屬性。

爲簡潔起見,classpath標籤支持自己的path和location屬性。所以:

<classpath>
<pathelement path="{classpath}"/>
</classpath>

可以被簡寫作:

<classpath path="{classpath}"/>
也可通過<fileset>元素指定路徑。構成一個fileset的多個文件加入path-like structure的順序是未定的。
<classpath>
<pathelement path="{classpath}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
<pathelement location="classes"/>
</classpath>

上面的例子構造了一個路徑值包括:{classpath}的路徑,跟着lib目錄下的所有jar文件,接着是classes目錄。

如果你想在多個task中使用相同的path-like structure,你可以用元素定義他們(與target同級),然後通過id屬性引用--參考Referencs例子。

path-like structure可能包括對另一個path-like structurede的引用(通過嵌套元素):

<path id="base.path">
<pathelement path="{classpath}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
<pathelement location="classes"/>
</path>
<path id="tests.path">
<path refid="base.path"/>
<pathelement location="testclasses"/>
</path>
前面所提的關於<classpath>的簡潔寫法對於<path>也是有效的,如:
<path id="tests.path">
<path refid="base.path"/>
<pathelement location="testclasses"/>
</path>

可寫成:

<path id="base.path" path="{classpath}"/>

命令行變量

有些task可接受參數,並將其傳遞給另一個進程。爲了能在變量中包含空格字符,可使用嵌套的arg元素。
AttributeDescriptionRequired
value一個命令行變量;可包含空格字符。只能用一個
line空格分隔的命令行變量列表。
file作爲命令行變量的文件名;會被文件的絕對名替代。
path一個作爲單個命令行變量的path-like的字符串;或作爲分隔符,Ant會將其轉變爲特定平臺的分隔符。

例子

<arg value="-l -a"/>
是一個含有空格的單個的命令行變量。
<arg line="-l -a"/>
是兩個空格分隔的命令行變量。
<arg path="/dir;/dir2:\dir3"/>
是一個命令行變量,其值在DOS系統上爲\dir;\dir2;\dir3;在Unix系統上爲/dir:/dir2:/dir3 。

References

buildfile元素的id屬性可用來引用這些元素。如果你需要一遍遍的複製相同的XML代碼塊,這一屬性就很有用--如多次使用結構。

下面的例子:

<project ... >
<target ... >
<rmic ...>
<classpath>
<pathelement location="lib/"/>
<pathelement path="{java.class.path}/"/>
<pathelement path="{additional.path}"/>
</classpath>
</rmic>
</target>
<target ... >
<javac ...>
<classpath>
<pathelement location="lib/"/>
<pathelement path="{java.class.path}/"/>
<pathelement path="{additional.path}"/>
</classpath>
</javac>
</target>
</project>
可以寫成如下形式:
<project ... >
<path id="project.class.path">
<pathelement location="lib/"/>
<pathelement path="{java.class.path}/"/>
<pathelement path="{additional.path}"/>
</path>
<target ... >
<rmic ...>
<classpath refid="project.class.path"/>
</rmic>
</target>
<target ... >
<javac ...>
<classpath refid="project.class.path"/>
</javac>
</target>
</project>

所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受這種類型的引用。
4Ant的Core Tasks
4.1File(Directory)類
4.1.1Mkdir
創建一個目錄,如果他的父目錄不存在,也會被同時創建。
例子:

<mkdir dir="build/classes"/>

說明:如果build不存在,也會被同時創建
4.1.2Copy
拷貝一個(組)文件、目錄
例子:
1.拷貝單個的文件:

<copy file="myfile.txt" tofile="mycopy.txt"/>

2.拷貝單個的文件到指定目錄下

<copy file="myfile.txt" todir="../some/other/dir"/>

3.拷貝一個目錄到另外一個目錄下

<copy todir="../new/dir">
<fileset dir="src_dir"/>
</copy>

4.拷貝一批文件到指定目錄下

<copy todir="../dest/dir">
<fileset dir="src_dir">
<include name="**/*.java"/>
<iexclude name="**/Test.java"/>
</fileset>
</copy>

<copy todir="../dest/dir">
<fileset dir="src_dir" excludes="**/*.java"/>
</copy>

5.拷貝一批文件到指定目錄下,將文件名後增加。Bak後綴

<copy todir="../backup/dir">
<fileset dir="src_dir"/>
<mapper type="glob" from="*" to="*.bak"/>
</copy>

6.拷貝一組文件到指定目錄下,替換其中的@標籤@內容

<copy todir="../backup/dir">
<fileset dir="src_dir"/>
<filterset>
<filter token="TITLE" value="Foo Bar"/>
</filterset>
</copy>

4.1.3Delete
刪除一個(組)文件或者目錄
例子
1.刪除一個文件

<delete file="/lib/ant.jar"/>

2.刪除指定目錄及其子目錄

<delete dir="lib"/>

3.刪除指定的一組文件

<delete>
<fileset dir="." includes="**/*.bak"/>
</delete>

4.刪除指定目錄及其子目錄,包括他自己

<delete includeEmptyDirs="true">
<fileset dir="build"/>
</delete>

4.1.4Move
移動或重命名一個(組)文件、目錄
例子:
1.移動或重命名一個文件

<move file="file.orig" tofile="file.moved"/>

2.移動或重命名一個文件到另一個文件夾下面

<move file="file.orig" todir="dir/to/move/to"/>

3.將一個目錄移到另外一個目錄下

<move todir="new/dir/to/move/to">
<fileset dir="src/dir"/>
</move>

4.將一組文件移動到另外的目錄下

<move todir="some/new/dir">
<fileset dir="my/src/dir">
<include name="**/*.jar"/>
<exclude name="**/ant.jar"/>
</fileset>
</move>

5.移動文件過程中增加。Bak後綴

<move todir="my/src/dir">
<fileset dir="my/src/dir">
<exclude name="**/*.bak"/>
</fileset>
<mapper type="glob" from="*" to="*.bak"/>
</move>

4.2Java相關
4.2.1Javac
編譯java原代碼
例子
1.

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

編譯{src}目錄及其子目錄下的所有。Java文件,。Class文件將放在{build}指定的目錄下,classpath表示需要用到的類文件或者目錄,debug設置爲on表示輸出debug信息
2.

<javac srcdir="{src}:{src2}"
destdir="{build}"
includes="mypackage/p1/**,mypackage/p2/**"
excludes="mypackage/p1/testpackage/**"
classpath="xyz.jar"
debug="on"
/>

編譯{src}和{src2}目錄及其子目錄下的所有。Java文件,但是package/p1/,mypackage/p2/將被編譯,而mypackage/p1/testpackage/**將不會被編譯。Class文件將放在{build}指定的目錄下,classpath表示需要用到的類文件或者目錄,debug設置爲on表示輸出debug信息
3.

<property name="classpath" value=".;./xml-apis.jar;../lib/xbean.jar;./easypo.jar"/>

<javac srcdir="{src}"
destdir="{src}"
classpath="{classpath}"
debug="on"
/>

路徑是在property中定義的
4.2.2java
執行指定的java類
例子:
1.

<java classname="test.Main">
<classpath>
<pathelement location="dist/test.jar"/>
<pathelement path="{java.class.path}"/>
</classpath>
</java>

classname中指定要執行的類,classpath設定要使用的環境變量
2.

<path id="project.class.path">
<pathelement location="lib/"/>
<pathelement path="{java.class.path}/"/>
<pathelement path="{additional.path}"/>
</path>

<target ... >
<rmic ...>
<classpath refid="project.class.path"/>
</rmic>
</target>

4.3打包相關
4.3.1jar
將一組文件打包
例子:
1.<jar destfile="{dist}/lib/app.jar" basedir="{build}/classes"/>
將{build}/classes下面的所有文件打包到{dist}/lib/app.jar中
2.

<jar destfile="{dist}/lib/app.jar"
basedir="{build}/classes"
includes="mypackage/test/**"
excludes="**/Test.class"
/>

將{build}/classes下面的所有文件打包到{dist}/lib/app.jar中,但是包括mypackage/test/所有文件不包括所有的Test.class
3.

<jar destfile="{dist}/lib/app.jar"
basedir="{build}/classes"
includes="mypackage/test/**"
excludes="**/Test.class"
manifest="my.mf"
/>

manifest屬性指定自己的META-INF/MANIFEST.MF文件,而不是由系統生成
4.3.2war
對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
下面是我們的任務的內容:

<war destfile="myapp.war" webxml="src/metadata/myapp.xml">
<fileset dir="src/html/myapp"/>
<fileset dir="src/jsp/myapp"/>
<lib dir="thirdparty/libs">
<exclude name="jdbc1.jar"/>
</lib>
<classes dir="build/main"/>
<zipfileset dir="src/graphics/images/gifs"
prefix="images"/>
</war>

完成後的結果:
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
4.3.3ear
用於打包企業應用
例子

<ear destfile="{build.dir}/myapp.ear" appxml="{src.dir}/metadata/application.xml">
<fileset dir="{build.dir}" includes="*.jar,*.war"/>
</ear>

4.4時間戳
在生成環境中使用當前時間和日期,以某種方式標記某個生成任務的輸出,以便記錄它是何時生成的,這經常是可取的。這可能涉及編輯一個文件,以便插入一個字符串來指定日期和時間,或將這個信息合併到 JAR 或 zip 文件的文件名中。
這種需要是通過簡單但是非常有用的 tstamp 任務來解決的。這個任務通常在某次生成過程開始時調用,比如在一個 init 目標中。這個任務不需要屬性,許多情況下只需 就足夠了。
tstamp 不產生任何輸出;相反,它根據當前系統時間和日期設置 Ant 屬性。下面是 tstamp 設置的一些屬性、對每個屬性的說明,以及這些屬性可被設置到的值的例子:
屬性說明例子
DSTAMP 設置爲當前日期,默認格式爲yyyymmdd 20031217
TSTAMP 設置爲當前時間,默認格式爲 hhmm 1603
TODAY 設置爲當前日期,帶完整的月份2003 年 12 月 17 日
例如,在前一小節中,我們按如下方式創建了一個 JAR 文件:

<jar destfile="package.jar" basedir="classes"/>

在調用 tstamp 任務之後,我們能夠根據日期命名該 JAR 文件,如下所示:

<jar destfile="package-{DSTAMP}.jar" basedir="classes"/>

因此,如果這個任務在 2003 年 12 月 17 日調用,該 JAR 文件將被命名爲 package-20031217.jar。
還可以配置 tstamp 任務來設置不同的屬性,應用一個當前時間之前或之後的時間偏移,或以不同的方式格式化該字符串。所有這些都是使用一個嵌套的 format 元素來完成的,如下所示:

<tstamp>
<format property="OFFSET_TIME"
pattern="HH:mm:ss"
offset="10" unit="minute"/>
</tstamp>

上面的清單將 OFFSET_TIME 屬性設置爲距離當前時間 10 分鐘之後的小時數、分鐘數和秒數。
用於定義格式字符串的字符與 java.text.SimpleDateFormat 類所定義的那些格式字符相同
4.5執行SQL語句
通過jdbc執行SQL語句
例子:
1.

<sql
driver="org.gjt.mm.mysql.Driver"
url="jdbc:mysql://localhost:3306/mydb"
userid="root"
password="root"
src="data.sql"
/>

2.

<sql
driver="org.database.jdbcDriver"
url="jdbc:database-url"
userid="sa"
password="pass"
src="data.sql"
rdbms="oracle"
version="8.1."
>
</sql>

只有在oracle、版本是8.1的時候才執行
4.6發送郵件
使用SMTP服務器發送郵件
例子:

<mail mailhost="smtp.myisp.com" mailport="1025" subject="Test build">
<from address="[email protected]"/>
<to address="[email protected]"/>
<message>The {buildname} nightly build has completed</message>
<fileset dir="dist">
<includes name="**/*.zip"/>
</fileset>
</mail>

mailhost: SMTP服務器地址
mailport:服務器端口
subject:主題
from:發送人地址
to:接受人地址
message:發送的消息
fileset:設置附件
ant使用指南1
2007-03-27 15:13
-. Ant簡介

Ant是一款類似make的工具,用來編譯/運行/打包Java程序。在構建、包裝和發佈過程
中幾乎每一件事都可以由Ant的任務來處理。

二.搭建ANT運行環境

1、將ant1.6.1解壓縮到任意目錄,假設解壓縮到C:\apache-ant-1.6.1目錄中
2、然後在path路徑中添加 C:\apache-ant-1.6.1\bin
3、再classpath中添加 C:\apache-ant-1.6.1\lib
三、ANT的組成(主要由三部分組成:Project、Target、Task)
1、Project(項目)。基本屬性:name、default、basedir。一個build.xml只能存在一個Project工程。
name :項目名稱
default :缺省開始執行的Target
basedir :用於計算所有其他路徑的基路徑。

例1:<project name="dev" basedir="." default="dist">

2、Target。一個項目可以定義一個或多個Target、一個Target是一系列你想要執行的任務,如編譯任務、打包任務、混淆任務。

Target的基本屬性: name:target的名字,depends:該target依賴關係,description: target的描述信息。

例2:<target name="clean" depends="init" description="Clean dist and temp directories">

Ant在執行時以Target爲單位,Target的depends屬性又決定了哪個Target先執行,因此我們可以通過Target來構造編譯順序。

例3:

<target name="copy" >
       <target name="javac" depends="copy">
       <target name="jar" depends="javac">

執行順序是從下至上,依次執行,如果某個Target沒有depends屬性,那麼就順序執行。

例4:一個完整的Target:

<target name="compile" depends="replacesrc"   description="Compiling Java source files">
     <javac   srcdir="temp/src"  
             destdir="temp/build"
             debug="on"
             deprecation="false"
             optimize="true">
     <classpath refid="classpath"/>
     </javac>
</target>

3、Task。Ant執行的一系列任務是由Target構成的,而Target又是由數個小的Task構成的,task任務是最小的運行單位,我們可以把copy、delete、mkdir等操作認爲是一個小任務。
(1)copy任務。
A.拷貝單個文件:

<copy file="Demo/manifest.mf" todir="temp/build/META-INF" /> 

解釋:把一個文件拷貝到拷貝相關文件夾中。
B.拷貝文件夾:

<copy todir="temp/build">
     <fileset dir="temp/classes"/>
   </copy> 
 解釋:把temp/build目錄下的所有文件,拷貝到temp/classes目錄中去

C.替換拷貝

<copy todir="temp/build">
   <fileset dir="temp/classes" includes="*.class" />
   <filterset>
        <filter token="@Time@" value="${app.time}"/>
   </filterset>
</copy> 

解釋: 過濾集,可以將temp/classes文件夾下的存在@Time@標記的文件,替換爲變量${app.time}值。這樣在完成拷貝的同時也完成了替換任務。
(2)mkdir任務和delete任務
A.單獨的delete和mkdir任務

      <delete dir="temp/src"/> 
      <delete file="temp/build/Thumbs.db" />
      <mkdir dir="temp/src"/>
B. 帶有條件的刪除任務
       <delete>
         <fileset dir="store" includes="*.*"/>
         <fileset dir="source" excludes="*.java"/>                                  </delete>       
   解釋:include表示要刪除哪些文件;而excludes表示排除的文件;

(3)replace替換任務
A.替換某一文件中的字符串

<replace file ="base/testing.txt">
token="@temp@" 
value="${newstring}"
</replace>

解釋:token是需要替換的標記;value是新值,將testing.txt文件中的@temp@替換爲新值。
B.替換某個文件夾中存在特定標記的文件

<replace dir="temp" token="@CHARSET@" value="${webapp.charset}"/>  

解釋:temp目錄中文件,如果有存在@CHARSET@標記的,將被替換爲${webapp.charset}變量值。
C.批量替換

<replace dir="dist" includes="${app.project}.jad" encoding="UTF-8">
<replacefilter token="@NAME@" value="${app.name}"/>
     <replacefilter token="@VENDOR@" value="${app.vendor}"/>
     <replacefilter token="@MIDLET@" value="${app.midlet}"/>
     <replacefilter token="@JAR@" value="${app.project}"/>
     <replacefilter token="@FILESIZE@" value="${size}"/>
     <replacefilter token="@DESCRIPTION@" value="${app.description}"/>             <replacefilter token="@PRICE@" value="${app.price}"/>
</replace>

(4) javac任務 ,編譯源程序

<target name="Compile" description="Compile Java source files">
<javac srcdir="src"

destdir="temp/classes"

bootclasspath="${compile.classpath}"

target="1.1"

debug="on"
deprecation="on"
includes="*.java"

optimize="true"

encoding="UTF-8"/>  


</target>

解釋:bootclasspath參數(啓動類庫):它已經包含了jre/lib目錄下的rt.jar,以及我們自定義的類庫。如果使用classpath參數,僅指我們定義的類庫;
(5) java任務 。爲運行Java應用程序,需要使用java任務
A.運行一個類

<target name="run" description="Run the program">
     <java classname="${main}" classpath="${classpath}"/>
</target>

解釋:classname表示要運行的主類。

B.運行某一特定類,並加上運行參數。

<java fork="true" classname="proguard.ProGuard" classpath="${proguard.classpath}">
             <arg line="-libraryjars ${proguard.classpath}"/>
             <arg line="-injars temp/${app.project}_tmp.jar"/>
             <arg line="-outjar temp/${app.project}_obf.jar"/>
             <arg line="-defaultpackage ''"/>
             <arg line="-dontusemixedcaseclassnames"/>
             <arg line="-keep public class ${app.midlet}"/>
</java>

解釋:fork參數:爲true時,在新的JVM實例中運行,不影響當前JVM工作
如何減少文件的size?
使用3.3.2版本的proguard.jar,然後在混淆參數中添加兩行代碼:


這樣可以保證startApp和destroyApp不被打上Final修飾符,同時還能更大的壓縮代碼,不過要求Midlet類中startApp和destroyApp方法保持上面的形式。
(6)JAR任務
將編譯好的CLASS文件打成JAR包,這是JAR任務的工作:

<target name="jar" depends="Compile" description="Build jar file">
<jar jarfile="dist/${name}.jar"
       basedir="${tmp/class}"
manifest="tmp/res/manifest.mf"
manifestencoding="UTF-8">
   <fileset dir="res" includes="*.*"/> <!-- 將res目錄中的文件也打進JAR包 -->
</jar>
</target>

(7)exec任務,用以調用外部程序

<exec executable="${LIB_PATH}/preverify.exe">
    <arg line="-classpath ${compile.classpath} -d temp/build temp/obfuscate"/>
</exec>

四、ANT的參數部分:

-quiet(不顯示大多數build信息)
-verbose(顯示構建過程的每個操作的詳細信息)
-buildfile filename.xml 構建特定的xml文件
-Dproperty=value 設定特別的外部參數,外部參數可以傳遞給內部變量
-find filename.xml 它會讓ANT自動查找當前的目錄、父目錄中的xml文件,直到失敗

例:
ant -buildfile test.xml

使用當前目錄下的test.xml運行Ant

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。

五、自定義TASK

ANT已經內置了不少task,像copy、replace、javac等等,但是有時候還需要一些特定的任務來完成操作,比如在生成JAD文件時,需要一個Midlet-Jar-Size的參數,得到JAR文件的大小,但是通過內部的task無法實現,因此可以自己編寫類來實現此功能,但必須保證該類是從Task類繼承過來的。

例:

<taskdef name="filesize" classname="ant.FileSizeTask" classpath="${LIB_PATH}/FileSizeTask.jar" />
<filesize file="${Base}/Demo_Build/${jarName}" property="size" />
   <replace dir="store" includes="${jadName}" encoding="UTF-8">
      <replacefilter token="@FILESIZE@" value="${size}" />
</replace>

解釋:taskdef:自定義任務,name:任務名
編寫Ant 自定義任務很簡單,Ant 能夠使用生成文件中指定的對應屬性的值來調用這個方法,這個方法的名稱需要是 set 加上屬性的名稱,因此在下面的例子中,我們需要名爲 setFile() 和 setTofile() 的兩個方法。
當 Ant 遇到生成文件中的一個屬性設置時,它會尋找相關任務中具有適當名稱的方法(稱爲 setter 方法)。
生成文件中的屬性是作爲字符串來指定的,因此我們的 setter 方法的參數可以是一個字符串。在這樣的情況下,Ant 將在展開值所引用的任何屬性之後,使用該屬性的字符串值來調用我們的方法。
但有時我們想把屬性的值看作是一種不同的類型。這裏的示例任務就是這種情況,其中的屬性值引用文件系統上的文件,而不只是引用任意的字符串。可以通過將方法參數聲明爲 java.io.File 類型來容易地做到這點。
Ant 將接受屬性的字符串值,並把它解釋爲一個文件,然後傳遞給我們的方法。Ant 能夠對其他類型執行類似的轉換,比如 boolean 和 int 類型。但如果提供具有相同名稱但是具有不同參數的兩個方法,Ant 將使用更明確的那一個方法,因此文件類型將優先於字符串類型。
例:一個排序的task任務

public class FileSorter extends Task {
private File file, tofile;
// ant在進行任務處理時會調用execute()方法
     public void execute() throws BuildException {
         System.out.println("Sorting file="+file);
         try {
             BufferedReader from =
                 new BufferedReader(new FileReader(file));
             BufferedWriter to =
                 new BufferedWriter(new FileWriter(tofile));
             List allLines = new ArrayList();
             // read in the input file
             String line = from.readLine();
             while (line != null) {
                 allLines.add(line);
                 line = from.readLine();
             }
             from.close();
             // sort the list
             Collections.sort(allLines);
             // write out the sorted list
             for (ListIterator i=allLines.listIterator(); i.hasNext(); ) {
                 String s = (String)i.next();
                 to.write(s); to.newLine();
             }
             to.close();
         } catch (FileNotFoundException e) {
             throw new BuildException(e);
         } catch (IOException e) {
             throw new BuildException(e);
         }
     }
     // file參數
     public void setFile(File file) {
         this.file = file;
     }
     // tofile參數
     public void setTofile(File tofile) {
         this.tofile = tofile;
     }
}

使用這個自定義任務:
<taskdef name="filesorter"   classname=" FileSorter" classpath="filesorter"/>
    <target name="main">
         <filesorter file="input.txt" tofile="output.txt"/>
    </target>

解釋:file和tofile分別是程序入口、出口

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章