国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Eclipse In Action - 第5章. 用Ant構(gòu)建


本章內(nèi)容:
  • 一個正式的構(gòu)建過程可以做什么
  • 為進行正式構(gòu)建組織項目
  • 回顧一個舊標準:Make
  • 新的標準Java構(gòu)建工具:Ant
  • Ant項目,目標,任務(wù)及屬性
  • 一個簡單的Ant構(gòu)建文件

  盡管編程--編寫和編譯代碼--是軟件開發(fā)中最明顯的部分,但并不意味著就是唯一的部分。就像你已經(jīng)看到過的,測試也很重要。但交付一個完成的產(chǎn)品還需要更多的步驟:你還需要文檔,打包,以及部署你所開發(fā)的軟件。手工進行這些工作是煩悶的、重復性的,還容易出錯。這是個迫切需要自動化進行的任務(wù)。

5.1 需要一個正式的構(gòu)建過程


  你已經(jīng)經(jīng)歷了測試--編碼,測試--編碼的循環(huán),并最終得到了一些人們可以實際使用的東西。那么該如何交付該功能呢?
  下一步就是要以確切的詞匯來標明這個產(chǎn)品到底是什么。它是一個API嗎?還是一個具有圖形界面的可執(zhí)行程序?它是被打包在一個JAR文件中嗎?它是否包含文檔?示例代碼呢?是否所有這些東西都要刻錄在一張光盤上?還是要壓縮在一塊兒以便通過因特網(wǎng)上交付使用?
  一旦你作出了決定,Eclipse會簡化這些步驟的執(zhí)行。在你保存了源代碼并編譯了所有東西之后,就能立刻運行單元測試,用Javadoc向?qū)?chuàng)建文檔(假設(shè)這對于你的讀者來說足夠了),把你的類導出到一個JAR文件,并把所有的東西放到一個p文件中。如果你只是要非正式地把你正在做的游戲的最新版本發(fā)給一個朋友,這個過程是不錯的,但如果你要把一個產(chǎn)品交付給一個客戶或公眾,你是不會這么做的。有太多的事情會出錯:忘了刷新源碼樹,忘了運行單元測試,沒注意到一個失敗的測試,生成一個Javadoc時選擇了錯誤的選項,漏拷了源碼文件,打錯了p文件名--可能的問題是無窮無盡的。當從事該項目的人不止一個時,這些問題會變得更加復雜。
  進行一個獨立的構(gòu)建過程的主要原因之一是可重復性。最理想的是,你希望能夠只需在一臺工作站打入一條命令,機器就會攪拌一會兒它的硬盤,并且在最后(如果一切順利并且成功運行了單元測試),吐出一個p文件或者一張光盤。減少了人工干預也就減少了構(gòu)建過程中出錯的幾率,并且任何發(fā)生的錯誤都可以被持續(xù)改正。
  因為使用圖形界面來自動化過程比較困難,構(gòu)建過程通常設(shè)計為在命令行下運行。那樣的話,通過使用一條簡單的命令,或者使用Unix/Linux的 chron命令或Windows的at命令設(shè)置每天的指定時間自動進行,就可以擺脫這個問題。
  使用外部的、獨立的構(gòu)建過程的額外好處是,它讓開發(fā)者能夠自由使用自己選擇的開發(fā)環(huán)境。這看起來不像是一個緊迫的需求,但是強迫開發(fā)者--尤其是那些很有經(jīng)驗的--放棄他們已經(jīng)精通的工具,對生產(chǎn)力是有害的。

5.1.1 創(chuàng)建構(gòu)建目錄結(jié)構(gòu)

  在我們查看特定的構(gòu)建工具之前,讓我們來考慮一下這個任務(wù):利用你在前面的章節(jié)中作為示例開始開發(fā)的基于文件的持久組件(Persistence),計劃和組織構(gòu)建過程。想象一下,由于某些原因,你(或你的主管)決定將該產(chǎn)品實用化。規(guī)范化構(gòu)建過程的第一步就是組織你的文件,以便能夠清晰的區(qū)分源代碼和其他資源,臨時文件,以及可交付文件。

5.1.2 分離源碼和構(gòu)建目錄

  在你創(chuàng)建了persistence對象之后,你沒有停下來考慮目錄結(jié)構(gòu)。你簡單的接受了Eclipse提供的默認配置:項目目錄等同于源碼目錄。這種結(jié)構(gòu)的結(jié)果是,源碼文件、測試類、編譯好的類文件都混在一起了:

\persistence
  \org
    \eclipseguide
      \astronomy
        *.class
        *.java

          \persistence
            *.class
            *.java

  因為在源碼文件和生成文件之間沒有明確的界限,在開始一個新構(gòu)建之前,刪除生成文件就需要你在某些目錄中刪除某些文件。這不難,但使用一個獨立的目錄更加簡單可靠,這樣你就能在開始構(gòu)建之前把整個目錄弄走--這就避免了過期的文件意外地弄糟了構(gòu)建過程,從而導致莫名其妙的錯誤的可能性。
  與混合源碼文件和類文件相比,一個更好的設(shè)計是在項目目錄中,為兩者創(chuàng)建單獨的目錄,像這樣:

\persistence
  \src
    \org
      \eclipseguide
        \astronomy
          *.java
        \persistence
          *.java
  \bin
    \org
      \eclipseguide
        \astronomy
          *.class
        \persistence
          *.class

  Eclipse在項目結(jié)構(gòu)上十分靈活。如果你一開始就已經(jīng)知道你需要一個正式構(gòu)建過程,當你創(chuàng)建項目時就已經(jīng)能指定src作為源碼目錄。那你就不會在輸入名稱后立即點[完成]來接受默認配置,而可以點[下一步]前進到另一個對話框,那里提供了選項以增加一個新的源碼目錄;在[源]頁面上點擊[添加文件夾]就可以創(chuàng)建新的文件夾名(參看圖5.1)。

圖5.1 新的源碼文件夾。你可以在創(chuàng)建一個新項目時定義一個單獨的源碼文件夾,然后Eclipse會幫助建立一個單獨的輸出文件夾。


  但別擔心--你不必全部倒回去重新照做一遍。所謂敏捷開發(fā)指的就是增量開發(fā)--按部就班,并且如果沒有好的理由,絕不以吃力的方式做任何事情。就像你至今可能預想的那樣,Eclipse輕松地完成這些變換。你所需做的一切只是新建一個源碼文件夾(src)并把你的源碼移動到里面。由Eclipse負責建立新的獨立的輸出文件夾(bin)及其子目錄。(此外,當你用Eclipse構(gòu)建時,它會將所有的class文件放置到正確的位置。)
  在Java透視圖中,在項目名稱(Persistence)上右擊鼠標,選擇[新建]->[源碼文件夾],然后輸入 src 作為文件夾名(參看圖5.2)。注意對話框頂部的注釋:為避免重復,現(xiàn)有的項目源碼文件夾入口將被替換,并且輸出文件夾將被設(shè)置為‘Persistence/bin‘。這正是你所想要的,那么就點擊[完成]。(如果你不想把輸出文件夾命名為bin--比如說想把它命名為build--你可以在稍后通過從項目的快捷菜單中選擇[屬性]->[Java 構(gòu)建路徑]->[源]來改變?nèi)笔〉妮敵鑫募A。)

圖5.2 將一個源碼文件夾添加到一個現(xiàn)存的項目中。Eclipse自動創(chuàng)建一個新的輸出目錄。


  現(xiàn)在,要把源碼文件移動到新的src目錄中,右鍵點擊頂層源碼目錄(org),選擇[重構(gòu)]->[移動],并選擇Persistence下面的src目錄(參看圖5.3)。(你可以安全地忽略那個警告:到缺省包的引用將不會被更新。)或者--甚至更簡單--在包瀏覽器中點擊org文件夾并拖動到src文件夾上。

圖5.3 更多的重構(gòu):將源碼樹移動到新的src目錄。


5.1.3 為可發(fā)布文件創(chuàng)建一個目錄

  創(chuàng)建一個獨立的輸出目錄是一個好的開始,但不是發(fā)布軟件的全部。一堆目錄里面的一堆類不是一個產(chǎn)品。你需要決定要將哪一片發(fā)布給你的客戶,并把它們干凈地包裝在一個JAR文件中。任何好的軟件產(chǎn)品都要求有文檔,因為你的產(chǎn)品是為開發(fā)者設(shè)計的一個軟件組件,它很可能只需包含Javadoc就足夠了。(在前面章節(jié)的代碼中,你對于包含Javadoc注釋是不嚴格的,這種情形下,你應當考慮更正--但現(xiàn)在,讓我們把它作為讀者--你的一個借口。)
  假定Persistence組件是普遍關(guān)心的唯一部分。你需要將persistence類和astronomy類、test類分離開來。記住你仍需構(gòu)建所有的類以便測試persistence類,要這么做,一個好的方法是再創(chuàng)建另一個目錄,里面僅放置那些組成可發(fā)布產(chǎn)品的文件。你將把它稱為dist(distribution的簡稱),而它將包含Persistence組件的JAR文件和Javadoc:

