eclipse下使用ant 以及ant的命令總結
1. eclipse下使用ant
專案結構如圖1
1. 在專案的根目錄下建立build.xml檔案
2. 專案右鍵-->properties-->Builders-->new-->Ant Builder 如圖2
3. 在彈出的對話方塊裡填入Name,在Main tab裡選擇Buildfile\Base Directory,Buildfile即第1步建立的build.xml檔案,Base Directory選擇專案的跟目錄。如圖
4.編寫build.xml檔案內容,也就是ant的配置檔案
輸入如下內容:
<?xml version="1.0" encoding="utf-8"?> <project default="build" basedir="."> <property name="src" value="src"/> <property name="dest" value="classes"></property> <property name="jar_name" value="myTest.jar"/> <target name="init"> <mkdir dir="${dest}"/> </target> <target name="clean" > <delete dir="${dest}"></delete> <delete file="${jar_name}"/> </target> <target name="compile" depends="init,clean"> <javac srcdir="${src}" destdir="${dest}"/> </target> <target name="build" depends="compile"> <jar jarfile="${jar_name}" basedir="${dest}"/> </target> </project>
說明:
<project name="testAnt" default="build" basedir=".">
ant的所有設定都必須包含到這個裡面name是你給取的名字,basedir=“."表示工作目錄是專案的跟目錄 default=”build“表示預設要做什麼事(這個是在下面定義的target)
<property name="src" value="src"/> <property name="dest" value="classes"></property> <property name="jar_name" value="myTest.jar"/>
property 定義的是變數,以便後面使用,這樣呼叫”${dest}“
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${dest}"/>
</target>
target中定義我們要做的每件事,它有個name屬性說明這個任務的名稱,可以自己隨便定義,depends屬性說明這個任務依賴於誰,比如以上語句要執行complie就會先執行init裡的任務,多個依賴用”,“隔開如target clean,以上語句是作用就是編譯src目錄下的所有類,如果指定某個包可以這樣寫
<property name="src" value="src\com\zjw\service"/>
再來回頭看下第2行
<project default="build" basedir=".">
說明預設呼叫build任務,那麼它依賴於compile,然後cimpile依賴於init,所以預設會執行 init--》compile--》build
mkdir:是建立一個資料夾
javac:編譯java檔案
jar:就是打包
5.執行ant
專案右鍵--》properties--》Builders --》把Java Builder前的勾去掉 把Ant_builder打勾,點選”ok“
在build.xml上右鍵--》Run as--》Ant Build 如圖6.結果
IDE控制檯輸出:
Buildfile: F:\code\workspace_MyEclipse 8.5\Test\build.xml
init:
compile:
build:
BUILD SUCCESSFUL
Total time: 235 milliseconds
好了,eclipse下簡單使用ant的例子就這樣,簡單吧。ant其實還有非常強大的功能,這裡就不一一介紹了,網上看到一篇ant命令總結,感覺不錯。copy過來,以便以後查閱,如下:
2.ant 命令大全
Ant的buildfile是用XML寫的。每個buildfile含有一個project。
buildfile中每個task元素可以有一個id屬性,可以用這個id值引用指定的任務。這個值必須是唯一的。(詳情請參考下面的Task小節)
3.1 Projects
project有下面的屬性:
Attribute Description Required
name 專案名稱. No
default 當沒有指定target時使用的預設target Yes
basedir 用於計算所有其他路徑的基路徑。該屬性可以被basedir property覆蓋。當覆蓋時,該屬性被忽略。如果屬性和basedir property都沒有設定,就使用buildfile檔案的父目錄。 No
專案的描述以一個頂級的<description>元素的形式出現(參看description小節)。
一個專案可以定義一個或多個target。一個target是一系列你想要執行的。執行Ant時,你可以選擇執行那個target。當沒有給定target時,使用project的default屬性所確定的target。
3.2 Targets
一個target可以依賴於其他的target。例如,你可能會有一個target用於編譯程式,一個target用於生成可執行檔案。你在生成可執行檔案之前必須先編譯通過,所以生成可執行檔案的target依賴於編譯target。Ant會處理這種依賴關係。
然而,應當注意到,Ant的depends屬性只指定了target應該被執行的順序-如果被依賴的target無法執行,這種depends對於指定了依賴關係的target就沒有影響。
Ant會依照depends屬性中target出現的順序(從左到右)依次執行每個target。然而,要記住的是隻要某個target依賴於一個target,後者就會被先執行。
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
假定我們要執行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因該有所判斷的屬性。例如:
<target name="build-module-A" if="module-A-present"/>
<target name="build-own-fake-module-A" unless="module-A-present"/>
如果沒有if或unless屬性,target總會被執行。
可選的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
3.3 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 ... >
task1.setFoo("bar");
</script>
設定某個task例項的foo屬性。在另一個task中(用java編寫),你可以利用下面的語句存取相應的例項。
project.getReference("task1").
注意1:如果task1還沒有執行,就不會被生效(例如:不設定屬性),如果你在隨後配置它,你所作的一切都會被覆蓋。
注意2:未來的Ant版本可能不會相容這裡所提的屬性,因為很有可能根本沒有task例項,只有proxies。
3.4 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>
3.5 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也接受這種型別的引用。
4.1 File(Directory)類
4.1.1 Mkdir
? 建立一個目錄,如果他的父目錄不存在,也會被同時建立。
? 例子:
<mkdir dir="build/classes"/>
? 說明: 如果build不存在,也會被同時建立
4.1.2 Copy
? 拷貝一個(組)檔案、目錄
? 例子:
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">
<exclude name="**/*.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.3 Delete
? 刪除一個(組)檔案或者目錄
? 例子
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.4 Move
? 移動或重新命名一個(組)檔案、目錄
? 例子:
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.2 Java相關
4.2.1 Javac
? 編譯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.2 java
? 執行指定的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.1 jar
? 將一組檔案打包
? 例子:
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.2 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
? 下面是我們的任務的內容:
<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.3 ear
? 用於打包企業應用
? 例子
<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/> 就足夠了。
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出現之前,編譯和部署Java應用需要使用包括特定平臺的指令碼、Make檔案、不同的IDE以及手工操作等組成的大雜燴。現在,幾乎所有的開源Java專案都在使用Ant,許多公司的開發專案也在使用Ant。Ant的大量使用,也自然帶來了對總結Ant最佳實踐的迫切需求。
本文總結了我喜好的Ant最佳實踐,很多是從親身經歷的專案錯誤,或從其他開發者的“恐怖”故事中得到的靈感的。比如,有人告訴我有個專案將 XDoclet 生成的程式碼放入鎖定檔案的版本控制工具中。單開發者修改原始碼時,他必須記住手工檢出(Check out)並鎖定所有將要重生成的檔案。然後,手工執行程式碼生成器,當他能夠讓Ant編譯程式碼時,這一方法還存在一些問題:
生成的程式碼無法儲存在版本控制系統中
Ant(本案例中是Xdoclet)應該自動確定下一次構建涉及的原始檔,而不應由程式設計師人工確定。
Ant的構建檔案應該定義好正確的任務依賴關係,這樣程式設計師不必按照特定順序呼叫任務。
當我開始一個新專案時,我首先編寫Ant構建檔案。檔案定義構建的過程,併為團隊中的每個程式設計師都使用。本文所有的最佳實踐假設Ant構建檔案是一個必須精心編寫的重要檔案,它應在版本控制系統中得到維護,並定期進行重構。下面是我的十五大Ant最佳實踐。
1. 採用一致的編碼規範
Ant使用者不管是喜歡還是痛恨XML構建檔案的語法,都願意跳進這一迷人的爭論中。讓我們先看一些保持XML構建檔案簡潔的方法。
首先,也是最重要的,化費時間格式化你的XML讓它看上去很清晰。不過XML是否美觀,Ant都可以工作。但是醜陋的XML很難讀懂。倘若你在任務之間留出空行,有規則的縮排,每行文字不超過90列,那麼XML令人驚訝的易讀。再加上好的編輯器或IDE高亮相應的語句,你就不會有如何閱讀的麻煩。同樣,精選有意義明確、容易讀懂的詞彙來命名任務和屬性。比如,dir.reports就比rpts好。並不需要特定的編碼規範,只要有一種規範並堅持使用就好。
2. 將build.xml 放在專案根目錄中
Ant構建檔案build.xml可以放在如何位置,但是放在專案頂層目錄中可以保持專案簡潔。這是最普遍的規範,使開發者能夠在根目錄找到它。同時,也能夠容易瞭解專案中不同目錄之間的邏輯關係。以下是一個典型的專案層次:
[root dir] | build.xml +--src +--lib (包含第三方 JAR包) +--build (由 build任務生成) +--dist (由 build任務生成)
當build.xml在頂級目錄時,倘若你在專案某個子目錄中,只要輸入:ant -find compile 命令,不需要改變工作目錄就能夠以命令列方式編譯程式碼。引數-find告訴Ant尋找存在於上級目錄中的build.xml並執行。
3. 使用單一構建檔案
有人喜歡將一個大專案分解到幾個小的構建檔案,每個構建檔案分擔整個構建過程的一小部分工作。但是應該認識到,將構建檔案分割會增加對整個構建過程的理解難度。要注意在單一構建檔案能夠清楚表現構建層次的情況下,不要過工程化(over-engineer)。
即使你把專案劃分為多個構建檔案,也應使程式設計師能夠在專案根目錄下找到核心build.xml。儘管該檔案只是將實際構建工作委派給下級構建檔案,也應保證該檔案可用。
4. 提供良好的幫助說明
應儘量使構建檔案自文件化。增加任務描述是最簡單的方法。當你輸入ant -projecthelp時,你就可以看到帶有描述的任務清單。比如,你可以這樣定義任務:
<target name="compile" description="Compiles code, output goes to the build dir.">
最簡單的規則是對所有你希望程式設計師通過命令列直接呼叫的任務都加上描述。對於一般用來執行中間處理過程的內部任務,比如生成程式碼或建立輸出目錄等,就無法使用描述屬性。
這時,可以通過在構建檔案中加入XML註釋來處理。或者專門定義一個help任務,當程式設計師輸入ant help時來顯示詳細的使用說明。
<target name="help" description="Display detailed usage information"> <echo>Detailed help...</echo></target>
5. 提供清空任務
每個構建檔案都應包含一個清空任務,刪除所有生成的檔案和目錄,使系統回到構建檔案執行前的初始狀態。執行清空任務後還存在的檔案應處在版本控制系統的管理下。
比如:
<target name="clean" description="Destroys all generated files and dirs."> <delete dir="${dir.build}"/> <delete dir="${dir.dist}"/></target>
除非是在產生整個系統版本的特殊任務中,否則不要自動呼叫clean任務。當程式設計師僅僅執行編譯任務或其他任務時,他們不需要構建檔案事先執行即令人討厭有沒有必要的清空任務。要相信程式設計師能夠確定何時需要清空所有檔案。
6. 使用ANT管理任務從屬關係
假設你的應用由Swing GUI元件、Web介面、EJB層和公共應用程式碼組成。在大型系統中,你需要清晰地定義Java包屬於系統的哪一層。否則如何一點修改都要重新編譯成千上百個檔案。任務從屬關係管理差會導致過度複雜而脆弱的系統。改變GUI面板的設計不應造成Servlet和EJB的重編譯。
當系統變得龐大後,稍不注意就可能將依賴於客戶端的程式碼引入到服務端。這是因為IDE在編譯檔案時使用單一的classpath。Ant讓你更有效地控制構建活動。
設計你的構建檔案編譯大型專案的步驟:首先,編譯公共應用程式碼,將編譯結果打成JAR包檔案。然後,編譯上一層的專案程式碼,編譯時依靠第一步產生的JAR檔案。不斷重複這一過程,直到最高層的程式碼編譯完成。
分步構建強化了任務從屬關係管理。如果你工作在底層Java框架上,引用高層的GUI模板元件,這時程式碼不需要編譯。這是由於構建檔案在編譯底層框架時,在源路徑中沒有包含高層GUI面板元件的程式碼。
7. 定義並重用檔案路徑
如果檔案路徑在一個地方集中定義,並在整個構建檔案中得到重用,那麼構建檔案更易於理解。以下是這樣做的一個例子:
<project name="sample" default="compile" basedir="."> <path id="classpath.common"> <pathelement location="${jdom.jar.withpath}"/> ...etc </path> <path id="classpath.client"> <pathelement location="${guistuff.jar.withpath}"/> <pathelement location="${another.jar.withpath}"/> <!-- reuse the common classpath --> <path refid="classpath.common"/> </path> <target name="compile.common" depends="prepare"> <javac destdir="${dir.build}" srcdir="${dir.src}"> <classpath refid="classpath.common"/> <include name="com/oreilly/common/**"/> </javac> </target></project>
當專案不斷增長,構建日益複雜時,這一技術越發體現出其價值。你可能為編譯不同層次的應用定義各自的檔案路徑,比如執行單元測試的、執行應用程式的、執行Xdoclet的、生成JavaDocs的等等不同路徑。這種元件化路徑定義的方法比為每個任務單獨定義路徑要優越得多。否則,很容易丟