.NETとJavaの相互運用
IKVM.NETをご存知でしょうか? 日記でも紹介したことがありますが、.NETランタイム上で動作するJavaVMです。以前見たときは、.NET上でJavaを動かしても何が嬉しいのかよく分かってませんでしたが、調べてみたところ結構面白いことが出来ることが分かりました。
※注意
IKVM.NETをダウンロード後、binディレクトリにPathを通し、また、開発ディレクトリに
これら2つのアセンブリをコピーしていることを前提に話を進めます。
・シナリオ1
あなたは.NETプログラマです。.NETに大変満足していますが、Javaの方が歴史があるため、多数の魅力的なライブラリがあることを羨ましく思っています。今日も、こんな魅力的なライブラリを見つけてしまい、欲しくてたまりません。
import java.io.*; public class FindFile { public static void find(String dir) { findSub(new File(dir)); } private static void findSub(File dir) { File[] files = dir.listFiles(); for (int i = 0; i < files.length; ++i) { if (files[i].isDirectory()) findSub(files[i]); else System.out.println(files[i].getName()); } } }
こんなもん、いらんとか言わないで。(^^; これをC#から呼び出してみましょう。上記ソースはコンパイルされ、FindFild.classになっているとします。
> ikvmc -target:library -reference:IKVM.GNU.Classpath.dll FileFind.class
このコマンドを実行するとjava bytecodeがcilへ変換されFileFind.dllが生成されます。FileFind.dllを呼び出すC#のコードを書きます。
public class Foo { public static void Main(string[] args) { if (args.Length > 0) { FindFile.find(args[0]); } } }
これを、Foo.csとして保存してコンパイルします。
> mcs /r:FindFile.dll,IKVM.GNU.Classpath.dll Foo.cs
これで、Foo.exeが完成です。ikvmcで変換したアセンブリをコンパイルするにはIKVM.GNU.Classpath.dllが必要になります。ちなみに、実行にはIKVM.Runtime.dllも必要なので注意です。で、
> Foo.exe c:\windows
とか実行すると、ディレクトリに存在するファイルが列挙されます。このように、.NET側からJavaを呼び出すことに成功しました。
・シナリオ2
Javaプログラマさんは面白くありません。.NET側から一方的にライブラリを利用されるだけです、腹いせに.NETライブラリを無駄に呼んでやろうとか黒い情念を燃やしています。で、yaneSDK4Csとかいうマイナーなライブラリに何故か目をつけました。どうやら、Javaから.NETを呼び出すには、ikvmstub.exeを使えば良いらしいです。
> ikvmstub mscorlib.dll
mscorlib.jarが生成され、.NETのコアライブラリは呼び出し放題です。
> ikvmstub IKVM.GNU.Classpath.dll
として、IKVM.GNU.Classpath.jarを作っておくと、.NET特有のboxing/unboxingのためのラッパークラスが使えます。準備が整ったので、いよいよyaneSDK4CS.dllを変換します。
> ikvmstub yaneSDK4CS.dll
では、変換したライブラリを呼び出してみます。
import ikvm.lang.*; import cli.y4cs.sdl.*; import cli.y4cs.aux.*; import cli.y4cs.math.*; import cli.y4cs.timer.*; import cli.y4cs.draw.*; public class Game { public static void main(String[] args) { Screen screen = new Screen(); screen.beginScreenTest(); screen.setVideoMode(640, 480, 0); screen.endScreenTest(); Surface bg = new Surface(); Surface sp = new Surface(); bg.load("bg.bmp"); sp.load("sp.bmp"); Color4ub key = new Color4ub( CIL.box_ubyte((byte)0), CIL.box_ubyte((byte)0), CIL.box_ubyte((byte)255), CIL.box_ubyte((byte)192) ); bg.blt(sp, 0, 0, key); Texture tx = new Texture(); tx.setSurface(bg); FpsTimer fpstimer = new FpsTimer(); fpstimer.setFps(60); while (GameFrame.pollEvent() == 0) { screen.clear(); screen.blt(tx, 0, 0); screen.update(); fpstimer.waitFrame(); } } }
ファイル名をGame.javaとして保存します。見てのとおり、変換したライブラリのパッケージはcli."C#での名前空間名"となります。では、こいつをコンパイルしましょう。
> javac -classpath mscorlib.jar;yaneSDK4Cs.jar;IKVM.GNU.Classpath.jar Game.java
これで、Game.classが出来ました。これで完成かと思いきや、実はこのまんま、JavaVMで実行することが出来ないのです。最初の例のように.NETアセンブリへ変換しなければなりません。
> ikvmc -reference:yaneSDK4Cs.dll:IKVM.GNU.Classpath.dll -target:exe Game.class
Javaプログラマとしては騙された気がしますが、一応、Javaでソースは書けたと無理矢理納得することに。(^^;
というわけで、.NET⇔Javaが出来ました。.NET←JavaがそのまんまJavaVMで実行できないのが残念ですけど、これは結構面白いんじゃないかと思います。