\persistence
  \src
    \...
  \bin
    \...
  \dist
    \lib
      persistence.jar
    \doc
      *.html

  在你更改src目錄中的Java源文件時,Eclipse自動保持bin目錄中的類文件最新,但除此之外的事情都得你來做。如前所述,你可以用Eclipse手動去做;但為了可靠性和一致性,使用一個構(gòu)建工具來自動化這個過程會好很多。

5.2 Make:一個回顧


  在我們考慮事實上的Java標準構(gòu)建工具Ant之前,讓我們來快速地回顧一下傳統(tǒng)的構(gòu)建工具--Make--以便從其他角度看看Ant所帶來的優(yōu)點。有許多不同的增強版Make,包括各種Unix變種,Gnu make,以及微軟的NMAKE(New Make),不過它們大體上都是相似的。
  Make接收一個make文件,文件中包含一個目標列表,每個目標后都接著一個腳本,當調(diào)用對應目標時運行。(默認狀況下,Make查找一個特定名字的文件,通常是makefile,但你一般可以在命令行強制指定一個其他名字的文件。)一個目標和它的命令有時稱為 規(guī)則(rules)。
  一個目標可以有依賴(dependencies);也就是其他的必須首先被評估的目標。當Make運行時,它查找第一個目標的依賴以查看它們是否已經(jīng)存在。如果目標是文件,并且依賴也是文件,Make會比較它們的時間戳;如果依賴比目標新,Make會運行規(guī)則以更新目標。
  這是一個make文件規(guī)則的一般格式:

TARGET: dependencies ...
  commands
  ...

  一個小的,簡單的,用來從兩個C源文件構(gòu)建一個程序的make文件看起來可能會是這樣:

myapp.exe: main.obj aux.obj
  link main.obj aux.obj -o myapp.exe

main.obj: main.c
  cc main.c

aux.obj: aux.c
  cc aux.c

  如果你不熟悉C,別擔心具體細節(jié),只要注意從C源代碼創(chuàng)建一個可執(zhí)行程序一般需要的兩個步驟:編譯源代碼為目標文件(示例中的.obj文件)以及把所有的目標文件鏈接為一個單一的可執(zhí)行文件(示例中的.exe文件)。
  第一個目標,myapp.exe,是一條規(guī)定了如何通過連接兩個目標文件以構(gòu)建可執(zhí)行文件的規(guī)則。默認情況下,make文件中的第一個目標就是由Make執(zhí)行的。Make計算依賴鏈以確保鏈上的每個東西都是最新的。你第一次運行這個make文件時,它首先編譯main.obj和aux.obj,然后把它們連接起來以構(gòu)建程序myapp.exe。
  如果你修改了aux.c并再次運行make文件,main.obj仍然是最新的。因此,Make僅編譯aux.obj文件,之后就連接新的aux.obj和已有的main.obj以創(chuàng)建myapp.exe。
  除了一個構(gòu)建程序的目標外,你還可以添加其他的目標來執(zhí)行特定任務(wù),例如刪除所有生成的文件以便強制完全重建。你可以將以下兩個目標添加到文件末尾:

CLEANALL: CLEAN
  del *.exe
  echo Deleted executable
CLEAN:
  del *.obj
  echo Deleted object files

  因為它們并沒有標識一個要構(gòu)建的真正目標,像這樣的目標通常稱為“偽目標”(pseudo-targets)。這兩個目標并沒有包含在默認目標的依賴鏈中,因此執(zhí)行它們的唯一途徑就是在啟動Make時在命令行中明確指定它們。
  指定CLEAN會刪除所有中間目標文件。指定CLEANALL會首先刪除所有中間目標文件(因為它依賴于CLEAN目標),然后刪除可執(zhí)行文件--以這種方式使用的依賴和方法調(diào)用的效果類似。
  除了規(guī)則之外,一個make文件還能對變量賦值以及訪問環(huán)境變量。因為本概述只是打算提供一個對Make的概覽,在這里我們不會談及這些問題。
  正如例子中所示范的那樣,Make具有一些批處理文件和shell腳本所不具有的重要優(yōu)點:
  • Make減少了構(gòu)建時間。Make能夠計算哪些構(gòu)建目標比它們的源碼更舊,并且只會構(gòu)建對于更新構(gòu)建目標來說必要的那些。當你在做一個在編譯時可能需要花費很長時間的大系統(tǒng)時,這能夠節(jié)省大量時間。
  • Make是說明性的。你不需要去一步一步地告訴它如何構(gòu)建。相反的,你只需將需要構(gòu)建的東西指定為一組相關(guān)的目標集。執(zhí)行順序,或者說控制流程,不會被正規(guī)地顯式規(guī)定--盡管你在必要時可以用偽目標來順序執(zhí)行一組命令。
  • Make是可擴展的。命令是由Shell來執(zhí)行的,所以如果你需要任何shell命令沒有提供的功能,你可以編寫你自己的工具程序--比如,用C語言。
  除了一些古怪行為外(就比如令每個Make用戶至少發(fā)瘋一次的對空格和制表符(Tab)的過度區(qū)分),Make是一個完美的可用的構(gòu)建工具。但示例用C來寫的一個原因是:為了更好的演示Make的增量構(gòu)建的能力。將Make運用在Java中則無法在這點上提供相當?shù)囊嫣?,因為絕大多數(shù)的Java編譯器自動地計算了依賴關(guān)系。假如你有一個Java類, HelloWorld

// HelloWorld.java

public class HelloWorld
{
  public static void main(String[] args)
  {
    Printer printer = new Printer();
    printer.out("Hello, world");
  }
}

  它使用這個Java類,Printer

// Printer.java

public class Printer
{
  void out(String s)
  {
    System.out.println(s);
  }
}

  你可以用一條命令來編譯這兩個類:

javac HelloWorld.java

  Java編譯器,javac,計算了HelloWorld.java并判斷它使用了Printer.java。如果還沒有編譯Printer.java,或者如果Printer.java比Printer.class要新,javac就會編譯Printer.java。換句話說,這一條命令實際上等同于你先前看到的那個C程序的make文件的第一部分--也就是開頭那三條指定了如何構(gòu)建程序的規(guī)則。
  因為增量編譯是Make與批處理文件或者shell腳本相比所能提供的最大優(yōu)點,Java編譯器能自動判斷依賴關(guān)系的能力看來減少了在Java開發(fā)中對Make工具的需求。然而,這并沒有完全消除對某些類型的構(gòu)建工具的需求,因為對象的類型在編譯時并不總是知道。類能包含集合引發(fā)了問題,因為一個集合可以存放任意類型的對象;例如,一個Company類可能包含有一個Employee的Vector,而編譯器可能無法在編譯時判斷出來。如果你需要可靠的增量編譯,你仍會需要某些類型的構(gòu)建工具。
  最后也是最重要的一點,編譯并不是構(gòu)建工具所做的唯一一件事。正如示例所示,傳統(tǒng)的make文件一般也執(zhí)行一些像刪除舊文件這樣的簡單的“管家”任務(wù)。Java項目經(jīng)常需要額外的步驟,例如生成Javadoc以及把包歸檔。

5.3 新的Java標準:Ant


  將傳統(tǒng)的Make工具應用到Java中有一個嚴重的缺點:這些工具運行的是shell命令,而它們在各個平臺上都不一樣。這個事實使得采用Java開發(fā)的主要因素之一:一次編寫,到處運行的能力,變得毫無用處。明顯的解決方案就是實現(xiàn)一個能說得上是“Java上的Make”的工具。Ant,一個來自Apache軟件基金會(ASF)的開源構(gòu)建工具,走上了這條路。除了成為了比Make更好的跨平臺解決方案之外,Ant還更新了make文件的語法,采用了標準說明格式:XML。由于這些緣故,Ant迅速地成為了Java上的標準構(gòu)建工具,并被緊密地集成到Eclipse中;這種集成包括了一個特殊的編輯器,用來和Ant構(gòu)建腳本一起工作。

