技術情報
2010.03.06
 
JExternalのためのXcodeの利用法

JExternalによって、4Dから呼び出されるJavaメソッドを、効率的に作成/デバッグする方法を解説したページを設けました。Apple社のXcodeを使用すれば、4Dの実行時に4Dと連動して、Javaメソッドをデバッグすることができます。


http://www.ronri-kobo.com/Japanese/HowToUseXcode_JP.html

[2010.03.06 加筆]
上記の解説は、古いXcodeを使用した解説です。JavaプロジェクにANTを使用する現在のXcodeとは多くの点で異なります。しかし、肝要な部分は現在も同じで、4Dの実行時にJavaメソッドをデバッグするためには、Executabl PathをJavaから4Dに変更することです(上記解説の[1.5]を参照してください)。現在のJExternalのデモに付属するXcodeプロジェクトは、すべて新しくなっており、Xcodeから4Dを起動し、4Dの実行時にJavaメソッドがデバッグできる設定になっています。

JWorld, JExternal, JbyJが、インテルプロセッサ搭載Macで動作しない原因
インテルプロセッサ搭載の新しいMac上のアプリケーションには、2つのタイプがあります。 インテルプロセッサ本来のバイナリコードが実行されるものと、PowerPCのバイナリコードをRosettaというエミュレータを介して実行されるものです。 もちろん、前者がインテルプロセッサの本来の威力を発揮します。現在(2006年2月 )の4Dは、後者のタイプで、Rosettaを介して実行されます。

一方、インテルプロセッサ搭載のMacで、Javaバーチャルマシンを起動できるのは、インテルプロセッサ本来のバイナリコードだけです。 PowerPCのバイナリコードからRosettaを介してJavaバーチャルマシンを起動することはできません。 この制限により、現在の弊社のJava関連のプラグインは、インテルプロセッサ搭載のMacで動作しません。。

弊社Java関連のプラグインが、インテルプロセッサ搭載のMacで動作するためには、Universal Binary化されなければなりません。 Universal Binaryとは、PowerPC搭載の旧来型のMacとインテルプロセッサ搭載の新しいMacの両方で動作するためのバイナリの形式です。 しかし、弊社のプラグインだけをUniversal Binary化しただけでは、問題は解決しません。4D自身もUniversal Binary化されなければならなりませんし、 一緒に使用する他のプラグインもすべてUniversal Binary化されなければなりません。 なぜなら、アプリケーションを構成する要素の1つでも、Universal Binary化されていないものがあれば、 Mac OSは、そのアプリケーションをRosettaを介して実行してしまうからです。

これは弊社プラグインを使用していない場合でも、問題になります。 なぜなら、1つでもUniversal Binary化されいないプラグインがあれば、それがアプリケーション全体のパフォーマンスを落とすことになるからです。 弊社プラグインをUniversal Binary化することに技術的問題はありません。 既存の弊社のMac版プラグインはすべてApple社のXcodeで作成されており、それを単に最新のXcodeで再コンパイルするだけです。 しかし、その動作確認を行うためには、まずUniversal Binary化された4Dが必要になります。

参考:
http://developer.apple.com/jp/qa/qa2005/qa1295.html
http://developer.apple.com/jp/documentation/MacOSX/Conceptual/universal_binary/ universal_binary_exec_a/chapter_7_section_4.html
[2010.03.06 加筆]
現在、4D(v11以降)も弊社プラグインもUniversal Binary化されており、問題なくインテルプロセッサ搭載Macで動作します。

[JWorld] ストラクチャの切り替えについて
JExternalとJbyJでは、Javaバーチャルマシンを起動するために、 JWorldと言うもう一つのプラグインを利用しています。JWorldは、4DからJavaを利用するために、Sun Microsystems社のJNI (Java Native Interface)というC言語ライブラリを使用しています。JNIでは、JNI_CreateJavaVMという関数でJavaバーチャルマシンを起 動し、DestroyJavaVMという関数でJavaバーチャルマシンを終了させることになっています。しかし、4DでこのJNIを利用する場合は、 4Dが動作している間はDestroyJavaVMを呼び出すことができないという制約があり、一度起動したJavaバーチャルマシンを終了させるために は、4Dを終了する以外に手段はありません。

一方、ユーザモードの「データベースを開く」で、ストラクチャが切り替えられた場合、切り替える前のプラグインはすべてアンロードされ、切り替え後のプラ グインは新たにロードされ初期化されます。たとえ、切り替える前と後で同じプラグインがあったとしても、別のプラグインとして扱われます。このことは JWorldにとって問題となります。なぜなら、JWorldがアンロードされたとしても、上記の制約のためJavaバーチャルマシンは「生き続けてい る」からです。不必要となったJavaバーチャルマシンが生き続けたとしても、別スレッドで動作しているため、4Dに影響を与えることはありませんが、 JWorldが新たにロードされたときに、すでに起動しているJavaバーチャルマシンを初期化することができません。

