sbtでネイティブライブラリを使う時のメモ

2012/11/02追記

もはやうろ覚えなのですが、このエントリを書いた頃は確かsbt0.7が最新だったはずなので以下は超絶古い情報です。
もう今はsbt0.13が出そうな状況だというのに「sbt dll」とかでググると未だにこのエントリが割と上の方に出てきやがることに危機感を覚えたので追記しておきます。


This page has moved
scala - Integrating native system libraries with SBT - Stack Overflow
↑を読んだらいいと思います!!以上!!!

以下はsbt0.7の情報

ググってもほとんど情報が見つからなかったのでメモ。


プロジェクトのルートディレクトリにネイティブライブラリ(dll,so)を置いてしまうと、二度目以降のrun時に

> java.lang.UnsatisfiedLinkError: Native Library ***.dll already loaded in another classloader

と出て実行できなくなります。


sbtでは、アプリケーションは通常sbtと同じJVM上で実行される*1みたいです。sbtのソースを見るとrunする時に新しいクラスローダを作ってるので、1度目のrunでdllをロードした古いクラスローダが生き残ってて冒頭のエラーが出るのかな。ごめんなさい検証せずに適当書いてます。


これを回避するにはforkRunを使ってアプリケーションをsbtとは別のJVMで起動し、JVMオプションのjava.library.pathでdllの場所を指定してやればいいです。
ルートディレクトリ以外の適当な場所にディレクトリを作って、dllをぶちこみます。ここではlib/nativeにしておきましょう。
project/build/Project.scala のプロジェクト定義の中に以下を記述。

def nativeLibPath = System.getProperty("path.separator") + (path("lib") / "native" )

override def fork = forkRun(
  ("-Djava.library.path=" + System.getProperty("java.library.path") + nativeLibPath) :: Nil
)

もういくらrunrunしてもUnsatisfiedLinkErrorが出ることはありません。めでたい。
これに気づかずしばらくの間、一度runしたらいちいちsbtを起動し直すというあほなことを続けてました……


参考:
Google Code Archive - Long-term storage for Google Code Project Hosting.
Scala and Sbt getting started.