Ant の build.xml
今まで Ant の build.xml は、メンテナンスのことをあまり考えずに書いてきた。で、今日、build.xml のバグを発見した。ビルドプロセスの一番最後にソフトウェアのインストーラを複数生成しているのだが、一方のインストーラに他方のファイルが混入していた。
このバグの原因は、Ant を depends 属性に頼って動かしていたことだった。一度のビルドでは、ひとつのターゲットは一度しか動かないように Ant が順序を組み立ててくれている。以下の動作となることを期待していた。
1. インストーラに含めるファイル置き場(ディレクトリ)を削除する。 2. ファイル置き場を再作成する。 3. ファイルをそこにコピーする。 4. インストーラを生成する。
これを複数のインストーラに対して繰り返していたのだ。2・3・4 は、Ant のターゲット名が違うので、きちんと動作したが、1 はひとつしか作ってなかったので一度しか動作していなかった。なので、後から生成したインストーラには、前に作成したものが混入していた。
原因が分かったので修正しようとしたんだけど。。。depends 属性に頼っていると実行順序を制御するのが難しいことに気がついた。
今ごろ気がついた。Ant を期待通りに動作させるには、antcall タスクベースで build.xml を書くべきだよ。そうすれば Ant を思い通りに動かせる。まず depends ベースで書いた場合は、以下のようになる。
<project name="hoge" default="all"> <target name="all" depends="init, clean, build"/> <target name="init"> <property name="src" value="src"/> <property name="dst" value="classes"/> </target> <target name="clean" depends="init"> <delete dir="${dst}"/> </target> <target name="build" depends="init"> <javac srcdir="${src}" destdir="${dst}"/> </target> </project>
この例だと短いので depends 属性でも制御できるけど、大きくなると難しい。Ant を思い通りに動かすには、以下のように書いた方がいい。
<project name="hoge" default="all"> <target name="all"> ← init に依存させない <antcall target="clean"/> <antcall target="build"/> </target> <target name="init"> <property name="src" value="src"/> <property name="dst" value="classes"/> </target> <target name="clean" depends="init"> <delete dir="${dst}"/> </target> <target name="build" depends="init"> <javac srcdir="${src}" destdir="${dst}"/> </target> </project>
それぞれのターゲットは、ターゲットが本当に依存しているものだけを depends 属性に書いておく。(もちろん、それぞれの中で antcall タスクを使ってもいいが、一度しか動作しなくてもかまわないタスクを何度も動かすのはもったいない。)
このように書けば、ビルド内の任意のタイミングで動いて欲しいタスクを確実に動かすことができる。
あー、もっと早く気付いてればずいぶん楽ができたのになぁ。。。