注意
目前為止,因為你一直在使用Eclipse來編譯你的Java源代碼,你還不需要一個單獨的Java編譯器。如前所述,Eclipse包含了它自己的特殊的增量編譯器;你所需添加的只是一個Java運行時環(huán)境(JRE)。
要用Ant來構(gòu)造,尤其是在命令行下,你需要有一個完整的Java開發(fā)工具包(JDK)。依據(jù)你的平臺而定,你可能會有許多選擇;但至少你應該使用JDK 1.3.x(JDK 1.4.x更好),Sun的或是其它公司的都行。確保在你的PATH環(huán)境變量中,該JDK的bin目錄要比其它任何包含有JRE的目錄靠前。同樣應確保,在你的CLASS環(huán)境變量中,刪除所有到舊的JDK和JRE的引用。你不需要在classpath中包含任何JDK的標準目錄或者JAR,因為它們會依據(jù)Java編譯器的可執(zhí)行文件(Windows中是javac.exe)和Java虛擬機(java.exe)的位置來自動定位。

5.3.1 一個對XML的非常簡短的介紹

  XML(可擴展標記語言,Extensible Markup Language)已經(jīng)成為了表述任何類型語言,因此你可能已經(jīng)用過它諸多功能中的其中一些了。如果你還沒有用過它,或者已經(jīng)用過但對它的一些技術(shù)還不了解,這份介紹可以讓你能更容易地理解后面對Ant構(gòu)建文件的討論。
  XML來源于SGML(標準廣義標記語言,Standard Generalized Markup Language),與其很相似的HTML(超文本標記語言,Hypertext Markup Language)也是如此。都使用標簽,也就是用尖括號括起來的標識符,就像這樣:

<TITLE>

  不過在HTML和XML之間還是有少數(shù)一些重要的不同點。因為HTML是設(shè)計用來為一個較有限的目標--描述如何將數(shù)據(jù)顯示為一個網(wǎng)頁--提供服務(wù)的,它定義了一組標準標簽。TITLE是一個有效的HTML標簽,但ORDER_NUMBER不是。然而,XML是可擴充的。由你正在使用的應用程序來定義哪些標簽是有效的。在一個使用XML來表示一個在線商店的數(shù)據(jù)的程序中,ORDER_NUMBER就很有可能是一個有效的標簽。
  一個像<TITLE>這樣的標簽稱為一個開標簽(Opening Tag);它標記了一段數(shù)據(jù)的開頭。開標簽通常需要有一個閉標簽,也就是和開標簽名字相同,前面有個斜杠的標簽。下面定義了一個網(wǎng)頁的標題:

<TITLE>A very brief introduction to XML</TITLE>

  HTML對語法要求相當松。開標簽并不總是要求有閉標簽。例如,標簽<P>被用來標記段落開頭,而</P>應該是用來標記末尾。然而實際上,你可以簡單地使用<P>來在一個網(wǎng)頁上表明文字段落間的間隔。這在XML中絕對不是如此--每個開標簽都 必須要有一個閉標簽。
  有時候在HTML中你可以回避不正確的嵌套的開標簽和閉標簽;但在XML中就不行了。以下代碼由于嵌套不正確,在XML中是無效的:

<B><I>This is not valid in XML!</B></I>

  HTML和XML的一個最大不同就是XML是大小寫敏感的。在HTML中,<TITLE>和<title>都是有效且是等價的。在XML中,取決于應用程序,它們都可能有效,但并不等價。

元素和屬性
  一個開標簽和一個閉標簽定義了一個元素(element)。每個XML文檔必須有一個根元素(或文檔元素)來把文檔中的所有其它元素包圍起來。
  每個元素的開標簽可能包含了形式為名字-值對(name-value pairs)的與元素相關(guān)的附加信息,我們稱之為屬性(attributes)。其中的值必須總是用引號包圍。按標簽不同,特定的屬性可能是必需的,或是可選的。比如,Ant定義了一個<target>標簽來標識構(gòu)建目標。這個target標簽接受好幾個屬性,例如depends和description,但只有name屬性是必需的:

<target name="Compile" depends="Init">
  <!-- do compilation stuff here-->
</target>

 ?。ㄗ⒁饬?,如同在HTML中一樣,你可以插入以<!--開頭,-->結(jié)尾的注釋。)
  有時候元素會沒有任何內(nèi)容。例如,用來運行Java程序的Ant標簽,<java>,允許你在屬性中給定所需的所有信息。如果你有一個類文件Hello.class,你可以放置在一個target里面來運行它,如下所示:

<target name="SayHello">
  <java classname="Hello.class"> </java>
</target>

  作為一種便捷的形式,像這里那個具有/<java>標簽的空元素可以把開標簽寫成以/>結(jié)尾,然后忽略閉標簽。以下和前面的例子是等同的:

<target name="SayHello">
  <java classname="Hello.class"/>
</target>

用屬性和嵌套元素來表示數(shù)據(jù)
  屬性(例如<target>標簽中的name屬性)和嵌套元素(例如被<TITLE>和</TITLE>標簽所包圍的文本)在XML中都能被用來說明數(shù)據(jù)。由應用程序來選擇。有時應用程序會同時支持兩種格式并讓用戶來選擇。Ant有時會提供屬性以選擇單個選項(例如classname),復雜些的就用嵌套標簽,例如文件集,或是路徑與個別文件的組合。
  舉個例子,標簽<java>,讓你既可以用一個屬性來指定類路徑(classpath),也可以用嵌套元素。你可以用classpath來將路徑設(shè)置為預定義好的屬性java.class.path(Ant把它設(shè)為你的環(huán)境的類路徑),如下所示:

<target name="SayHello">
  <java classname="Hello.class" classpath="${java.class.path}"/>
</target>

  或者你可以使用一個嵌套的classpath元素,兩者是等價的:

<target name="SayHello">
  <java classname="Hello.class">
    <classpath path="${java.class.path}"/>
  </java>
</target>

  嵌套元素可以依次包含嵌套元素。例如,你可以用一個或多個的嵌套<pathelement>元素來替換掉<classpath>標簽中的path屬性,別的元素也可如此:

<target name="SayHello">
  <java classname="Hello.class">
    <classpath>
      <pathelement path="${java.class.path}"/>
      <pathelement location="c:/junit/lib/junit.jar"/>
    </classpath>
  </java>
</target>

  由于允許像這樣的多個選項,有時Ant和其它使用XML的程序會讓人難以理解。嵌套元素提供了比屬性強得多的靈活性,后者局限于單個值。如果你僅僅需要一個值,使用簡單些的語法來設(shè)置選項會很方便。
  使用嵌套元素這種方式來擴展選項顯示了XML的主要問題:冗長。你包含進去的每一點點的數(shù)據(jù)都添加了另一對開標簽和閉標簽。好在(或者說是因為很有必要),大多數(shù)基于XML的程序都提供了工具,以使得編寫XML的工作更輕松些。

5.3.2 一個簡單的Ant示例

  在探究Ant及其構(gòu)建腳本的細節(jié)之前,讓我們通過“Hello,World.”的Ant等價物來看看Eclipse中的Ant的使用技巧。如同Make默認將一個make文件命名為makefile一樣,Ant的默認構(gòu)建腳本名為build.xml。和Make一樣,你可以通過在調(diào)用Ant時顯式指定一個文件來跳過默認設(shè)置。然而,通常還是遵守這個約定較好,尤其是因為Eclipse也同樣將構(gòu)建腳本默認命名為build.xml,并且會自動用Ant腳本編輯器打開叫這個名字的文件。(你可以到[窗口]->[首選項]->[工作臺]->[文件關(guān)聯(lián)]對話框去更改它的行為,但把它修改為打開所有的.xml文件并不是個好主意--將來你會見到其它類型的XML文件,它們將更能從其它專用編輯器獲益。如果你不愿把你的構(gòu)建腳本叫做build.xml,在[文件關(guān)聯(lián)]對話框中逐個輸入所有的構(gòu)建腳本名,以便用Ant編輯器打開它們。)
  要創(chuàng)建構(gòu)建文件,可以在一個現(xiàn)存的項目(比如你的老項目Hello)上右擊鼠標,然后在快捷菜單中選擇[新建]->[文件]。輸入build.xml作為文件名并點擊[完成]。如果編輯器沒有自動為你打開build.xml,那么就雙擊build.xml文件。輸入以下內(nèi)容:

<?xml version="1.0"?>
<project name="Hello" default="print message">
  <target name="print message">
    <echo message="Hello from Ant!"/>
  </target>
</project>

  Ant編輯器并不像Java編輯器那么有用,但是它提供了一些基本的方便,例如你可以在任何時候通過按下[Ctrl]+[空格]鍵來調(diào)用自動代碼完成功能。在標簽外時,它會顯示有效的標簽;在標簽里時,它將顯示該標簽的有效屬性。(后面的功能尤其有用,因為各個標簽的屬性名并不相同。)同時,Ant編輯器還提供了語法高亮和一個大綱視圖。
  要運行這個腳本,首先保存它,然后在[包瀏覽器]中右擊build.xml,在快捷菜單中選擇[運行Ant]。這樣將打開一個已經(jīng)選定了默認目標的對話框(參看圖5.4)。

