自分の会社のJavaプロジェクトでAntが使用されていたので、プロジェクトをビルドするためにAntをざっと勉強した際のメモ。 Javaの3大ビルドツール Ant, Maven, Gradleのうちの1つだが、最近では理由がない限り使われないと思う。 ただ、ビルドツールを理解するうえでは、Antを勉強するだけでも十分基本概念を勉強できると思う。 実務ではビルドツールをある程度理解していることは必須知識になるので、Javaの簡単なビルドと同じことをビルドツールで再現してみることで、一般的なビルドの流れを把握しておくことはとても有益だと思う。
ドキュメント
公式ドキュメント
体系的なチュートリアル
参考記事
Antについてメモ
makeファイルのようなもの
Apache Ant is a Java-based build tool. In theory, it is kind of like make , without make 's wrinkles.
- makeファイルとは異なりshellコマンドベースではなく、xmlベース
- target treeを呼び出して実行される
インストール
- 環境
- Ubuntu@WLS2
- JDKインストール
Antインストール
前提:JDKをインストール済みで、JAVA_HOMEが設定済み
Antのバイナリをインストールする
ダウンロードした圧縮フォルダを解凍し、任意のディレクトリに格納する
2.のディレクトリのパスでANT_HOMEを追加
export ANT_HOME="${HOME_DIR}/apache-ant-1.10.12-bin/apache-ant-1.10.12/"
さらにPATHに追加
export PATH=$PATH:$ANT_HOME/bin
Ant task実行に必要なライブラリをインストールしておく。ANT_HOME/lib配下に格納される。(systemを指定した場合)
cd $ANT_HOME ant -f fetch.xml -Ddest=system
Buildファイル(build.xlm)
以下のUsing Apache Antのページ
Projects
Targets
- tasksとdatatypesのコンテナ
- taskは他のtaskに依存し、antは現在のtaskの前に依存taskが実行されることを保証する
- 依存チェーンで重複で依存している場合でも、一回しか呼び出されないようになっている。
A → B → C → Dの場合は、Dを実行するためにCを実行し、その際にCの依存関係としてB,Aが実行されて、Dの依存関係に戻るが、さらにそこからB,Aを実行するということはない。
A → B → C → D A → B → C A → B A
Tasks
↑のマニュアルの「Ant Tasks」のページ → 各タスクのドキュメント
<task名 attribute1="*value1*" attribute2="*value2*" ... />
ユニークな任意のidを割り当てて、参照することもできる
<*taskname* id="*taskID*" ... />
Properties
- カスタムフィールド
チュートリアル
Hello World with Apache Ant
まず手動でコンパイルしてクラスファイル作成し、実行してみる。この流れをantのbuild.xlmに定義してantのビルドで同じことを再現してみる。
Javaコマンドで実施
-
. ├── build │ ├── classes │ └── jar └── src └── oata └── HelloWorld.java
javaファイルを適当に用意
package oata; public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } }
コンパイルしてclassファイルを作成
javac -sourcepath src -d build/classes src/oata/HelloWorld.java
実行してみる
java -cp build/classes oata.HelloWorld
Hello World
さらにjarファイルも作成してみる。まずはmanifestファイルを用意。
echo Main-Class: oata.HelloWorld>myManifest
jarファイルを作成
jar cfm build/jar/HelloWorld.jar myManifest -C build/classes .
jarファイル実行
java -jar build/jar/HelloWorld.jar
出力
Hello World
ここまでのディレクトリ構成
.
├── build
│ ├── classes
│ │ └── oata
│ │ └── HelloWorld.class
│ └── jar
│ └── HelloWorld.jar
├── myManifest
└── src
└── oata
└── HelloWorld.java
Antで実施
ルートにbuild.xlmを用意
touch build.xml
build.xlmにproject, targe, taskを定義
target
- clean
- compile
- jar
- run
<project> <target name="clean"> <delete dir="build"/> </target> <target name="compile"> <mkdir dir="build/classes"/> <javac srcdir="src" destdir="build/classes"/> </target> <target name="jar"> <mkdir dir="build/jar"/> <jar destfile="build/jar/HelloWorld.jar" basedir="build/classes"> <manifest> <attribute name="Main-Class" value="oata.HelloWorld"/> </manifest> </jar> </target> <target name="run"> <java jar="build/jar/HelloWorld.jar" fork="true"/> </target> </project>
antのtaskを実行する
ant compile ant jar ant run
一括で実行もできる
ant compile jar run
build.xmlを修正する
いくつかの問題を改善する
同じディレクトリ名(src, build, build/classes)を複数回使っている
<!-- 複数回参照するディレクトリ名をプロパティ化 --> <property name="src.dir" value="src"/> <property name="build.dir" value="build"/> <property name="classes.dir" value="${build.dir}/classes"/> <property name="jar.dir" value="${build.dir}/jar"/>
main class, jarファイル名がハードコーディング
<!-- project名をjarファイル名と合わせるようにすると便利 --> <project name="HelloWorld" basedir="." default="main"> <!-- main class名、jarファイル名のハードコーディングを避けるためプロパティ化 --> <property name="main-class" value="oata.HelloWorld"/>
ターゲットの実行順序を覚えていないといけない(ant compile jar run)
main: clean → (compile → jar → run)
<!-- ディレクトリ名をプロパティ参照に変更 --> <target name="compile"> <mkdir dir="${classes.dir}"/> <javac srcdir="${src.dir}" destdir="${classes.dir}"/> </target> <!-- ディレクトリ名をプロパティ参照に変更 --> <!-- dependsで依存関係を追加 --> <target name="jar" depends="compile"> <mkdir dir="${jar.dir}"/> <jar destfile="${jar.dir}/${ant.project.name}" basedir="${classes.dir}"> <manifest> <attribute name="Main-Class" value="${main-class}"/> </manifest> </jar> </target> <!-- ディレクトリ名をプロパティ参照に変更 --> <!-- dependsで依存関係を追加 --> <target name="run" depends="jar"> <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/> </target> <target name="clean-build" depends="clean,jar"/> <!-- antのデフォルトtarget --> <target name="main" depends="clean,run"/>
以上の修正を行うことで、ant
を実行するだけでデフォルトのmainが実行され、compile jar runの順序でtargetが実行される
antコマンド
ant [options] [target [target2 [target3] ...]] Options: -help, -h print this message and exit -projecthelp, -p print project help information and exit -version print the version information and exit -diagnostics print information that might be helpful to diagnose or report problems and exit -quiet, -q be extra quiet -silent, -S print nothing but task outputs and build failures -verbose, -v be extra verbose -debug, -d print debugging information -emacs, -e produce logging information without adornments -lib <path> specifies a path to search for jars and classes -logfile <file> use given file for log -l <file> '' -logger <classname> the class which is to perform logging -listener <classname> add an instance of class as a project listener -noinput do not allow interactive input -buildfile <file> use given buildfile -file <file> '' -f <file> '' -D<property>=<value> use value for given property -keep-going, -k execute all targets that do not depend on failed target(s) -propertyfile <name> load all properties from file with -D properties taking precedence -inputhandler <class> the class which will handle input requests -find <file> (s)earch for buildfile towards the root of -s <file> the filesystem and use it -nice number A niceness value for the main thread: 1 (lowest) to 10 (highest); 5 is the default -nouserlib Run ant without using the jar files from ${user.home}/.ant/lib -noclasspath Run ant without using CLASSPATH -autoproxy Java1.5+: use the OS proxy settings -main <class> override Ant's normal entry point