Rincanter allows one to access the R statistical programming language from Clojure. Rincanter also integrates R with Incanter for charting and more stats. Rincanter is based on rJava‘s JRI R-from-Java bridge. Getting this working required making a JNI library available to Clojure via an as-yet-undocumented Leiningen setting, :native-path.
R-Java Bridge Motivation
I have some statistical functions written in R which would be annoying to re-implement in Java or Clojure, mainly because they depend on R libraries that are already written and for which there are no readily apparent Java/Clojure equivalents (the augmented Dickey-Fuller test, if you’re interested.) So, naturally, I decided to look into embedding R into Java, somehow.
Rincanter: R from Clojure
Rincanter came up, and it looks perfect: not only does it embed R into the JVM (via rJava‘s JRI component), it provides a nice Clojure wrapper and it integrates it with Incanter, a Clojure-based statistics and charting package that I’ve been wanting to try.
rJava and JRI: Low level bridge
rJava is, incidentally, mainly intended for calling Java code from R, which is the opposite of what I want to do. It absorbed the JRI project, which allows one to call R from Java, into its source tree a while ago, but so far it appears to be a direct graft onto the source tree with little or no integration. Perfect, since I don’t need to use the Java-from-R stuff anyway. So I downloaded rJava and built only the JRI subdirectory.
Going by Rincanter’s installation instructions, I need two things from JRIL: a generic JAR for the system-independent Java parts and a platform-specific JNI, a Java Native Interface to the actual R implementation on the system. The build produced two important files (hidden in the src/ subdirectory), JRI.jar and libjri.jnilib. (The name of the latter will vary depending on your build platform; it will be a .so file on Linux, a .dll file on Windows, etc.) I stuck them in my Clojure project’s lib/ subdirectory, restarted Leiningen, and went to the REPL to see whether everything worked.
Glancing through the examples that came with JRI, I decided to try a “(.new org.rosuda.JRI.Rengine)“. This failed spectacularly, and crashed the JVM with a complaint about being unable to locate the JNI library.
Loading JNI libraries with Leiningen
Further investigation showed that just placing the JNI library on the classpath doesn’t work. JNI libraries apparently have a separate classpath-like construct stored in the JVM system property java.library.path. Mine was set to ".:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java" by default.
I don’t want to install the JRI library system-wide. The default inclusion of "." was curious, but I also don’t want to start dumping files into my project’s root directory. What I need is a way to set this system property. Of course, I could be crude and just hammer it in in one of my Clojure source files, but, as it’s analogous to setting up the classpath, it seems rather like something that Leiningen should be doing as part of its config-file based JVM startup procedure.
Good news: Leiningen got the ability to set java.library.path last December. It’s still not documented in the README, but the code was merged into the official release. Searching through the codebase, I found that the defproject argument :native-path sets up JNI’s java.library.path. I made myself a jni/ subdirectory, added :native-path "jni" to my project.clj, and it worked.
It did clobber the default java.library.path property completely, replacing it with my “jni/” argument rather than appending it. That’s OK for my case, since I’m not using any systemwide JNI libraries, but it is something to be aware of in case you are.
Update: Rincanter apparently does its own management of java.library.path and JNI library loading. The docs ask for the .jnilib to be installed into Rincanter itself. It’s still good to know about the Leiningen way.
Popularity: 17% [?]
If you like this post and would like to receive updates from this blog, please subscribe our feed.