圖5.4 運行一個Ant文件。默認目標已經(jīng)被自動選定。


  點擊對話框底部的[運行]按鈕,Eclipse的控制臺視圖會輸出如下內(nèi)容:

Buildfile: c:\eclipse\workspace\hello\build.xml

print message:
  [echo] Hello from Ant!
BUILD SUCCESSFUL
Total time: 2 seconds

在Eclipse外部運行Ant
  除了可以在Eclipse內(nèi)部運行Ant腳本外,你也可以在Eclipse外部使用構(gòu)建腳本。要這么做,你需要從Apache軟件基金會(ASF,Apache Software Foundation)(Ant項目可以在http://ant.apache.org找到)下載并安裝完整的Ant發(fā)行版。如果當前版本和Eclipse自帶的那個不同(或者不兼容),你就得找到舊版來下載或是升級Eclipse自帶的Ant。
  要升級Eeclipse自帶的Ant,在Eclipse主菜單中選擇[窗口]->[首選項]->[Ant]->[運行時]。然后從classpath中清除1.5.1版的ant.jar和optional.jar,并添加新版的這兩個JAR文件的路徑。
  在下載適合于你系統(tǒng)的p文件(或tar文件)并解壓之后,將bin目錄路徑添加到你的path,lib目錄路徑添加到classpath。如果你將Ant安裝在Windows上的c:\jakarta-ant-1.5.1目錄,你可以通過在命令行下鍵入如下命令來將這些目錄加入到你的path中:

SET PATH=c:\jakarta-ant-1.5.1\bin;%PATH%
SET CLASSPATH= c:\jakarta-ant-1.5.1\lib;%CLASSPATH%

  這些更改只會對當前命令行窗口有效。要想讓設(shè)置長期生效,需要用Windows NT/2000/XP中的[控制面板]的[系統(tǒng)],或是Windows 95/98/ME中的autoexec.bat文件來修改它們,之后你打開的任何命令行窗口都將設(shè)置適合于Ant的選項。在執(zhí)行這些步驟后,現(xiàn)在你可以進入c:\eclipse\workspace\Hello目錄,輸入 ant以運行Ant:

C:\eclipse\workspace\Hello>ant
Buildfile: build.xml

print message:
  [echo] Hello from Ant!

BUILD SUCCESSFUL
Total time: 2 seconds

  如果你在項目的正式構(gòu)建中使用Ant,但在日常工作中繼續(xù)使用Eclipse的自動編譯(這非常方便),你可能要在Eclipse中--或者更愿意在命令行下,偶爾運行 ant來構(gòu)建。這么做可以確保你沒有干擾正式構(gòu)建過程,并且在構(gòu)建中包含了你最近創(chuàng)建的任何文件。
  在你制作一個更大的構(gòu)建文件前,讓我們首先來看看構(gòu)成一個Ant的make文件的重要標簽及屬性的相關(guān)細節(jié)。

5.3.3 項目

  一個構(gòu)建文件必須具備的文檔元素是<project>標簽,它必須指定一個默認目標,還可以指定一個名字(可選的)。此外,還可以標明項目的基本目錄。表5.1中列出了它的屬性:

表5.1 <project>標簽屬性
屬性 描述 是否必需
default 要運行的默認目標
name 項目名稱
basedir 基本目錄
description 項目描述

  在basedir屬性中,你既可以指定相對路徑也可以指定絕對路徑;不管哪種情況,這都將被解析為其他標簽可以使用的絕對路徑。然而使用一個相對路徑會較好,因為這樣能讓構(gòu)建更具可移植性。在進行一次構(gòu)建時,其它開發(fā)者的機器以及正式構(gòu)建用機不需要設(shè)置得和你的一樣。以下示例將basedir屬性設(shè)置為當前路徑(.)--也就是說,定位到build.xml所在的目錄:

<project name="Hello" default="compile" basedir="." description = "Hello, world build file">

<project>標簽可以有以下嵌套元素:
  • <desciption>--如果你需要將描述擴展到超過一行,你可以用嵌套元素來包含項目描述,而非用一個屬性。強烈推薦寫上描述。
  • <target>--如5.3.4節(jié)所述。
  • <property>--如5.3.6節(jié)所述。

5.3.4 目標

  一個目標(target)就是一個任務(wù)或是一組相關(guān)任務(wù)的容器標簽,可以(粗略地)比喻為一個方法(method)。它可具有如表5.2所列屬性:

表5.2 <target>標簽屬性
屬性 描述 是否必需
name 目標名稱
depends 依賴關(guān)系列表
if 僅當設(shè)置了指定屬性時執(zhí)行
unless 僅當未設(shè)置指定屬性時執(zhí)行
description 目標描述

  為你的主要目標給出一份描述是個好主意,因為Ant提供了一個-projecthelp選項來列出所有具有描述的目標,并把它們作為主要目標。這個選項令你的構(gòu)建文檔在一定程度上可以進行自我文檔編制。
  這里是一個例子:

<target name="compile" depends="init" description="Compile all sources">

5.3.5 任務(wù)

  如果把一個目標比喻為一個方法,一個任務(wù)(task)可以比喻為方法中的一條語句。Ant提供了大量的任務(wù)--超過100條,如果你把核心任務(wù)和可選任務(wù)都算上。
  Ant的巨大優(yōu)點之一是它對跨平臺問題是透明處理的。例如,在UNIX中,一個文件路徑在目錄和文件間用的是向前的斜線(/),而在Windows中,用的是一個反斜線(\)。在Ant中,你都可以使用,然后Ant會提供對你正在使用的系統(tǒng)來說正確的格式。對于類路徑來說也是一樣的。在UNIX中,一個類路徑中不同的路徑是用一個冒號分隔的,而在Windows中使用的則是一個分號;你兩個都可以用,剩下的事情就交給Ant了。
  以下是一些常見的人物,它們都有一組基本屬性--足以理解示例并開始編寫你自己的構(gòu)建文件。需要一份所有任務(wù)及其選項的完整描述的話,請參考http://ant.apache.org/manual/index.html上的Ant文檔。

<buildname>
  該任務(wù)從一個文件中讀取構(gòu)建號(build number),將屬性build.number設(shè)置為該號碼,然后將build.number的值+1后寫回文件。它只有一個屬性,如表5.3中所列:

表5.3 <buildname>任務(wù)屬性
屬性 描述 是否必需
file 要讀取的文件(默認:build.number)

  這里是一個例子:

<buildnumber file="buildnum.txt" />

<copy>
  該任務(wù)復制一個或一組文件。要拷貝單個的文件,用file屬性即可。要拷貝多個文件,需要用一個嵌套的<fileset>元素。
  通常,該任務(wù)僅當目標文件不存在或比源文件舊時才執(zhí)行復制,但你可以通過設(shè)置override屬性為true來改變默認行為。<copy>任務(wù)的屬性如表5.4中所列:

表5.4 <copy>任務(wù)屬性
屬性 描述 是否必需
file 源文件名 是,除非使用了<fileset>
tofile 目標文件名 是,除非使用了todir
todir 目標目錄 是,如果拷貝一個以上的文件
overwrite 覆蓋更新的目標文件 否;默認是false
includeEmptyDirs 復制空目錄 否;默認是true
failonerror 如果找不到文件則停止構(gòu)建 否;默認是true
verbose 列出已復制的文件 否;默認是false

  一個<fileset>嵌套元素可以用來指定一個以上的文件。(參看5.3.7節(jié)。)
  這里是一個示例:

<copy file="log4k.properties" todir="bin"/>

<delete>
  該任務(wù)刪除一個或一組文件,或者一個目錄。要刪除單個的文件,用file屬性即可。要刪除多個文件,則要用一個嵌套的<fileset>元素。要刪除目錄,用directory屬性即可。<delete>任務(wù)的屬性如表5.5中所列:

表5.5 <delete>任務(wù)屬性
屬性 描述 是否必需
file 要刪除的文件 是,除非使用了<fileset>或dir
dir 要刪除的目錄 是,除非使用了<fileset>或file
verbose 列出已刪除的文件 否;默認是false
failonerror 如果出錯則停止構(gòu)建 否;默認是true
includeEmptyDirs 使用<fileset>時刪除文件夾 否;默認是false

  一個嵌套的<fileset>元素可以用來指定一個以上的文件。(參看5.3.7節(jié)。)
  這里是兩個例子:

<delete file="ant.log"/>
<delete dir="temp"/>

<echo>
  該任務(wù)將一條信息寫到System.out(默認),一個文件,一份日志,或者一個偵聽器。它的屬性如表5.6中所列:

表5.6 <echo>任務(wù)屬性
屬性 描述 是否必需
message 要寫入的文本 是,除非用了文本作為元素內(nèi)容
file 輸出文件
append 附加到文件(而非覆蓋) 否;默認是false

這里有一些例子:

<echo message="Hello"/">
<echo>
  This is a message from Ant.
</echo>

<jar>
  該任務(wù)將一組文件壓縮到一個JAR文件中。允許的選項如表5.7中所示:

表5.7 <jar>任務(wù)屬性
屬性 描述 是否必需
destfile JAR文件名
basedir 要打包的文件的基本目錄
includes 要打包的文件的模式列表
excludes 要排除的文件的模式列表

  模式列表是由逗號或空格分隔的文件匹配模式列表。<jar>接受如同<fileset>元素的嵌套元素。(參看5.3.7節(jié)。)
  這里是一些例子:

<jar destfile="dist/persistence.jar"
  basedir="bin"
  includes=
  "org/eclipseguide/persistence/**, org/eclipseguide/astronomy/**"
  excludes="*Test*.class "/>

<jar destfile="dist/persistence.jar">
  <include name="**/*.class"/>
  <exclude name="**/*Test*"/>
</jar>

<java>
  任務(wù)java使用一個JVM(Java虛擬機)來調(diào)用一個類。默認情況下,所用的JVM和Ant用的是同一個。如果你是在調(diào)用一個穩(wěn)定的自定義構(gòu)建工具,這樣可以節(jié)省時間;但如果你是在用它運行沒測試過的代碼,你將冒錯誤代碼乃至構(gòu)建進程崩潰的風險。你可以將fork選項設(shè)置為true來調(diào)用一個新的JVM。該任務(wù)的屬性如表5.8中所列:

表5.8 <java>任務(wù)屬性
屬性 描述 是否必需
classname 要運行的類的名稱 是,除非指定了jar
jar 要運行的可執(zhí)行JAR文件的名稱 是,除非指定了classname
classpath 要用的Classpath
fork 用一個新的JVM運行類或JAR 否;默認是false
failonerror 當發(fā)生錯誤時停止構(gòu)建 否;默認是false
output 輸出文件
append 附加或覆蓋默認文件

  任務(wù)<java>可用以下嵌套元素:
  • <classpath>--可用于代替classpath屬性
  • <arg>--可用于指定命令行參數(shù)
  這是一些例子:

<java classname="HelloWorld"/>
<java classname="Add" classpath="${basedir}/bin">
  <arg value="100"/>
  <arg value="200"/>
</java>

<javac>
  該任務(wù)編譯一個或一組Java文件。它有一組復雜的選項(參看表5.9),但它比你所想象的要更容易使用,因為很多選項是提供給你以控制編譯器選項的。Ant設(shè)定的選項是面向目錄工作的,而非單個的Java文件,這讓構(gòu)建項目更容易。

表5.9 <javac>任務(wù)屬性
屬性 描述 是否必需
srcdir 源碼樹的根 是,除非使用了嵌套的<src>
destdir 輸出目錄
includes 要編譯的文件的模式列表 否;默認包含所有的.java文件
excludes 用忽略的文件的模式列表
classpath 要用的Classpath
debug 包含調(diào)試信息 否;默認是false
optimize 使用優(yōu)化 否;默認是false
verbose 提供詳細輸出
failonerror 發(fā)生錯誤時停止構(gòu)建 否;默認是true

  默認情況下,<javac>編譯時包含調(diào)試信息。這樣做通常適合于將被用于產(chǎn)品環(huán)境的構(gòu)建。你可能希望有一種方法來打開或關(guān)閉這個選項,也許會采取分開調(diào)試構(gòu)建和發(fā)布構(gòu)建的目標的方法。
  <javac>可用以下嵌套元素:
  • <classpath>--可用于代替classpath屬性。
  • <jar>接受如同一個<fileset>元素那樣的嵌套元素。(參看5.3.7節(jié)。)
  這是一些例子:

<javac srcdir="src" destdir="bin"/>

<javac srcdir="${basedir}" destdir="bin"
  includes="org/eclipseguide/persistence/**"
  excludes="**/*Test*">
  <classpath>
    <pathelement path="${java.class.path}"/>
    <pathelement location="D:/log4j/jakarta-log4j-1.2.7/dist/lib/log4j-1.2.7.jar"/>
  </classpath>
</javac>

<javadoc>
  任務(wù)<javadoc>從Java源代碼文件生成一份Javadoc。任務(wù)jar、 java中用于選擇要包含哪些文件的選項應該比較熟悉了。指定給javadoc的首要選項設(shè)定了要包含哪些Javadoc注釋;參看表5.10。

表5.10 <javadoc>任務(wù)屬性
屬性 描述 是否必需
sourcepath 源碼樹的根 是,除非指定了sourcefiles或者sourcepathref
sourcepathref 到一個指定源碼樹根的路徑結(jié)構(gòu)的引用 是,除非指定了sourcepath或者sourcefiles
sourcefiles 源碼文件的逗號分隔列表 是,除非指定了sourcepath或者sourcepathref
destdir 目標目錄 是,除非已經(jīng)指定了doclet
classpath 類路徑(Classpath)
public 僅顯示公共類及成員
protected 顯示公共和保護的類及成員 否;默認是true
package 顯示包,保護和公共的類及成員
private 顯示所有的類及成員
version 包含@version信息
use 包含@use信息
author 包含@author信息
failonerror 出錯時停止構(gòu)建 否;默認是true

  任務(wù)<javadoc>可用以下嵌套元素:
  • <fileset>--可用于選擇一組文件。Ant自動把**/*.java添加到每個組。
  • <packageset>--可用于選擇目錄。目錄路徑默認為和包名稱一致。
  • <classpath>--可用于設(shè)置classpath。
  這是一些例子:

<javadoc destdir="doctest"
  sourcefiles ="src/org/eclipseguide/persistence/ObjectManager.java"/>

<javadoc destdir="doc"
  author="true"
  version="true"
  use="true"
  package="true">
  <fileset dir = "${src}/org/eclipseguide/astronomy/">
    <include name="**/*.java"/>
    <exclude name="**/*Test*"/>
  </fileset>
  <classpath>
    <pathelement path="${java.class.path}"/>
    <pathelement location ="D:/log4j/jakarta-log4j-1.2.7/dist/lib/log4j-1.2.7.jar"/>
  </classpath>
</javadoc>

<mkdir>
  該任務(wù)創(chuàng)建一個目錄。它具有如表5.11所示的一個屬性。如果指定了一個嵌套目錄,那么若必要的話會連父目錄也一起創(chuàng)建。

表5.11 <mkdir>任務(wù)屬性
屬性 描述 是否必需
dir 要創(chuàng)建的目錄

  這是一個示例:

<mkdir dir="dist/doc">

<tstamp>
  該任務(wù)設(shè)置屬性DSTAMP,TSTAMP以及TODAY。一個嵌套元素,<format>,可用于使用Java類SimpleDateFormat定義的格式來改變它們的格式,但默認情況下,這些格式如下所示:

DSTAMP yyyyMMdd
TSTAMP hhmm
TODAY MMM dd yyyy

  關(guān)于<tstamp>和<format>元素的更多信息,請參看Ant文檔。

5.3.6 屬性

  屬性是你可以在一個構(gòu)建文件中用作符號常數(shù)的名稱-值對。屬性的值是通過用${和}括起名字的方式來引用的。例如,如果一個屬性junit_home已經(jīng)用值D:/junit/junit3.8.1定義,你可以使用該屬性以在編譯時添加junit的JAR文件到classpath中:

<javac srcdir="src" destdir="bin" classpath="${junit_home}/lib/junit.jar"/>

  屬性可以用幾種方式定義:
  • 由Ant預定義
  • 在Ant命令行,用-D選項(例如,ant -Djunit_home=D:/junit/junit3.8.1)定義
  • 在一個構(gòu)建文件中用<property>任務(wù)定義
  由Ant預定義的屬性包含了所有的標準Java系統(tǒng)屬性,包括了以下內(nèi)容:
  • java.class.path
  • os.name
  • os.version
  • user.name
  • user.home
  Ant特有的屬性包括:
  • ant.version
  • ant.file
  • ant.project.name

<property>和名字屬性
  在一個Ant構(gòu)建文件中設(shè)置屬性的最常用方式是利用<property>任務(wù)及其屬性name,以及屬性value或location。屬性value用于設(shè)置一個直接的值:

<property name="jar_name" value="myapp.jar"/>
<property name="company" value="Acme Industrial Software Inc."/>

  屬性location用于設(shè)置一個絕對路徑或文件名。如果你設(shè)定了一個相對路徑,Ant會認為它是基于basedir屬性的,然后把它轉(zhuǎn)換為一個絕對路徑并解析它。此外,文件路徑分隔符會被轉(zhuǎn)換為適合于平臺的字符(/,\,或者是:)。例如:

<property name="junit_home" location= "D:/junit/junit3.8.1"/>
<property name="src" location="src"/>

  第一個例子不會被改動(除了文件路徑分隔符外),因為它表示一個絕對路徑。第二個例子會被擴展,因為它是個相對路徑;假設(shè)basedir(基本路徑)是c:\eclipse\workspace\persistence,${src}就等同于"c:\eclipse\workspace\persistence\src"。

<property>和文件屬性
  你可以用file屬性使用標準Java屬性文件格式來從一個文件中讀取屬性。假設(shè)有個叫build.properties的文件放在基本目錄中或是在classpath中:

# build.properties
junit_home= D:/junit/junit3.8.1
log4j_home=D:/log4j/jakarta-log4j-1.2.7

  你可以用以下標簽來讀取這些屬性:

<property file="build.properties"/>

<property>和環(huán)境屬性
  通過用environment屬性給環(huán)境設(shè)置前綴的方法,像讀取屬性那樣去讀取環(huán)境變量也是可行的。以下給環(huán)境設(shè)置了前綴myenv:

<property environment="myenv">

  之后,你只要使用前綴myenv就可以像訪問屬性一樣訪問環(huán)境變量。例如,如果環(huán)境中定義了JUNIT_HOME,你可以用${myenv.JUNIT_HOME}獲取它的值。
  你應該小心使用該技術(shù),因為并不是在所有操作系統(tǒng)上都支持它。同時,即使底層操作系統(tǒng)是大小寫不敏感的,在Ant中,屬性名也是大小敏感的。這很容易在各版本的Windows中因疏忽而導致問題,因為系統(tǒng)保留了環(huán)境變量的大小寫而執(zhí)行比較時卻不區(qū)分大小寫。
  例如,如果有一個變量CLASSPATH,其值是c:\mylibs,以下既不會創(chuàng)建一個叫classpath的新變量,也不會改變原CLASSPATH變量的大小寫:

set classpath=.%classpath%;c:\anotherlib

  相反的,這樣做會更新原CLASSPATH變量的值為c:\mylibs;c\anotherlib。要確保大小寫像你期望的那樣,你可以先清除該變量然后重新定義它。以下幾行可以放在命令行或是一個批處理文件中,它們可以強制把classpath變成小寫:

set tmpvar=%classpath%
set classpath=
set classpath=%tmpvar%;c:\anotherlib

  如果你正要為Ant設(shè)置環(huán)境變量,像這樣使用Windows批處理文件來預防問題是值得考慮的──尤其是當該批處理文件會用在其它系統(tǒng)上時。

5.3.7 文件集和路徑結(jié)構(gòu)

  由于Ant的特性,許多Ant任務(wù),如<javac>和<jar>要求你設(shè)置路徑和文件集。Ant提供了元素以使你能給它們指定足夠多的細節(jié),你既可以明確地選擇文件和目錄,也可以使用模式(patterns)來包含或排除一組文件或目錄。因為這些元素除了引用對象以外,什么事情也不做,所以被稱為類型(types)。在這里你僅使用兩種類型:<fileset>和<classpath>。

<fileset>
  正如其名字所表述的那樣,<fileset>元素讓你選擇文件集。一個<fileset>必需的屬性只有基本目錄。如果你別的什么也沒有設(shè)定,該目錄下的所有文件及其子目錄都將被選定──特定的臨時文件以及特定工具(如CVS)生成的文件除外。(這樣的文件通常都有特殊的名字,用一個波紋號(~)或#開頭和結(jié)尾,或者具有像CVS和SCCS這樣的特定的名字和擴展名;它們和一個典型項目的一般文件相同的情況極為罕見。要獲得一份Ant要默認排除的完整的模式列表,請參考Ant文檔。)
  你也可以選擇或排除那些和你提供的模式相匹配文件。模式可以包含以下通配符:

匹配一個任意字符
* 匹配零或多個字符
** 匹配零或多個目錄

  考慮這兩個常見的例子:你可以在include屬性中用模式**/*.java來包含所有的Java源文件,也可以在exclude屬性中用模式**/*Test*來排除測試用例。共同使用時,它們指定了除測試用例外的所有Java文件。
  <fileset>元素的屬性如表5.12所列。

表5.12 <fileset>元素屬性
屬性 描述 是否必需
dir 目錄樹的根
defaultexcludes 排除通常的臨時文件和工具文件 否;默認是true
includes 要包含的文件的模式列表
excludes 要排除的文件的模式列表
followsymlinks 使用符號鏈接所指定的文件

  嵌套元素<include>和<exclude>可以分別用來代替includes屬性和excludes屬性。
  這是一些例子:

<fileset dir = "src/org/eclipseguide/astronomy"
  includes = "**/*.java"
  excludes = "**/*Test*"/>

<fileset dir = "src/org/eclipseguide/astronomy/">
  <include name="**/*.java"/>
  <exclude name="**/*Test*"/>
</fileset>

<classpath>
  <classpath>元素讓你可以指定哪些目錄和JAR文件是當類要運行時(或者,對于Java編譯器來說,要編譯時),程序應該搜索的。默認情況下,Ant繼承了環(huán)境的類路徑,但你都需要為特定程序(如JUnit)添加額外的目錄或JAR文件。使用類路徑的任務(wù)提供了一個classpath屬性,但有時使用一個<classpath>嵌套元素會更方便些──尤其是當類路徑很長的時候。路徑可以包含用一個冒號或一個分號隔開的多個文件或目錄;Ant會將分隔符轉(zhuǎn)換為適合于當前操作系統(tǒng)的字符。
  表5.13中列出了<classpath>元素的屬性。

表5.13 <classpath>元素屬性
屬性 描述 是否必需
path 冒號或分號分隔的路徑
location 單個文件或目錄

  一個或多個<pathelement>元素可以通過嵌套來構(gòu)造一個更長的類路徑。<pathelement>接受和<classpath>:path以及l(fā)ocation相同的屬性。
  此外,一個<fileset>可以用于指定文件。
  這是一些例子:

<classpath path = "bin"/>
<classpath>
  <pathelement path="${java.class.path}"/>
  <pathelement location="${junit_path}"/>
  <pathelement location="${log4j_path}"/>
</classpath>

5.3.8 Ant的額外能力

  這里講述的基本知識已經(jīng)足以讓你開始用Ant來工作而不會不知所措了。當你用Ant做更多的事情之后,你很可能會遇到一種情況──也許會發(fā)覺你一直在反復使用相同的<filelist>──并想知道有沒有一種比剪切、粘貼更優(yōu)雅的解決方案。通常,你會發(fā)現(xiàn)在Ant中,幾乎沒有什么是不可能的。
  減少冗余代碼的一種方法是使用引用。例如,Ant中的每個元素都能指定一個ID;并且(取決于涉及的元素的類型)你可以在構(gòu)建文件中的其它地方使用ID來引用那個元素。例如,你可以使用id屬性給一個<classpath>指定一個標識符:

<classpath id="common_path">
  <pathelement path="${java.class.path}"/>
  <pathelement location="${junit_path}"/>
  <pathelement location="${log4j_path}"/>
</classpath>

  這樣一來,這個類路徑就可以在別的地方用refid屬性來引用:

<javac srcdir="src" destdir="bin">
  <classpath refid=common_path/>
</javac>

  Ant提供了任務(wù)和類型以供你過濾文件,如同以文本來復制、替換符號一樣,這樣你就能夠在你的構(gòu)建中包含版本信息──例如,使用帶有一個<filterset>的<copy>任務(wù)。它讓你可以通過使用選擇器類型(如<contains>,<date>和<size>)來按照復雜的條件選擇文件。在很罕見的情況下,Ant沒有可以符合你需求的任務(wù),你會發(fā)現(xiàn)編寫自己的Ant任務(wù)是很簡單的事情。

5.4 一個Ant構(gòu)建的示例


  以下是你的構(gòu)建過程需要做的主要步驟:
  • 編譯程序,輸出到bin目錄
  • 在bin目錄中運行單元測試
  • 生成一份Javadoc文檔,輸出到dist/doc目錄
  • 將程序的類文件打包到dist目錄下的一個JAR文件中
  因為你可能需要能逐步完成這些工作,它們在Ant構(gòu)建文件中是獨立的目標。然而通常,你會需要一次性完成所有步驟,所以你也需要有一個目標依賴于這些獨立的目標。
  通常這些獨立的目標都有共通的安裝需求。你可以創(chuàng)建一個初始化目標來執(zhí)行安裝,該目標可以以依賴的方式包含這些獨立目標。因為這是一個相當簡單的示例,在這里,你所需要做的一切只是通過調(diào)用tstamp任務(wù),初始化屬性DSTAMP,TSTAMP和TODAY為當前的日期和時間,然后打印日期和時間。

5.4.1 創(chuàng)建構(gòu)建文件build.xml

  要創(chuàng)建構(gòu)建文件,請遵循以下步驟:
  1.   
  2. 在[包資源管理器]中的項目Persistence上右擊鼠標,選擇[新建]->[文件]。
  3.   
  4. 在[新建文件]對話框中鍵入build.xml并點擊[完成]。
  在定義任何目標前,讓我們來創(chuàng)建一些屬性,之后就可以像符號常量那樣使用,而無需在構(gòu)建文件中雜亂地堆放實際值。這個方法會讓構(gòu)建文件更容易維護。這是build.xml的開頭:

<?xml version="1.0"?>
<project name="Persistence" default="BuildAll" basedir=".">

  <description>
  Build file for persistence component,
  org.eclipseguide.persistence
  </description>

    <!-- Properties -->
    <property name="bin" location="bin"/>
    <property name="src" location="src"/>
    <property name="dist" location="dist"/>
    <property name="doc" location="${dist}/doc"/>
    <property name="jardir" location="${dist}/lib"/>
    <property name="jarfile" location="${jardir}/persistence.jar"/>
    <property name="logpropfile" value="log4j.properties"/>
    <property name="relpersistencepath" value="org/eclipseguide/persistence"/>
    <property name="alltests" value="org.eclipseguide.persistence.AllTests"/>
    <property name="junit_path" location="D:/junit/junit3.8.1/junit.jar"/>
    <property name="log4j_path" location="D:/log4j/jakarta-log4j-1.2.7/dist/lib/log4j-1.2.7.jar"/>

  如你所料,目錄一般是用location屬性來指定的,Ant會基于項目的基本目錄將它擴展為絕對路徑。有一個例外:relpersistencepath,這是一個你會在多個不同地方會用到的相對路徑,它是基于不同目錄的;要避免Ant將它轉(zhuǎn)變?yōu)榻^對路徑,你需要用value屬性來設(shè)置它。
  也請注意你顯式指定了幾個類路徑。這不是最好的方法──因為這意味著該構(gòu)建只能在一臺以特殊方式配置的機器上工作──但這是最簡單的。你可能想知道你能否用你在Eclipse中設(shè)置的classpath變量來代替。答案是肯定的,使用一個定制的第三方Ant任務(wù)可以實現(xiàn);但這將意味著你只能在Eclipse中使用該構(gòu)建過程。(如果你不介意這個限制,你可以通過到eclipse.tools新聞組搜索一個定制的Ant任務(wù)的代碼。)
  除了該方法之外,特別是當你在Eclipse外部用命令行構(gòu)建時,你可以用其它幾種方法來設(shè)置這些類路徑。第一個方法,也可能是最簡單的,就是通過以下命令將它們添加到環(huán)境的CLASSPATH變量中:

  <Set CLASSPATH=%CLASSPATH%;D:/junit/junit3.8.1/junit.jar;D:/log4j/jakarta-log4j-1.2.7/dist/lib/log4j-1.2.7.jar>

  第二個方法是在命令行顯式用-D選項把它們傳遞給Ant:

  <ant -Djunit_path=D:/junit/junit3.8.1/junit.jar -Dlog4j_path=D:/log4j/jakarta-log4j-1.2.7/dist/lib/log4j-1.2.7.jar>

  更好一點的方法是將這些路徑存在它們自己的環(huán)境變量中。你可以在構(gòu)建文件中用以下屬性標簽讀取它們:

  <property environment="env"/>
  <property name="junit_path" value="${env.JUNIT_HOME}/lib"/>
  <property name="log4j_path" value="${env.LOG4J_HOME}/lib"/>

  或者是在命令行中像這樣來傳遞它們:

  <ant -Djunit_path=%JUNIT_HOME%\lib -Dlog4j_path=%LOG4J_HOME%\lib>

  最后,其它的選項是使用一個屬性文件。你可能有一個名為build.properties的文件,其中有如下幾行:

  <cjunit_path=D:/junit/junit3.8.1/junit.jar>
  <log4j_path=D:/log4j/jakarta-log4j-1.2.7/dist/lib/log4j-1.2.7.jar>

  要在文件中使用這些值,需要在build.xml包含如下標簽:

  <property file="build.properties"/>

  在設(shè)置了屬性之后,就需要包含主要目標了。先放置默認目標不是必要的(就像用Make時一樣),但由于這是個特殊的目標──它僅僅是以一組依賴性的方式來把其它目標鏈接起來,你就需要這樣寫:

  <!-- Main targets -->
  <target name="BuildAll"
    depends="-Init, -Prep, Compile, Test, Javadoc, Jar"
    description="Complete rebuild. Calls Init, Compile, Test, Javadoc, Package"/>
    <echo message="Build complete."/>
  </target>

  按照被BuildAll調(diào)用的順序包含剩下的主目標:下一個是編譯目標。注意,通過將源目錄標識為org,你可以編譯org.eclipseguide.persistence包和 org.eclipseguide.astronomy包中的任何東西,包括單元測試。該技術(shù)是拷貝任何所需資源──在這個例子中是log4j.properties文件──的極好方法:

  <target name="Compile"
    depends="-Init"
    description="Compile all Java classes">
    <!-- Compile org.* (${src}) -->
    <javac srcdir="${src}" destdir="${bin}">
      <classpath>
        <pathelement path="${java.class.path}"/>
        <pathelement location="${junit_path}"/>
        <pathelement location="${log4j_path}"/>
      </classpath>
    </javac>
    <!-- Copy log4j.properties files -->
    <copy file="${logpropfile}" todir="${bin}"/>
    <echo message="Compiled."/>
  </target>

  下一個目標是運行單元測試。要在Eclipse外部運行JUnit測試,你需要用到一個JUnit的TestRunner類。由于你需要能夠在命令行下運行該構(gòu)建文件并且記錄到一個文件中,你需要使用基于文本的TestRunner,即 junit.textui.TestRunner,而不是漂亮的圖形界面版本。要作為一個Java應用程序運行,需要用Ant的java任務(wù)。要確保它不會連同你的構(gòu)建過程一同崩潰,你需要指定它使用獨立的JVM,通過設(shè)置fork屬性為true就可以了。同時,你還必需以嵌套值的方式提供其它的一些值,包括TestRunner要運行的測試類名以及需要用到的類路徑:

  <target name="Test" depends="-Init " description="Run JUnit
    <!-- Run test suite using separate JVM -->
    <java fork="yes" classname="junit.textui.TestRunner" taskname="junit" failonerror="true">
      <arg value="${alltests}"/>
      <classpath>
        <pathelement path="${java.class.path}"/>
        <pathelement location="${bin}"/>
        <pathelement location="${log4j_path}"/>
        <pathelement location="${junit_path}"/>
      </classpath>
    </java>
    <echo message="Tested!"/>
  </target>

  Javadoc目標包括了你在這里用到的絕大多數(shù)復雜任務(wù)。首先,你需要在javadoc標簽中,以屬性來指定包名(packagename)和你要包含的Javadoc備注。然后,由于要排除掉單元測試,你要使用一個嵌套的<fileset>,里面依次包含嵌套的標簽<include>和<exclude>:

  <target name="Javadoc" depends="-Init" description="Create Javadoc">
    <!-- Javadoc, only for persistence classes -->
    <javadoc destdir="${doc}" author="true" version="true" use="true" package="true">
      <fileset dir="${src}/${relpersistencepath}">
        <include name="**/*.java"/>
        <exclude name="**/*Test*"/>
      </fileset>
      <classpath>
        <pathelement path="${java.class.path}"/>
        <pathelement location="${junit_path}"/>
        <pathelement location="${log4j_path}"/>
      </classpath>
    </javadoc>
    <echo message="Javadoc complete."/>
  </target>

  目標Jar相當明了。正如你在javadoc任務(wù)中所做的一樣,你在這里使用一個<fileset>來指定要排除的測試文件。由于用戶需要log4j.properties文件,你還得拷貝它:

  <target name="Jar" depends="-Init ">
    <!-- Jar for persistence classes -->
    <jar destfile="${jarfile}"
      basedir="${bin}"
      includes="${relpersistencepath}/*.class"
      excludes="**/*Test*"
    />
    <echo message="${bin}${relpersistencepath}/**"/>
    <!-- Copy log4j.properties to provide a sample -->
    <copy file="log4j.properties" todir="${dist}"/>
    <echo message="Packaging complete"/>
  </target>

  最后,該是內(nèi)部目標了:-Init和-Prep。(它們的名字用一個連字符開頭,這可以避免它們被直接使用。雖然這不是必需的,但實踐證明這是個好辦法,因為這能令你的意圖更明確清晰。)-Init打印時間。所有的主目標都依賴于它:

  <!-- Internal targets -->
  <target name="-Init"> <!-- private target, omit description-->
    <!-- Set timestamp and print time -->
    <tstamp/>
    <echo message="Build time: ${TODAY} ${TSTAMP}"/>
  </target>

  -Prep僅當你指定了BuildAll目標時調(diào)用。它從以前的構(gòu)建中刪除所有東西──特別是bin和dist目錄:

  <target name="-Prep">
    <!-- Delete output directories -->
    <delete dir="${bin}"/>
    <delete dir="${dist}"/>
    <delete dir="${jardir}"/>
    <!-- Create output directories -->
    <mkdir dir="${bin}"/>
    <mkdir dir="${dist}"/>
    <mkdir dir="${jardir}"/>
  </target>
</project>

5.4.2 執(zhí)行一個構(gòu)建

  運行Ant構(gòu)建文件和以前一樣──在build.xml上右擊鼠標并選擇[運行Ant]。但現(xiàn)在你有更多的選項,這是因為你有更多目標。注意,默認目標BuildAll已經(jīng)被自動選中了,不過你可以用復選框選擇其它目標。例如,你可以選擇Compile和Javadoc(見圖5.5)。

圖5.5 你可以在Ant構(gòu)建對話框中顯式選擇目標


  你也可以設(shè)置目標執(zhí)行的順序,只需點擊[排序]按鈕來打開如圖5.6所示的對話框。點擊一個目標并點擊[上移]或[下移]來改變它的構(gòu)建順序。選擇好之后,點擊[確定]并點擊[運行]來開始構(gòu)建。

圖5.6 目標排序?qū)υ捒颉T谶@里,你可以改變目標執(zhí)行的順序。


  和以前一樣,輸出會顯示在控制臺視圖。不同類型的消息會用不同顏色顯示:Ant狀態(tài)消息是綠色,<echo>消息是橙色,而錯誤──有的話──是紅色。
  如果你很小心,而且沒有作出僅對當前Eclipse環(huán)境有效的假定(例如所依賴的類路徑設(shè)置只有你的Eclipse配置才有),你應該能夠在命令行構(gòu)建。要這么做的話,只需在命令行下鍵入ant,就像你在示例Hello中所做的一樣。
  你已經(jīng)注意包含了項目描述和主目標,這樣一來,別人能比較容易使用你的構(gòu)建文件,因為他們可以在命令行下鍵入ant -projecthelp。這樣會輸出以下內(nèi)容:

C:\eclipse\workspace\persistence>ant -projecthelp
Buildfile: build.xml

Build file for persistence component,
org.eclipseguide.persistence

Main targets:

BuildAll Complete rebuild. Calls Init, Compile, Test, Javadoc, Pa
Compile Compile all Java classes
Javadoc Create Javadoc
Test Run JUnit tests

Default target: BuildAll

  不過由于Ant和Eclipse集成在一起,在Eclipse里運行構(gòu)建文件有不少好處──尤其是當你剛開始開發(fā)時。

5.4.3 調(diào)試構(gòu)建

  雖然Eclipse和Ant沒有為Ant提供一個調(diào)試器,但它們可以幫助識別和糾正可能發(fā)生的多種類型的錯誤。抵御錯誤的最前線,自然是由編輯器提供的語法高亮了。在Ant編輯器中,備注一般是紅色的,文本內(nèi)容是黑色的,標簽和屬性是藍色的,屬性值是綠色的。如果什么東西的顏色和應有的不同(例如有幾行代碼顯示為紅色),這會很明顯,而你就能知道有什么錯了。
  然而,Ant編輯器的語法高亮并不能標識所有錯誤;除了備注缺少括號和閉標簽之外,你你還需要保存你的構(gòu)建文件以便能夠正確解析它。在你保存文件之后,錯誤會被標識在Ant編輯器旁邊的大綱視圖中,也會標識在編輯器的右邊空白處。點擊邊緣的紅框,就會直接跳到錯誤處(如圖5.7)。

