Ant用build.xml事始め

「Ant椿は恋の花」「Ant驚くタメゴロウ」等Antについて薀蓄を述べようというのではありません。Apache Jakartaプロジェクトのサブプロジェクトの一つであるAnt用のbuild.xmlの書き方について簡単に説明しようと思います。

Unixを使ったソフトウェア開発ならば通常makeを使いますし、Windows上では所謂統合開発環境と呼ばれるツールを使うことが多いと思います。ただmakeはとても便利で汎用的に使える反面、依存関係をちゃんと書くのが非常に難しいのが難点です。依存関係を自動作成してくれるツールもありますが、なかなか思うように動いてくれない事が多いのです。もう少し何とかならないかと思うことはしばしばです。一方Windows上の統合開発環境と呼ばれるツールの場合、何をやってくれているのかが外からは見えにくく、また別のツールとの組み合わせをしたくてもできないことが多く、何だかなぁと思う人は少なくないでしょう。

Antがそういう悩みを100%解決するとは言いませんが、Javaのプログラム開発を行うのであれば、使って損はないツールだと思います。またJakartaプロジェクトで提供されるツールを始めとして、フリーのJavaプログラムのソースをコンパイルする場合、今やMakefileではなく、build.xml(AntのMakefileみたいなの)がついてくる時代ですので、全く知らないでは済ませられません。ちょっとだけ勉強してみましょう(私もそんなに詳しいわけではありませんが)。

Antの取得方法は省略します。Apache Jakartaプロジェクトといえば判るでしょう。この文書を書いている時点での最新バージョンは1.5.1です。

Antはそれ自身がJavaで記述されているツールですので、動作にはJavaVMが必須です。起動用にantというシェルスクリプト(Windows用にはant.bat)が用意されています。ちなみにスタートアップ用のクラスはorg.apache.tools.ant.Mainです。Javaで書かれているということは、JavaコンパイラやCoreクラスのバージョンやら、クラスパスやら、その辺の設定で悩まなければならない要素はあります。

Antのbuild.xmlの考え方はmakeを知っている人なら、それほど難しいものではありません。Makefileに相当するのがbuild.xmlです。Makefile内のall::やらclean::といったmakeターゲットはbuild.xmlではまさしく<target>タグになります。makeとは少し違うのは、makeがMakefileで指定される色々な作業そのものについては気にしないのに対し、Antは<target>でやってよいことが予め用意されている、という点です。このやってよい事をタスクと呼んでいます。ようするにAntは用意されたタスクを実行するツールな訳です。

タスクにはJavaのプログラムの開発に必要なものが概ね用意されています。javacやらjavadoc、jarやrmic、はたまたディレクトリの作成や削除、コピー、zip、cvs等がCoreタスクとしてありますし、オプションタスクとしてJavaCCやJavah、rpm、telnetといった、思いつくものは大体あるので、適当なタスクが無くて困ることは特に無いと思われます。

<project>

さて実際のbuild.xmlの書き方について、Ant自身のbuild.xmlを見てゆきましょう。まず先頭に

    <?xml version="1.0"?>
があることで判るように(それ以前にファイル名がbuild.xmlだし)、build.xmlはXMLファイルです。つまり書式は通常のXMLのルールに従うことになります。もしbuild.xmlファイル中に日本語文字を使うのであれば
    <?xml version="1.0" encoding="Shift_JIS"?>
の様にencoding属性を指定しておく必要があります。XMLなのでルートノードがただ1つあります。build.xmlの場合は常に<project>ノードがルートノードで、ファイルの最後で</project>で終わっています。

    <project default="main" basedir=".">

<project>タグには3つの属性を指定することができます。name、defaultそしてbasedirです。defaultだけが必須です。nameはプロジェクトの名前、defaultはデフォルトのターゲット名、basedirはbuild.xml中の相対パスを指定する基点のディレクトリを指定します。

<property>

<project>タグの下位ノードの主なものは<property>タグと<target>タグになります。<property>タグはいわばマクロ置換のような機能を提供します。例えば、

    <property name="Name" value="Apache Ant"/>
というのは、これ以後Nameで参照している処は、"Apache Ant"の事ですよ、と読むことができます。ant.versionの様に明示的に書かなくとも設定されているプロパティ(ビルトインプロパティ)もあります。プロパティの値のうち、個別の環境に依存するようなものについては別ファイルにするのが一般的です。その場合はfile属性を用いて、
    <property file="${user.home}/.ant.properties"/>
