Posted 2015-07-20 13:50:09 GMT

Allegro CLでは、結構前からjLinkerという機能がありCommon LispとJavaが連携できたりしましたが、LispWorksは最新の7から連携機能が付いたようです。

普段Javaを呼んだりすることはあまりありませんが、折角なのでどんなものか試してみることにしました。

下準備

LispWorks Java interfaceを利用するには、Linuxの場合、 libjvm.so が利用できるようになっている必要があるようです。

LD_LIBRARY_PATH で設定するか、 ldconfig で設定することになるかと思います。

64bit Debian GNU/Linuxでは、下記のパスを登録すればよいようでした。

/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/

LispWorksへパッチの適用

このJava連携機能ですが、ファイルの同梱漏れがあったようで、 lispcalls.jar をサイトからダウンロードして適切な場所に設置する必があります。

(2015-07-20日現在、最新のインストーラからインストールを実行しても lispcalls.jar は導入されません。)

Javaを呼んでみる

利用にはモジュールをロードして初期化という流れのようです。 下記は、joda-timeとicuを呼んでみている例と、入門サイトのちょっとした例を書き換えてみた例です。

require "java-interface" (lw-ji:init-java-interface :jvm-library-path T :java-class-path '("/var/tmp/joda-time-2.8.1/joda-time-2.8.1.jar" "/usr/share/java/com.ibm.icu-4.2.1.1.jar")) (lw-ji:import-java-class-definitions "org.joda.time.DateTime") (lw-ji:import-java-class-definitions "com.ibm.icu.text.Normalizer") (let ((date (|org.joda.time|:datetime.new))) (list (|org.joda.time|:datetime.getyear date) (|org.joda.time|:datetime.getmonthofyear date) (|org.joda.time|:datetime.getdayofmonth date) (|org.joda.time|:datetime.gethourofday date) (|org.joda.time|:datetime.getminuteofhour date) (|org.joda.time|:datetime.getsecondofminute date))) (defun normalize-string (s) (|com.ibm.icu.text|:normalizer.normalize s (lw-ji:read-java-field "com.ibm.icu.text.Normalizer.NFKC"))) (normalize-string "ＡＢＣＤＥＦＧ１２３４５アイウエオABCDEFG12345ｱｲｳｴｵ")

なお、 lw-ji:write-java-class-definitions-to-file を使うとJavaのクラス定義が書き出せて、後でこのファイルをロードすることで lw-ji:import-java-class-definitions の手間を省くことも可能なようです。

(lw-ji:write-java-class-definitions-to-file "org.joda.time.DateTime" "/tmp/joda-datetime.lisp") (lw-ji:write-java-class-definitions-to-file "com.ibm.icu.text.Normalizer" "/tmp/icu.lisp") (load (compile-file "/tmp/icu.lisp)") ...

macrolet ( &rest classes ) ` mapcar lambda ( c ) ` ( lw-ji:import-java-class-definitions ,c ) classes progn ,@ jimport ( jimport "java.io.File" "java.io.FileWriter" "java.io.BufferedWriter" "java.io.PrintWriter" "java.io.IOException" ) (defun check-before-wite-file (file) (and (|java.io|:file.exists file) (|java.io|:file.canwrite file))) (let* ((filename "/tmp/text.txt") (file (|java.io|:file.new filename))) (if (check-before-wite-file file) (let ((pw (|java.io|:printwriter.new (|java.io|:bufferedwriter.new (|java.io|:filewriter.new file))))) (unwind-protect (flet ((output (msg) (|java.io|:printwriter.println pw msg))) (output "今日の最高気温は") (output 10) (output "度です")) (|java.io|:printwriter.close pw))) (error "ファイルに書き込めません")) (hcl:file-string filename :external-format :utf-8))

まとめ

Javaが呼べるCommon Lisp処理系というと、Allegro CLのjLinkerの他にJVMを利用した処理系であるABCLがあります。

API的には、jLinkerとABCLは似ている所がありますが、LispWorks Java Interfaceは、これらとはちょっと違った雰囲気になっているようです。

■

