Building a JNI Universal Application with Xcode 3.0
アップルにある「Building a JNI Universal Application with Xcode」というドキュメントがちょっと古くてXcode 3.0(Leopard)だとうまくチュートリアルの通りに進まなかったのでメモ。
Creating the Initial Application
まず、最初からつまづく。なんといってもNew Projectに「Java Swing Application」が見当たらない。出来上がりのアプリケーションから察するにXcode 3.0では単純に「Java Application」と名前を変えているらしい。
プロジェクトの構成
そして一番の問題がプロジェクトがほとんどAnt-basedになっちゃってること。
そのせいで新規にビルドフェーズをXcode上から追加できない。全部自分でbuild.xmlをいじらなくちゃいけない模様。
まあJava開発者ならAntの方が使いやすいだろうという配慮なんだけど私には余計なお世話でした…。
まあとりあえずBuilding a JNI Universal Application with Xcode通りにnativeメソッドをJavaのソースコードに追加して、ライブラリをロードするところまで進める。
Adding the Native Method Declaration and Call
public native String getMyFullName();
Loading the Dynamic Library
static { System.loadLibrary( "MyFirstJNILib" ); }
Creating the Header File
さて、ここら辺からドキュメントが役立たずになってきますよ。
今回はヘッダファイルを作るのに(ドキュメントにあるJavaHeadersターゲットは作成せずに、)antタスクのjavahを使います。javahでヘッダファイルを作るためにいくつかの変数をbuild.xmlに追加します。
build.xml
initターゲットとjarターゲットを修正。
<!-- Initialization target, for any prelimary setup needed to build -->
<target name="init" description="Preparation">
<!-- Get properties from environment -->
<property environment="env"/>
<property name="curr_build_dir" location="build/${env.CONFIGURATION}"/>
<property name="curr_header_dir" location="build/${env.CONFIGURATION}/Headers"/>
<mkdir dir="${curr_build_dir}"/>
<mkdir dir="${curr_header_dir}"/>
<mkdir dir="${src}"/>
<mkdir dir="${lib}"/>
</target>
<target name="jar" depends="compile" description="Build jar">
<mkdir dir="${jars}"/>
<jar jarfile="${jars}/${ant.project.name}.jar" basedir="${bin}" manifest="${resources}/Manifest">
<!-- Inject resources -->
<fileset dir="${resources}/"
excludes="${resources}/Manifest"
/>
<!-- Merge library jars into final jar file -->
<zipgroupfileset refid="lib.jars"/>
</jar>
<!-- generate the header files -->
<javah classpath=""${jars}/${ant.project.name}.jar" outputfile="${curr_header_dir}/MyFirstJNILib.h">
<class name="MyLeopardJNIProject"/>
</javah>
</target>
propertyとjavacタスクを追加したよ。
とりあえずここまででビルドしてみると、うまくいってればbuild/${env.CONFIGURATION}/Headers
フォルダにMyFirstJNIProject.h
ができているはず。
Adding the JNI Library Target
ここのセクションはいくつかの相違点以外は基本的にそのまま。
相違点
- ヘッダ検索パスの追加
- ヘッダファイルのincludeの指定の仕方
- MyFirstJNILibターゲットのDependenciesにJavaHeadersを追加しない
- build.xmlにターゲットを追加する
ヘッダ検索パスの追加
ドキュメントではヘッダ検索パスとして$(SDKROOT)/System/Library/Frameworks/JavaVM.framework/Headers
を追加していたが、さらに"${TARGET_BUILD_DIR}/Headers"も追加する。
ヘッダファイルのincludeの指定の仕方
MyFirstJNILib.cはMyFirstJNILib.hをincludeするが、MyFirstJNILib.hはヘッダ検索パスを前項で追加したため、#include "MyFirstJNILib.h"
ではなく、以下のように指定する。
#include <MyFirstJNILib.h>
build.xmlにターゲットを追加する
追加したMyFirstJNILibターゲットをAntからコンパイルするようにbuild.xmlを編集する。
まず、build.xmlの最初の方にネイティブコードをコンパイルするための変数を追加。
property追加
...
<property name="application.resources" location="${dist}/${ant.project.name}.app/Contents/Resources"/>
<property name="application.resources.java" location="${dist}/${ant.project.name}.app/Contents/Resources/Java"/>
<property name="native.target" value="MyFirstJNILib"/>
<property name="native.project" value="MyLeopardJNIProject.xcodeproj"/>
<property name="native.library" value="libMyFirstJNILib.jnilib"/>
<property name="env.CONFIGURATION" value="Release"/>
<!-- lib directory should contain any pre-built jar files needed to build the project
AppleJavaExtensions.jar is included to allow the built jars to run cross-platform if you depend on Apple eAWT or eIO classes.
See http://developer.apple.com/samplecode/AppleJavaExtensions/index.html for more information -->
...
ネイティブコードのコンパイル
ネイティブコードをXcodeを利用してコンパイルするターゲットを追加。
<!-- Note: this target requires that Xcode Tools be installed -->
<target name="nativelib" depends="jar">
<exec executable="/usr/bin/xcodebuild">
<arg line="-project ${native.project}"/>
<arg line="-target ${native.target}"/>
<arg line="-configuration ${env.CONFIGURATION}"/>
</exec>
<copy file="${curr_build_dir}/${native.library}" toDir="${jars}" failonerror="true" verbose="true"/>
</target>
パッケージング
packageターゲットの依存関係にnativelibターゲットを追加し、*.jnilibをリソースとして追加するタスクを追加する。
<target name="package" depends="nativelib" description="Make a double-clickable Mac OS X application">
<mkdir dir="${dist}"/>
<mkdir dir="${application.resources.java}"/>
<mkdir dir="${application.macos}"/>
<!-- copy jars -->
<copy toDir="${application.resources.java}">
<fileset dir="${jars}">
<include name="*.jar"/>
<include name="*.jnilib" />
</fileset>
</copy>
実行
以上で設定終わり。「ビルドして進行」ボタンを押せばJNIを利用したSwingアプリケーションができあがってるはず。
感想
LeopardになってからJavaが蔑ろにされてる気が…。
ところでJavaでJNI使ってる人ってまだいるのかしらん?
ダウンロード
念のため今回作ってみたプロジェクト。