圖5.7 Ant編輯器在右邊空白處標識了一個語法錯誤。


  有些錯誤只有在你運行構(gòu)建文件時才能識別出來。比如在你使用了一個無效屬性時。假設(shè)你記得<javac>使用了<fileset>所使用的屬性和嵌套元素的一個超集,并且寫了如下內(nèi)容:

<javac dir="${src}" destdir="${bin}">

  確實,<javac>幾乎具有<fileset>所使用的所有屬性;但唯一的不同之處是,<javac>使用srcdir而<fileset>用的是<dir>。如果運行帶有該錯誤的構(gòu)建文件,當Ant嘗試執(zhí)行該任務(wù)時,會導致在調(diào)試器窗口顯示如下問題:

[javac] BUILD FAILED: file:C:/eclipse/workspace/persistence/
build.xml:38: The <javac> task doesn‘t support the "dir" attribute.

  點擊該錯誤,會導致Ant嘗試跳轉(zhuǎn)到非法代碼。當你在文本[javac]上點擊時──這時就成功地找到問題了。(點擊任何方括號中的任務(wù)名,不只是那些有錯誤的,都會跳轉(zhuǎn)到構(gòu)建文件中的對應代碼。)
  當然,一旦你解決了最初的一些在構(gòu)建過程和構(gòu)建文件中的問題,構(gòu)建問題經(jīng)常都涉及到源代碼了。這正是Ant和Eclipse集成的閃光點,因為在一個編譯錯誤上點擊,就會跳轉(zhuǎn)到源代碼中產(chǎn)生問題的地方。
  例如,假設(shè)在FileObjectManager類的createObjectManager()方法的參數(shù)列表中,你把變量type的名字錯拼為typo。當編譯時,你會得到一個“未解析的符號”的錯誤(見圖5.8)。

