Ant指南
1. Ant是什么?
2. 安裝Ant
3. 運行Ant
4. 編寫build.xml
5. 內置task(internet)
6. EAR task(internet)
7. WAR task(internet)
8. JUnit task(internet)
1. Ant是什么?
2. 安裝Ant
3. 運行Ant
4. 編寫build.xml
5. 內置task(internet)
6. EAR task(internet)
7. WAR task(internet)
8. JUnit task(internet)
1. Ant是什么?
Ant是一種基于Java的build工具。理論上來說,它有些類似于(Unix)C中的make ,但沒有make的缺陷。2. 安裝Ant
既然我們已經有了make, gnumake, nmake, jam以及其他的build工具為什么還要要一種新的build工具呢?因為Ant的原作者在多種(硬件)平臺上開發軟件時,無法忍受這些工具的限制和不便。類似于make的工具本質上是基于shell(語言)的:他們計算依賴關系,然后執行命令(這些命令與你在命令行敲的命令沒太大區別)。這就意味著你可以很容易地通過使用OS特有的或編寫新的(命令)程序擴展該工具;然而,這也意味著你將自己限制在了特定的OS,或特定的OS類型上,如Unix。
Makefile也很可惡。任何使用過他們的人都碰到過可惡的tab問題。Ant的原作者經常這樣問自己:“是否我的命令不執行只是因為在我的tab前有一個空格?!!”。類似于jam的工具很好地處理了這類問題,但是(用戶)必須記住和使用一種新的格式。
Ant就不同了。與基于shell命令的擴展模式不同,Ant用Java的類來擴展。(用戶)不必編寫shell命令,配置文件是基于XML的,通過調用target樹,就可執行各種task。每個task由實現了一個實現了特定Task接口的對象來運行。(如果你對Ant一點概念都沒有的話,可能看不懂這一節,沒有關系,后面會對target,task做詳細的介紹。你如果沒有太多的時間甚至可以略過這一節,然后再回來瀏覽一下這里的介紹,那時你就會看懂了。同樣,如果你對make之類的工具不熟悉也沒關系,下面的介紹根本不會用到make中的概念。)
必須承認,這樣做,在構造shell命令時會失去一些特有的表達能力。如`find . -name foo -exec rm {}`,但卻給了你跨平臺的能力-你可以在任何地方工作。如果你真的需要執行一些shell命令,Ant有一個<exec> task,這個task允許執行特定OS上的命令。
返回
由于Ant是一個Open Source的軟件,所以有兩種安裝Ant的方式,一種是用已編譯好的binary 文件安裝Ant,另一種是用源代碼自己build Ant。3. 運行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,1.1版或更高。未來的Ant版本會要求使用JDK 1.2或更高版本。
安裝Ant
binary 版的Ant包括三個目錄:bin, docs 和lib。只有bin和lib目錄是運行Ant所需的。要想安裝Ant,選擇一個目錄并將發行版的文件拷貝到該目錄下。這個目錄被稱作ANT_HOME。
在你運行Ant之前需要做一些配置工作。注意:不要將Ant的ant.jar文件放到JDK/JRE的lib/ext目錄下。Ant是個應用程序,而lib/ext目錄是為JDK擴展使用的(如JCE,JSSE擴展)。而且通過擴展裝入的類會有安全方面的限制。
- 將bin目錄加入PATH環境變量。
- 設定ANT_HOME環境變量,指向你安裝Ant的目錄。在一些OS上,Ant的腳本可以猜測ANT_HOME(Unix和Windos NT/2000)-但最好不要依賴這一特性。
- 可選地,設定JAVA_HOME環境變量(參考下面的高級小節),該變量應該指向你安裝JDK的目錄。
可選Task
Ant支持一些可選task。一個可選task一般需要額外的庫才能工作。可選task與Ant的內置task分開,單獨打包。這個可選包可以從你下載Ant的同一個地方下載。目前包含可選task的jar文件名叫jakarta-ant-1.4.1-optional.jar。這個jar文件應該放到Ant安裝目錄的lib目錄下。
每個可選task所需的外部庫可參看依賴庫小節。這些外部庫可以放到Ant的lib目錄下,這樣Ant就能自動裝入,或者將其放入環境變量中。
Windows
假定Ant安裝在c:\ant\目錄下。下面是設定環境的命令:set ANT_HOME=c:\antUnix (bash)
set JAVA_HOME=c:\jdk1.2.2
set PATH=%PATH%;%ANT_HOME%\bin
假定Ant安裝在/usr/local/ant目錄下。下面是設定環境的命令:export ANT_HOME=/usr/local/ant高級
export JAVA_HOME=/usr/local/jdk-1.2.2
export PATH=${PATH}:${ANT_HOME}/bin
要想運行Ant必須使用很多的變量。你至少參考需要下面的內容:Building 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環境變量自動設置該屬性。
要想從源代碼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小節中所做的那樣設定這些jar文件。
現在你可以build Ant了:build -Ddist.dir=<directory_to_contain_Ant_distribution> dist (Windows)這樣就可你指定的目錄中創建一個binary版本。
build.sh -Ddist.dir=<directory_to_contain_Ant_distribution> dist (Unix)
上面的命令執行下面的動作:大多數情況下,你不必直接bootstrap Ant,因為build腳本為你完成這一切。運行bootstrap.bat (Windows) 或 bootstrap.sh (UNIX) 可以build一個新的bootstrap版Ant。
- 如果有必要可以bootstrap Ant的代碼。bootstrap 包括手工編輯一些Ant代碼以便運行Ant。bootstrap 用于下面的build步驟。
- 向build腳本傳遞參數以調用bootstrap Ant。參數定義了Ant的屬性值并指定了Ant自己的build.xml文件的"dist" target。
如果你希望將Ant安裝到ANT_HOME目錄下,你可以使用:build install (Windows)如果你希望跳過冗長的Javadoc步驟,可以用:
build.sh install (Unix)build install-lite (Windows)這樣就只會安裝bin和lib目錄。
build.sh install-lite (Unix)
注意install和install-lite都會覆蓋ANT_HOME中的當前Ant版本。
依賴庫
如果你需要執行特定的task,你需要將對應的庫放入CLASSPATH或放到Ant安裝目錄的lib目錄下。注意使用mapper時只需要一個regexp庫。同時,你也要安裝Ant的可選jar包,它包含了task的定義。參考上面的安裝Ant小節。
Jar Name Needed For Available At An XSL transformer like Xalan or XSL:P style task http://xml.apache.org/xalan-j/index.html or http://www.clc-marketing.com/xslp/ jakarta-regexp-1.2.jar regexp type with mappers jakarta.apache.org/regexp/ jakarta-oro-2.0.1.jar regexp type with mappers and the perforce tasks jakarta.apache.org/oro/ junit.jar junit tasks www.junit.org stylebook.jar stylebook task CVS repository of xml.apache.org testlet.jar test task java.apache.org/framework antlr.jar antlr task www.antlr.org bsf.jar script task oss.software.ibm.com/developerworks/projects/bsf netrexx.jar netrexx task www2.hursley.ibm.com/netrexx rhino.jar javascript with script task www.mozilla.org jpython.jar python with script task www.jpython.org netcomponents.jar ftp and telnet tasks www.savarese.org/oro/downloads
返回
運行Ant非常簡單,當你正確地安裝Ant后,只要輸入ant就可以了。4. 編寫build.xml
沒有指定任何參數時,Ant會在當前目錄下查詢build.xml文件。如果找到了就用該文件作為buildfile。如果你用 -find 選項。Ant就會在上級目錄中尋找buildfile,直至到達文件系統的根。要想讓Ant使用其他的buildfile,可以用參數 -buildfile file,這里file指定了你想使用的buildfile。
你也可以設定一些屬性,以覆蓋buildfile中指定的屬性值(參看property task)。可以用 -Dproperty=value 選項,這里property是指屬性的名稱,而value則是指屬性的值。也可以用這種辦法來指定一些環境變量的值。你也可以用property task來存取環境變量。只要將 -DMYVAR=%MYVAR% (Windows) 或 -DMYVAR=$MYVAR (Unix) 傳遞給Ant -你就可以在你的buildfile中用${MYVAR}來存取這些環境變量。
還有兩個選項 -quite,告訴Ant運行時只輸出少量的必要信息。而 -verbose,告訴Ant運行時要輸出更多的信息。
可以指定執行一個或多個target。當省略target時,Ant使用標簽<project>的default屬性所指定的target。
如果有的話,-projecthelp 選項輸出項目的描述信息和項目target的列表。先列出那些有描述的,然后是沒有描述的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 valueant使用當前目錄下的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。
文件
在Unix上,Ant的執行腳本在做任何事之前都會source(讀并計算值)~/.antrc 文件;在Windows上,Ant的批處理文件會在開始時調用%HOME%\antrc_pre.bat,在結束時調用%HOME%\antrc_post.bat。你可以用這些文件配置或取消一些只有在運行Ant時才需要的環境變量。看下面的例子。
環境變量
包裹腳本(wrapper scripts)使用下面的環境變量(如果有的話):手工運行Ant
- JAVACMD Java可執行文件的絕對路徑。用這個值可以指定一個不同于JAVA_HOME/bin/java(.exe)的JVM。
- ANT_OPTS 傳遞給JVM的命令行變量-例如,你可以定義屬性或設定Java堆的最大值
如果你自己動手安裝(DIY)Ant,你可以用下面的命令啟動Ant:java -Dant.home=c:\ant org.apache.tools.ant.Main [options] [target]這個命令與前面的ant命令一樣。選項和target也和用ant命令時一樣。這個例子假定你的CLASSPATH包含:返回
- ant.jar
- jars/classes for your XML parser
- the JDK's required jar/zip files
Ant的buildfile是用XML寫的。每個buildfile含有一個project。
buildfile中每個task元素可以有一個id屬性,可以用這個id值引用指定的任務。這個值必須是唯一的。(詳情請參考下面的Task小節)
Projects
project有下面的屬性:項目的描述以一個頂級的<description>元素的形式出現(參看description小節)。
Attribute Description Required name 項目名稱. No default 當沒有指定target時使用的缺省target Yes basedir 用于計算所有其他路徑的基路徑。該屬性可以被basedir property覆蓋。當覆蓋時,該屬性被忽略。如果屬性和basedir property都沒有設定,就使用buildfile文件的父目錄。 No
一個項目可以定義一個或多個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 name="A"/>假定我們要執行target D。從它的依賴屬性來看,你可能認為先執行C,然后B,最后A被執行。錯了,C依賴于B,B依賴于A,所以先執行A,然后B,然后C,最后D被執行。
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
一個target只能被執行一次,即時有多個target依賴于它(看上面的例子)。
如果(或如果不)某些屬性被設定,才執行某個target。這樣,允許根據系統的狀態(java version, OS, 命令行屬性定義等等)來更好地控制build的過程。要想讓一個target這樣做,你就應該在target元素中,加入if(或unless)屬性,帶上target因該有所判斷的屬性。例如:<target name="build-module-A" if="module-A-present"/>如果沒有if或unless屬性,target總會被執行。
<target name="build-own-fake-module-A" unless="module-A-present"/>
可選的description屬性可用來提供關于target的一行描述,這些描述可由-projecthelp命令行選項輸出。
將你的tstamp task在一個所謂的初始化target是很好的做法,其他的target依賴這個初始化target。要確保初始化target是出現在其他target依賴表中的第一個target。在本手冊中大多數的初始化target的名字是"init"。
target有下面的屬性:
Attribute Description Required name target的名字 Yes depends 用逗號分隔的target的名字列表,也就是依賴表。 No if 執行target所需要設定的屬性名。 No unless 執行target需要清除設定的屬性名。 No description 關于target功能的簡短描述。 No
Tasks
一個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 ... >設定某個task實例的foo屬性。在另一個task中(用java編寫),你可以利用下面的語句存取相應的實例。
task1.setFoo("bar");
</script>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。
內置屬性
如果你使用了<property> task 定義了所有的系統屬性,Ant允許你使用這些屬性。例如,${os.name}對應操作系統的名字。
要想得到系統屬性的列表可參考the Javadoc of System.getProperties。
除了Java的系統屬性,Ant還定義了一些自己的內置屬性:basedir project基目錄的絕對路徑 (與<project>的basedir屬性一樣)。 ant.file buildfile的絕對路徑。 ant.version Ant的版本。 ant.project.name 當前執行的project的名字;由<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>Token Filters
一個project可以有很多tokens,這些tokens在文件拷貝時會被自動擴展,這要求在支持這一行為的task中選擇過濾拷貝功能。這一功能可用filter task在buildfile中設定。
既然這很可能是一個有危害的行為,文件中的tokens必須采取@token@的形式,這里token是filter task中設定的token名。這種token語法與其他build系統執行類似filtering的語法相同,而且與大多數的編程和腳本語言以及文檔系統并不沖突,
注意:如果在一個文件中發現了一個@token@形式的token,但沒有filter與這個token關連,則不會發生任何事;因此,沒有轉義方法-但只要你為token選擇合適的名字,就不會產生問題。
警告:如果你在拷貝binary文件時打開filtering功能,你有可能破壞文件。這個功能只針對文本文件。
Path-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,你可以用<path>元素定義他們(與target同級),然后通過id屬性引用--參考Referencs例子。
path-like structure可能包括對另一個path-like structurede的引用(通過嵌套<path>元素):<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元素。
Attribute Description Required 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代碼塊,這一屬性就很有用--如多次使用<classpath>結構。
下面的例子:<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也接受這種類型的引用。