« 単純ANTとJAVAメモ:幾つかの落とし穴回避のための | トップページ | ◇justとまだ、seeと見初める;言語の時間軸 »

ANTでJarにまとめる、Jarをまとめる

先の記事単純ANTとJAVAメモ:幾つかの落とし穴回避のためのの 補助記事です。より本格的なシステムを組むためのものです。

 Jarにまとめる、Jarをまとめる

Javaでは 余程単純な試験プログラムで無い限り 一つの実行プログラムは 複数の.classファイルから構成されることになります。

これらがバラバラのファイルのままでは取り扱いが著しく 困難になります。

そこで通常、それらを一つのjarファイルにまとめることに なります。

Javaでは既に作られているライブラリのjarを参照することも あります。
コンパイル時はclasspathにより参照指定できるのですが 実行環境を移す場合、指定はとても難しいものになります。

そこで、ライブラリも含め一つのjarにまとめます。

built.xmlの例を示します。

<?xml version="1.0" encoding="UTF-8"?>
<!-- build.xml -->
<project default="main">
   <property name="classpath" value="./hiNote.jar"/>
   <property name="topdir"    value="otsu"/>
   <property name="installDir" value="../lib" />
   <property name="MAIN"      value="HelloWorld" />
   <target name="main" depends="clean,build,run">
      <echo>=== CLEAN BUILD and RUN done ===</echo>
   </target>
   <target name="build" depends="compile">
      <unjar  src="${classpath}" dest="."/> <!-- jarマージ用に展開 -->
      <jar destfile="${MAIN}.jar" 
           basedir="." 
           includes="**/*.class" >
         <manifest>
           <attribute name="Main-Class" value="${MAIN}"/>
        </manifest>
      </jar>
      <delete dir="${topdir}"/> <!-- マージ後展開ディレクトリ削除 -->
      <delete dir="META-INF"/> <!-- マージ後削除 -->
   </target>
   <target name="compile">
      <javac srcdir           ="."
             includes         ="*.java"
             includeAntRuntime="false"
             encoding         ="UTF-8"
             debug="yes" optimize="no"
             classpath=".;${classpath}" />
   </target>
   <target name="run">
      <java jar="${MAIN}.jar"
            fork="true" failonerror="true">
         <arg line="ANT TEST"/>
         <!-- output="out.txt" error="err.txt" -->
      </java>
   </target>
   <target name="install" depends="build">
      <copy file="${MAIN}.jar" todir="${installDir}" overwrite="yes"/>
   </target>
   <target name="clean">
      <delete dir="." includes="*.class,*.BAK,testOut.txt,${MAIN}.jar"/>
   </target>
</project>

参照しているここでライブラリjarはhiNote.jarで カレントディレクトリに置いてあります。

<target name="compile">でそれをclasspathで参照しコンパイル しています。
ここで自プログラムの.classが生成されます。

<targe name="build">でライブラリを展開し自プログラムと 一緒にjarにすることで、単一jarに必要なものを全て入れています。
<manifest>でMain-Classアトリビュートにmainのクラスを指定する必要があります。
実行可能jarとなります。
システムのライブラリまでは入れる必要はありませんが、付加的な ライブラリはこのような形で取り込むと安定して動くシステムを リリースすることができます。
マージ後展開したフォルダを削除しています。

実行時はjarを指定します。

installでは.jarを<copy>で../libにコピーしています。<copy>ではoverwrite="yes"を必ず 付ける必要があります。多くのプロジェクトがこのoverwrite付け忘れにより混乱に陥っています;ANTの馬鹿げた仕様の一つです

このjarだけで動作可能です。(もちろんjavaの基本部が入っているシステムは必要です)

 Jarにまとめる。他Jarを参照する(注意!)

落とし穴:
javaコマンドでjar指定で起動する場合、 何と! classpath指定は無効です。
信じがたいことですが、バグではなく仕様です。

