Laboratorium 2 - Apache Ant


Wstęp

  1. Narzędzie Ant, podobnie jak make służy do zarządzania kompilacją projektów składających się z wielu plików źródłowych. Głównym zastosowaniem Anta jest kompilacja projektów pisanych w języku Java. Dzięki temu, że sam Ant jest napisany w Javie, jest niezależny od systemu operacyjnego (działa tak samo pod Windows, jak i pod Liuxem) i można go zastosować do innych celów (np. kompilacja dokumentów Latex).
  2. Aby używać Anta należy napisać skrypt o nazwie build.xml, będący odpowiednikiem makefile. Dzięki użyciu XML, skrypty Anta mogą być w łatwy sposób integrowane z narzędziami dewloperskimi, takimi jak Eclipse. Plik build.xml zawiera:
    • cele (target) które są do zrealizowania i zależności między nimi
    • sposób realizacji celów: zadania (task).
    Przy pomocy polecenia ant kompilujemy projekt. Jako argument możemy podać cel, na przykład ant clean. Jeżeli nie podamy argumentów, wówczas będzie realizowany cel domyślny.

Budowa skryptu build.xml

  1. Plik build.xml składa się z jednego projektu (project) i co najmniej jednego (domyślnego) celu (target). Cel zawiera elementy opisujące zadania (target). Przykładowy projekt ma wygląd:
    <project name="HelloProject" default="dist" basedir=".">
        <description>
            This is a description of a project.
        </description>
    
    Atrybut name określa nazwę projektu, default domyślny cel, basedir katalog roboczy projektu, a description opcjonalny opis.
  2. Cel może zależeć od innych celów, określonych przez atrybut depends.
    <target name="A"/>
    <target name="B" depends="A"/>
    <target name="C" depends="B,A"/>
    
    Jeżeli cel ma więcej zależności (oddzielonych przecinkami), wówczas w pierwszej kolejności jest wykonywany cel pierwszy od lewej. Uwaga: w pierwszej kolejności muszą być spełnione zależności tych celów. W powyższym przykładzie, jeżeli będziemy chcieli wykonać cel C, wówczas najpierw zostanie wykonany cel A, następnie B, a na końcu C, ponieważ C zależy od B, a B zależy od A. Każdy cel jest wykonywany tylko raz.
  3. Zadanie (task) jest kodem, który można wykonać. Każdy task ma strukturę:
    <nazwa atrybut1="wartość1" atrybut2="wartość2" ... />
    Ant posiada bogaty zestaw wbudowanych zadań, służących do wykonywania takich czynności jak kompilacja, operacje na plikach, tworzenie archiwów JAR, uruchamianie programów, korzystanie z CVS, a także do sterowania wykonaniem skryptów Anta (np. zadania warunkowe). Istnieją również zadania opcjonalne, a także można tworzyć własne definicje zadań (w języku Java).
  4. Każdy element może mieć zdefiniowany identyfikator przez użycie atrybutu id. Potem możemy odwołać się do tego elementu używając atrybutu refid w elemencie tego samego typu.

    Przykładowo, następujący projekt:

    <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>
    
    Może byc przepisany jako:
    <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>
    

Zmienne w skrypcie Anta

  1. W pliku build.xml można definiować zmienne, przy pomocy zadania property tak jak w poniższym przykładzie:
     <property name="src" location="src"/>
     <property name="build" location="build"/>
     <property name="dist"  location="dist"/>
    
    Ant posiada wbudowane zmienne, takie jak basedir, ant.version, ant.file, ant.project.name, ant.java.version.
  2. Do zmiennych odwołujemy się używając znaku dolara i nawiasów klamrowych, tak jak w poniższym celu używamy zmiennej build:
      <target name="init">
        <!-- Utworzenie katalogu build w którym będą umieszczane skompilowane pliki. -->
        <mkdir dir="${build}"/>
      </target>
    

