ClojureCLRあれこれ

## ClojureCLR
ClojureCLRは、windowsの.net環境向けに作られたClojure実行環境です。

現在は、Clojureのgithubアカウントに統合されて、開発が進んでいます。
https://github.com/clojure/clojure-clr/wiki

githubのコミット履歴を確認すると、jvm向けのコミットに対応したポートを作成しつつ、CLR独自の対応を進めていることが分かります。
最新版は、Clojure 1.5.1に対応してます。

また、徐々にですがMono環境への対応も進めています。
以下、Mono環境での話を進めていきます。

## 基本コマンド
REPLの実行は、`mono Clojure.Main.exe` です。 `java -cp clojure-1.5.1.jar clojure.main` にあたります。

コンパイルの実行は、`mono Clojure.Compile.exe` です。
hoge.clj ファイルから hoge.clj.dllファイルが作成されます。
nsにgen-classの指定がある場合は、exeファイル（.net環境の実行ファイル）が作成されます。

## ライブラリ
ライブラリが、clojureの関数のみに依存している場合は、そのまま利用できますが、
JVMに依存しているライブラリは置き換えが必要です。

### coreライブラリ
coreライブラリ中のclojure.javaネームスペースについては、clojure.clrに置き換えてあります。

- clojure.clr.io (clojure.java.io)
- clojure.clr.shell (clojure.java.shell)

### contributeライブラリ
clojure のgithubには、下記の8つが登録されています。

- clr.data.json
- clr.data.generators
- clr.test.generative
- clr.tools.nrepl
- clr.tools.namespace
- clr.tools.analyzer
- clr.tools.logging
- clr.tools.trace

contributeライブラリでは管理者が別になるため、同じネームスペースでは管理せずに、
java APIに依存したライブラリを移植して、clrを先頭に付けたライブラリを用意しています。

### その他

- cljclr.tools.cli (clojure.tools.cli)

contributeに登録されていないライブラリです。
ネームスペースは、現在のところclrではなくcljclrを使っているようです。

### nuget
nugetには、７つのパッケージが登録されています。
http://www.nuget.org/packages?q=clojureclr

- Clojure By: dmiller kocubinski aaronc
- ClojureClrEx By: kocubinski aaronc

- clojure.data.json By: dmiller
- clojure.tools.namespace By: dmiller
- clojure.data.generators By: dmiller
- clojure.test.generative By: dmiller
- cljclr.tools.cli By: rippinrobr

ClojureCLRをビルドするときにtest関連プロジェクトで必要なため、nugetで管理しています。

## lein-clr
Clojure.Main.exeは、Windowsのコマンドプロンプトを前提に設計されており、うまく使えない状況のため、MonoからREPLを操作するには、nrepl経由の操作が必要になります。

javaでleinプロジェクトを作成することになりますが、
手軽に試せるので、こちらを紹介して記事を終わりにしたいと思います。

### 事前準備
monoとleiningenは、別途用意してください。
OSXの場合、
monoは、XamarinStudioと一緒または、公式ページからMonoのRuntimeを入れることができます。
leiningenは、homebrewから`$ brew install leiningen`で、インストールできます。

### プロジェクト作成
プロジェクトを作成します。
`$ lein new lein-clr hello`
`$ cd hello`

### ClojureCLRのダウンロード
ダウンロードします。
`$ wget http://jaist.dl.sourceforge.net/project/clojureclr/clojure-clr-1.5.0-Release-4.0.zip`
`$ unzip clojure-clr-1.5.0-Release-4.0.zip`

### 設定
project.clj内で、CLJCLR14_40環境変数にClojureCLRが存在する前提になっているので、今回はそのまま設定します。
``$ export CLJCLR14_40 = `pwd`/Release``

### REPL実行
nrepl経由で、REPLを実行します。
`$ lein clr repl`

user=> \*clojure-version\*
{:major 1, :minor 5, :incremental 0, :qualifier ""}

となります。

### メイン関数実行
main関数を実行します。
`$ lein clr run -m hello.core x y z`
true
Received args: x y z

で、`src/hello/core.clj`のコマンドライン引数を表示する-main関数が実行されました。

### コンパイル
バイトコードにコンパイルします。
`$ lein clr compile :all`
Compiling hello.core to /Users/kyusa/Works/test/hello/target/clr/bin -- 122 milliseconds.
Compiling hello.core-test to /Users/kyusa/Works/test/hello/target/clr/bin -- 80 milliseconds.

### exeファイル作成
`src/hello/core.clj`に`(:gen-class)`を追加してコンパイルします。

```clj:src/hello/core.clj
(ns hello.core
  (:gen-class))
```

`$ lein clr compile :all`
Compiling hello.core to /Users/kyusa/Works/test/hello/target/clr/bin -- 149 milliseconds.
Compiling hello.core-test to /Users/kyusa/Works/test/hello/target/clr/bin -- 77 milliseconds.

`$ ls target/clr/bin`
hello.core.clj.dll       hello.core.exe           hello.core_test.clj.dll

今度は、exeファイルが作成されました。

### exeの実行
それでは、exeファイルを実行します。
`$ MONO_PATH=$CLJCLR14_40 mono target/clr/bin/hello.core.exe x y z`
Received args: x y z

monoで参照するdllファイル（アセンブリファイル）のパス(javaの-cpにあたります)は、MONO_PATH環境変数で指定できます。

参考サイト(MONO_PATH)
http://kakurasan.ehoh.net/summary/lib.exec.mono.html
http://www.mono-project.com/Best_Practices

### AOT
事前コンパイルして、起動時間を短縮できます。
`mono --aot Release/*.dll`
`mono --aot target/clr/bin/*.dll`

今回、エラーが出てしまい、うまくAOTコンパイル出来ませんでした。
下記は、別途用意したClojureCLRで確認した結果です。

AOT前
`$ MONO_PATH=$CLJCLR14_40 time mono target/clr/bin/hello.core.exe x y z`
Received args: x y z
        1.56 real         1.52 user         0.04 sys

AOT後
`$ MONO_PATH=$CLJCLR14_40 time mono target/clr/bin/hello.core.exe x y z`
Received args: x y z
        0.68 real         0.66 user         0.02 sys

JITおよびAOTの利点と欠点は、下記のサイトなどを参考にしてください。
http://www.ibm.com/developerworks/jp/java/library/j-rtj2/

### LLVMバックエンド
また、monoではVMにllvmが利用できますので試してみましょう。

OSXの場合、libmono-llvm.bundle(soのかたまり)ファイルを参照するため、LD_LIBRARY_PATH環境変数の指定が必要です。
`LD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib MONO_PATH=$CLJCLR14_40 time mono --llvm target/clr/bin/hello.core.exe x y z`
Received args: x y z
        5.69 real         5.63 user         0.04 sys

初期化の実行に時間がかかるため、単純な場合はあまり意味がありませんが、
科学計算などでは効果があるようです。

以上で終わりです。