起動するjar作成時にマニフェストにClass-Pathを指定する必要があります。
先の例では展開して取り込んだhiNote.jarを外置きのまま使う場合、次のような記述となります。

<?xml version="1.0" encoding="UTF-8"?>
<!-- build.xml -->
<project default="main">
   <property name="classpath" value="./hiNote.jar"/>
   <property name="MAIN"      value="HelloWorld" />
   <target name="main" depends="clean,build,run">
      <echo>=== CLEAN BUILD and RUN done ===</echo>
   </target>
   <target name="build" depends="compile">
      <jar destfile="${MAIN}.jar" 
           basedir="." 
           includes="**/*.class" >
         <manifest>
            <attribute name="Main-Class" value="${MAIN}"/>
            <attribute name="Class-Path" value=". ${classpath}"/>
         </manifest>
      </jar>
   </target>
   <target name="compile">
      <javac srcdir           ="."
             includes         ="*.java"
             includeAntRuntime="false"
             encoding         ="UTF-8"
             debug="yes" optimize="no"
             classpath=".;${classpath}" />
   </target>
   <target name="run">
      <java jar="${MAIN}.jar"
            fork="true" failonerror="true">
         <arg line="ANT TEST"/>
      </java>
   </target>
   <target name="install" depends="build">
      <copy file="${MAIN}.jar" todir="${installDir}" overwrite="yes"/>
   </target>
   <target name="clean">
      <delete dir="." includes="*.class,*.BAK,testOut.txt,HelloWorld.jar"/>
   </target>
</project>
この例ではhiNote.jarを展開していません。

 サンプルプログラム

この例でのサンプルプログラムは次のものです。

// HelloWorld.java
import otsu.hiNote.*;
import java.io.*;
public class HelloWorld{
   public static void main(String[]args){
      try{
         PrintWriter pw= new hiMultiPrinter(System.out,"testOut.txt");
         pw.print("Hello");
         for(String s:args) {
            pw.printf(" (%s)",s);
            }
         pw.println(" World!");
         }
      catch(Exception e){
         e.printStackTrace(System.err);
         System.exit(1);
         }
      System.exit(0);
      }
   }

otsu.hiNote.hiMuiltPrinterは複数のプリンタに同じものを出力できるクラスで ここでは標準出力と、testOut.txtファイルに同じものを 出力しています。

オツアンドサンズのライブラリです。
hiNode.jarは70Kバイト程度です。
ターゲットシステムに別途導入してclasspathに設定することが理想ではありますが、 面倒ならここで示したように実行形式.jarに組み込んでも問題はないサイズです。

構文解析ライブラリSymphonieも公開されています。(Symphonie.jar)

説明は

にあります。
オツアンドサンズのホームページは です。

 ダウンロード

実際にこの記事のために作成、動作確認されたANTjar.zipを置きます。
jarを外置きのまま使う例、ANTjar2.zipも用意してあります。 「右クリック-対象をファイルに保存」でダウンロードできます

展開すると次のファイルが得られます。

   ANTjar/
      A00_clean.bat
      A01_build.bat
      A05_run.bat
      A10_test.bat
      A80_install.bat
      A90_release.bat
      AA00_clean.sh
      AA01_build.sh
      AA05_run.sh
      AA80_install.sh
      AA10_test.sh
      build.xml
      HelloWorld.java
      README_UTF8.txt
      READEM_EUC.tzt
      README_SJIS.txt
      release.xml
      hiNote.jar
.batと.shは単にantを呼んでいるだけです。
WindowsとLinuxで動作確認を行ってあります。

|

« 単純ANTとJAVAメモ:幾つかの落とし穴回避のための | トップページ | ◇justとまだ、seeと見初める;言語の時間軸 »

トラックバック


この記事へのトラックバック一覧です: ANTでJarにまとめる、Jarをまとめる:

« 単純ANTとJAVAメモ:幾つかの落とし穴回避のための | トップページ | ◇justとまだ、seeと見初める;言語の時間軸 »