ストラクチャを切り替える前後でプラグインJWorldを使用する場合、上記の理由で一度起動したJavaバーチャルマシンを再度初期化することができな いため、最初に設定されたクラスパスだけがいつまでも有効で、本来、切り替え後に有効になるはずのクラスパスは有効になりません。つまり、最初のストラク チャといっしょに使用されるJavaClassesフォルダにあるJavaファイルだけがクラスパスとして設定され、本来、切り替え後のストラクチャと いっしょに使用されるはずのJavaClassesフォルダのJavaファイルは、決してクラスパスとして設定されることはないのです。

この問題は、ストラクチャの切り替え前後で利用するJavaファイルを、すべて共通のJavaClassesフォルダに置くことで解決できます。 JavaClassesフォルダをストラクチャファイルがあるフォルダに設置するのではなく、アプリケーションファイル(4th Dimensionまたは4D Client)があるフォルダ、または4Dフォルダ(ACIフォルダ) に設置することで、すべてのストラクチャから共通に利用することができます。

Mac OS 8/9上では、Apple社のJManagerを利用してJavaバーチャルマシンを起動しているため、上記のような制約がありません。そのため、Mac OS 8/9上では、ストラクチャが切り替切えられる度に、Javaバーチャルマシンの初期化が行われます。
[2010.03.06 加筆]
現在のJWorld 6.0.0は、ストラクチャの切り替えに対応しています。ストラクチャを切り替えたとき、「JavaClasses」のクラスは、すべてアンロードされ、「JavaClasses」は、新しいものに切り替わります。

[JWorld] libJWorld.jnilibについて

RonriKoboフォルダにあるlibJWorld.jnilibは、プラグインJWorldが必要とするファイルであ り、Javaと4Dがコミュニケーションを行う際に必要になるライブラリです。このライブラリは、Mac OS X版だけに必要であり、Mac OS 8/9やWindowsでは、このライブラリが持つ機能は、プラグインファイルの中に内蔵されています。次のようなMac OS Xの特殊な事情のためにプラグインファイルの中に含めることができませんでした。

(1)4Dのプラグインファイルは、CFMという実行形式のファイルでなければならないのに対し、 libJWorld.jnilibは、Mach-Oという実行形式のファイルでなければならい。
(2)Mac OS Xでは、この種のライブラリは、特定のディレクトリ(カレントディレクトリ、または「/usr/lib」)に置かなければならない。

(2)の理由のため、JWorldのプラグインメソッドJWD Create java worldは、RonriKoboフォルダ内のlibJWorld.jnilibをカレントディレクトリにコピーしようとします。ところで、Mac OS Xで4Dを起動した際のカレントディレクトリはどこになっているのでしょうか。通常であれば、4D本体のアプリケーションがあるディレクトリか、開いてい るストラクチャファイルがあるディレクトリになっているところですが、現状のMac OS X版の4D(6.8〜6.8.3)では、ルートディレクトリ(/)がカレントディレクトリになっています。ルートディレクトリには、 (Administratorでない)通常ユーザはファイルを書き込むことができません。そのため、通常ユーザがJExternalやJbyJを装備した アプリケーションを起動しようとすると、-15901のエラーが発生します。通常ユーザでもJExternalやJbyJを装備したアプリケーションを使 用できるようにするためには、libJWorld.jnilibをあらかじめ「/usr/lib」にコピーしておきます。コピーは、Terminalから 次のように行います。

-- あらかじめlibJWorld.jnilibがあるRonriKoboフォルダに移動しておく
$ sudo cp libJWorld.jnilib /usr/lib
$ sudo chmod 555 /usr/lib/libJWorld.jnilib

常に4DをAdministrator(管理者)でしか使用しない場合でも、libJWorld.jnilibをあらかじ め「/usr/lib」にコピーしておけば、アプリケーション起動時のファイルコピーとアプリケーション終了時のファイル削除が必要なくなる分、パフォー マンスが向上します。

[2003.05.29 加筆]
JWorldバージョン3.0.3からは、 libJWorld.jnilib を/usr/libにコピーする必要はなくなりました。そのままRonriKoboフォルダに置いておくだけで、ライブラリとして機能するようになってい ます。

[JExternal] Javaコードのデバッグについて

JExternalは、4DからJavaのメソッドを実行することを可能にするプラグインです。通常はデバッグ済みの Javaメソッドを実行しますが、4Dからシームレスに(継ぎ目なく)デバッグすることも可能です。つまり4DからJavaのメソッドを呼び出したとき に、自動的にJavaデバッガ−に制御が移り、そのJavaメソッドが終了したら、また4Dに戻るようにすることができます。これにより開発効率を高める ことができます。