の様にファイルを指定します。指定するファイルは慣習的に.propertiesという拡張子を指定します。ちなみに上記の${user.home}というのはuser.homeというプロパティの値を参照する場合の記法です。user.homeの値が/home/hogehogeならば上記のファイルは/home/hogehoge/.ant.propertiesになるわけです。

<target>

<target>タグでの記述が、build.xmlの中心になります。ここでやりたいことを記述するわけです。Antを起動するときに、

    % ant hoge
とタイプした場合、引数(この場合"hoge")で指定したものに名前が一致するターゲットが実行されます。上記の場合は、
    <target name="hoge">
で始まるターゲットが実行されます。引数が指定されない場合は<project>タグのdefault属性で指定されたデフォルトターゲットが実行されます。<target>タグ自身はname属性、description属性、depends属性を指定できます(他にifやunlessもありますが説明しません)。name属性のみが必須です。name属性はターゲットの名前、description属性はターゲットの説明文です。depends属性では、このターゲットを実行するまえに実行してもらう必要があるターゲットを指定します。例えばコンパイルをする前にコンパイルした結果のクラスファイルを置くディレクトリツリーを作成しておく、といった場合に使用します。Antのbuild.xmlのデフォルトターゲットであるmainの場合、
    <target name="main"
          description="--> creates a minimum distribution in ./dist"
          depends="dist-lite"/>
とだけ書いてあって、ノード自身は空になっていますが、これはdepends属性でdist-liteターゲットが指定されているので、自動的にdist-liteターゲットが実行されます。dist-liteターゲットのdepends属性にはjarsターゲットが、jarsターゲットのdepends属性にはbuildターゲットが、buildターゲットのdepends属性にはprepareターゲットとcheck_for_optional_packagesターゲットが指定されている、という具合に、ターゲット間の依存関係は(ちゃんとしたリリースをしようと思うと)なかなか難しいものがあります。徐々に勉強してゆくのが良いでしょう。

タスク

<target>タグの下位ノードには、そのターゲットで実行したい様々なことをタスクとして記述します。タスクは

    <mkdir dir="${build.dir}"/>
の様にディレクトリを作ったり、
    <copy todir="${dist.lib}">
      <fileset dir="${build.lib}"/>
    </copy>
のようにコピーをしたりするようなものもありますが、とりあえず必要なのはjavacタスクでしょう。

Antのbuild.xmlの場合、

    <javac srcdir="${java.dir}"
           destdir="${build.classes}"
           debug="${debug}"
           deprecation="${deprecation}"
           target="${javac.target}"
           optimize="${optimize}" >
で始まる部分でAntのコンパイルを行っています。それぞれの属性の意味はマニュアルを読めばわかります。問題になるのは(大抵の場合は)クラスパスの指定でしょう。

クラスパスは属性classpathで指定することも可能ですが、多くの場合は複数のjarやclassファイルを参照したいでしょう。その場合は<javac>タグの子ノードとして<classpath<タグを指定します。クラスパスだけでなくソースディレクトリ等パス形式の値を指定するにはみな同じ方法が取れます。

    <classpath>
      <pathelement path="${classpath}"/>
    </classpath>
とすれば、現在のクラスパス自身を使って指定できます。pathで指定する場合はクラスパスをコロンまたはセミコロンでつなぎます。

Antのマニュアルにはクラスパス設定のサンプルとして、

    <classpath>
      <pathelement path="${classpath}"/>
      <fileset dir="lib">
        <include name="**/*.jar"/>
      </fileset>
      <pathelement location="classes"/>
      <dirset dir="${build.dir}">
        <include name="apps/**/classes"/>
        <exclude name="apps/**/*Test*"/>
      </dirset>
      <filelist refid="third-party_jars">
    </classpath>
という例が出てきます。この場合、クラスパスの参照は、まず${classpath}で指定される処、次にすべてのlibディレクトリの中のjarファイル、次にclassesディレクトリ(の中のクラスファイル)、次に${build.dir}のサブディレクトリappsの下位にあるすべてのクラスディレクトリ(の中のクラスファイル)で、かつファイルの名前にTestが含まれていないもの、最後にthrid-party_jarsで参照されるファイルリスト、となります。実際にどの指定がどのように効いてくるのかは、色々設定を試してみるのが一番の近道ですね。

それから

javac以外にもjarを作ったり(warを作ったり)、javadocを作ったりという、Javaを使うプロジェクトで通常必要となるタスクも用意されていますので、実際に使って見てください。


人材開発室 PoisonSoft