Najważniejsze zadania Anta

  1. Zadania operujące na systemie plików:
    <mkdir dir="nowy_katalog"/>
    
    <copy file="myfile.txt" tofile="mycopy.txt"/>
    
    <copy file="myfile.txt" todir="../some/other/dir"/>
    
    <delete dir="katalog"/>
    
  2. Kompilacja plików języka Java
    <javac srcdir="${src}" destdir="${build}"/>
    
    Zadanie javac wyszukuje i kompiluje wszystkie pliki *.java w podanym katalogu i podkatalogach. Javac kompiluje tylko te pliki, które zostały zmodyfikowane po ich ostatniej kompilacji.
  3. Tworzenie archiwum JAR

    <jar jarfile="${dist}/lib/HelloProject.jar" basedir="${build}"/>
    
  4. Tworzenie dokumentacji przy pomocy Javadoc
      
      <javadoc
               destdir="docs/api"
               windowtitle="Test API">
        <fileset dir="src" defaultexcludes="yes">
          <include name="pl/edu/agh/**"/>
        </fileset>
    
      </javadoc>
    Uwaga: Javadoc nie sprawdza, czy pliki źródłowe były zmodyfikowane, tylko generuje całą dokumentację od początku.
  5. Uruchomienie aplikacji Javy. Należy podać klasę zawierającą metodę Main().
           <java classname="hello.client.Main">
             <classpath>
               <pathelement location="dist/lib/hello.jar"/>
               <pathelement path="${java.class.path}"/>
             </classpath>
           </java>
    
    

Typy

Ant posiada bogaty zestaw wbudowanych typów, ułatwiających wykonywanie zadań na zbiorach plików, dopasowanie wzorców, korzystanie z wyrażeń regularnych itp. Poniżej zamieszczone są przykłady najczęściej używanych:
  1. Zbiory plików:
    <fileset dir="${server.src}" casesensitive="yes">
      <include name="**/*.java"/>
      <exclude name="**/*Test*"/>
    </fileset>
    
  2. Zbiory wzorców są bardziej ogólne:
    <patternset id="non.test.sources">
      <include name="**/*.java"/>
      <exclude name="**/*Test*"/>
    </patternset>
    
    można się do nich następnie odwoływać przez nazwę:
    <fileset dir="${client.src}" >
      <patternset refid="non.test.sources"/>
    </fileset>
    
  3. UWAGA: We wzorcach nazw plików można używać symbolu podwójnej gwiazdki (**), co oznacza wszystkie katalogi i ich podkatalogi (rekursywnie wgłąb) spełniające wzorzec. Na przykład: do wzorca: **/srv/** pasują wszystkie pliki, w których ścieżce występuje element srv; do wzorca hello/**/*.java pasują wszystkie pliki o rozszerzeniu .java w katalogu hello i w całym poddrzewie jego podkatalogów.
  4. Większość zadań korzysta z domyślnych wzorców nazw plików, na których operuje. Np. javac zamienia pliki .java na pliki .class w podanym drzewie katalogów.

Ćwiczenie

  1. Proszę pobrać przykładowy projekt hello.tar.gz, rozpakować go, a następnie skompilować załączonym do niego skryptem build.xml.
  2. Uwaga:
    • Czasem z niewiadomych przyczyn aplikacja nie kompiluje się prawidłowo, gdy język w systemie jest ustawiony na polski (!!!). Wtedy należy zmienić wartość zmiennej:
      export LC_ALL=en_EN
      
    • po skompilowaniu poleceniem ant aplikację uruchamia się będąc w katalogu build poleceniem
      java hello/client/MainApp
  3. Proszę rozbudować skrypt o następujące cele:
    • javadoc - generujący dokumentację
    • rebuild - kompilujący wszystkie pliki od nowa
    • tworzenie osobnych plików JAR dla pakietów hello.srv i hello.client
    • rebuild.dist - tworzenie całej dystrybucji od początku
    • run - uruchomienie aplikacji hello
    • opcjonalnie: pobranie źródeł z CVS.

Informacje dodatkowe

  1. Szczegółowe informacje zawarte są na stronie projektu Ant: ant.apache.org.
  2. Jeżeli Ant nie jest zainstalowany, można go łatwo zainstalować samodzielnie. Wystarczy pobrać binarną dystrybucję, rozpakować ją, a następnie ustawić zmienną środowiskową ANT_HOME aby wskazywała ścieżkę do tej dystrybucji, oraz do zmiennej PATH dołączyć ANT_HOME/bin. Mozna to zrobic w katalogu /tmp, zeby uniknac rozpakowywania przez sieciowy system plikow, np.:
    mkdir /tmp/$USER
    cd /tmp/$USER
    wget http://apache.forall.pl/ant/binaries/apache-ant-1.7.0-bin.tar.gz
    tar zxvf apache-ant-1.7.0-bin.tar.gz
    export ANT_HOME=/tmp/$USER/apache-ant-1.7.0
    export PATH=$ANT_HOME/bin:$PATH
    


Bartosz Baliś, balis at agh.edu.pl
Maciej Malawski, malawski at agh.edu.pl