Archive

Posts Tagged ‘swig’

On Clojure, Swig, and the UnsatisfiedLinkError

September 16th, 2011 3 comments

This week I did some Clojure work with a swigged-up C++ library that works great from Java. I was surprised when things didn’t go as smoothly in Clojure. In particular, loading native libraries in the REPL doesn’t seem to work. I’m writing this down in case someone else has the same problem in hopes that it’ll save them an hour or two of head-scratching and library path fiddling.

So, to set the stage, let’s make a tiny Swig library, compile it and try using it from the REPL. I’m using Leiningen just to save some time:

    $ lein new swiggy
    $ cd swiggy
    $ cat >swiggy.i <<EOF
    > %module Swiggy
    > %{
    >   int get_something() { return 42; }
    > %}
    > int get_something();
    > EOF
    $ swig -java -package swiggy -outdir src/swiggy swiggy.i
    $ gcc -I$JAVA_HOME/include -L$JAVA_HOME/lib -shared swiggy_wrap.c -o libswiggy.dylib
    $ javac src/swiggy/Swiggy*.java
    $ export JAVA_OPTS="-Djava.library.path=. -verbose:jni"
    $ lein repl
    ... snipped tons of irrelevant -verbose:jni output ...
    user=> (System/loadLibrary "swiggy")
    nil
    user=> (swiggy.Swiggy/get_something)
    java.lang.UnsatisfiedLinkError: swiggy.SwiggyJNI.get_something()I (NO_SOURCE_FILE:0)

That’s interesting. libswiggy.dylib loaded happily and yet there’s an UnsatisfiedLinkError. The thing to note here is that it’s complaining about linking the get_something() method, not the library itself. That’s unexpected. Also note that I have the -verbose:jni flag set, but nothing was printed about linking the method to the backing native code in the library. hmmm.

So, I googled. And found a couple references to this problem without real solutions. Unfortunately, the usual reaction to this problem is immediately “Did you set LD_LIBRARY_PATH and java.library.path?” The exception is the same and that’s normally the problem in Java. It turns out that putting the loadLibrary() call within a Java class that’s loaded by Clojure is enough to trick the system into correctly linking the native method. That is, edit Swiggy.java something like this:

    ...
    public class Swiggy {
      // Explicitly load the library when this class loads
      static {
        System.loadLibrary("swiggy");
      }
      public static int get_something() {
        return SwiggyJNI.get_something();
      }
    }
    ...

then recompile and give it another try:

    $ javac src/swiggy/Swiggy*.java
    $ lein repl
    user=> (swiggy.Swiggy/get_something)
    [Dynamic-linking native method swiggy.SwiggyJNI.get_something ... JNI]
    42

That’s better. Does anyone know what causes this? Is it related to the classloader used by the repl or something?

If your in the situation where you can’t or don’t want to modify the swig interface file to include this change, all is not lost. Simply create your own dummy Java class with the loadLibrary call and reference it from Clojure. You can even use Leiningen’s :java-source-path property to get it to auto-compile it for you. I suppose gen-class should also work, but the Java’s pretty trivial.

Categories: clojure Tags: , , ,