圖5.8 Ant調(diào)試輸出。在一個錯誤上點擊就會跳轉(zhuǎn)到源代碼中的對應行。


  在調(diào)試視圖中的錯誤信息上點擊,就會在編輯器中打開相應的源文件,同時光標會跳到錯誤所在行。

5.5 總結(jié)


  團隊開發(fā)對開發(fā)過程提出了新的需求。其中之一就是對協(xié)同團隊中不同開發(fā)者的工作并給出一個正式構(gòu)建的需求。因為這應該是一個可重復的過程,簡單地給出一個特別的構(gòu)建是不夠的。執(zhí)行一個正式構(gòu)建的傳統(tǒng)方法是使用一個叫做Make的命令行工具;這個工具具有廣泛的兼容性,在多種不同平臺上都有其對應版本,但它們都有一個共同的格式,而且語法有些晦澀。
  你當然可以使用Make來構(gòu)建Java產(chǎn)品,但Java和傳統(tǒng)編程語言(如C/C++)在需求上有些許不同;首要的一點就是,Java很努力地要成為一門跨平臺語言,這就使得Make不夠理想。開發(fā)Ant很大程度上就是為了滿足這個需求。同時,除了保留Make的精神外,它還引入了一些新特性,包括XML語法和使用Java類的可擴展性。
  因為它和Eclipse的是集成的,一個Ant構(gòu)建過程既可以在Eclipse內(nèi)部運行,也可以在外部用命令行運行。這樣,在命令行下運行的正式過程,可以完全獨立于Eclipse。這個能力提供了額外的好處──開發(fā)者們將可以使用任何自己喜歡的開發(fā)環(huán)境。
  盡管團隊開發(fā)需要一個構(gòu)建工具,但Ant的使用并不只局限于團隊。即便是在一個像Eclipse這樣能夠自動編譯代碼并且為創(chuàng)建Javadoc文檔、JAR文件以及p文件提供了很易用的向?qū)У拈_發(fā)環(huán)境中,個人也可以從Ant的使用中獲益。一個構(gòu)建過程由多個步驟組成,雖然簡單,但可能冗長乏味并很容易出錯,所以花一點時間用Ant把構(gòu)建過程自動化將是一項值得考慮的投資。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
java 打包
Maven 2.0:編譯、測試、部署、運行
用Maven做項目管理
Openfire服務(wù)端源代碼開發(fā)配置指南
phonegap3.4.0 生成PHONEGAP.JAR
Android Studio導入項目的幾種方法
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服