このためには、Metrowerks社のCodeWarrior Macintosh版を使用しなければなりません。他の開発環境やプラットホームでは今のところできません。ここではCodeWarrior6 Macintosh版の使用を前提としていますが、バージョン6以前のCodeWarriorでも可能です。

まず、CodeWarrior6 Reference CDのThrill SeekersフォルダにあるIMPORTANT(Mac Java Debug).txtという文書に目を通してください。以下はこの文書に書いてあることとほぼ同じことを行います。(CodeWarriorと4Dをいっ たん終了しておいてください。)

1)現在ハードディスクにインストールされているMetrowerks CodeWarrior 6.0:Metrowerks CodeWarrior:CodeWarrior Plugins:DebuggersフォルダにあるSunJavaPluginとMetroNub PluginとJavaSymbolicsを他のフォルダに退避する。

2)Reference CDのThrill Seekers:MetroNub Java Debugger:INTO Metrowerks CodeWarrior:INTO CodeWarrior Plugins:INTO DebuggersフォルダにあるMetroNub PluginとJavaSymbolicsを1)のフォルダにコピーする。

3)CodeWarriorで作成したJavaプロジェクトファイルを開き、ビルドし、結果として出力されたJarファイ ル(この中に4Dから呼び出したいメソッドがある)を4Dのストラクチャファイルと同じフォルダ内にあるJavaClassesフォルダに移動する。

4)CodeWarriorのファイルメニューの「開く...」で3)のJarファイルを開く。デバッガが起動するので、 適当な箇所にブレークポイント設定する。

5)4Dストラクチャファイルを開き、4Dを実行する。JEX Call class method または JEX Call object method が実行されるとCodeWarriorのデバッガに制御が移り、Javaコードがデバッグできる。

注意:5、6回デバッグしたら、一度CodeWarriorを終了してください。何度もデバッグしていると途中で CodeWarriorがクラッシュします。

[2007.11.08 加筆]
Metrowerks社は、CodeWarriorの開発/販売を中止しました。Apple社Xcodeを利用した効率のいい、JExternalのためのJavaコードの作成/デバッグを紹介したページを設けました。そちらをご覧ください。

[JExternal/JbyJ] 引数/結果値を増やす方法について

JExternalは、通常は最大21個の引数(配列を含む)をJavaメソッドに渡すことができ、Javaメソッドから 最大21個の結果値(配列を含む)を受けることができます。

JbyJも同様に、4Dから他の4Dのメソッドを呼ぶとき、またはJavaから4Dのメソッドを呼ぶとき、最大21個の引 数(配列を含む)を渡すことができ、最大21個の結果値(配列を含む)を受けることができます。

この最大21個という制限は、VAR#リソースを編集することで最大99個までに拡張することができます。なお、ここで紹 介する作業はすべてMacintosh上で行わなければなりません。

まず、ResEditでMac4DXフォルダにあるJWorld_XXX.4DXをオープンし、VAR#リソースを表示し てください。VAR#は、STR#と同じテンプレートでオープンすることができます。VAR#では引数や結果値を一時的に保存する変数名が宣言されていま す。

例えば、Boolen型の場合、JWD_P_V_B01:BからJWD_P_V_B21:Bまでの変数が宣言されています。これは通常4Dで
C_BOOLEAN(JWD_P_V_B01)
C_BOOLEAN(JWD_P_V_B02)
 .
 .
 .
C_BOOLEAN(JWD_P_V_B20)
C_BOOLEAN(JWD_P_V_B21)

と宣言するのと同じことです。ここに21個までの変数しかないために、上記のような制限があるのです。

21個以上の引数/結果値が必要になったら、JWD_P_V_B22:B、JWD_P_V_B23:B、 JWD_P_V_B24:B、.... と必要な数まで追加してください。ただし99個までしか追加してはいけません。この追加作業は、すべての変数型/ 配列型に同様に行わなければなりません。つまり、Boolen型変数を30個に拡張したら、Text型変数も30個、String配列も30個もに拡張し なければなりません。そうしなければ実行時にエラーが発生します。

ストラクチャファイルをコンパイルしていない場合は、上記の作業をしなくても引数/結果値を21個以上に拡張できますが、 コンパイルした場合は上記の作業をしない限り、未宣言の変数にアクセスすることになりエラーが発生します。

[2003.11.17 加筆]
JWorldバージョン3.1.0以降では、上記の作業を行うことなく、は じめから 仕様上の限度である99個までの引数/結果が利用できるように拡張されています。


 
Copyright (c) Ronri Kobo, Inc. All rights reserved.
support@ronri-kobo.com