Loading JNI

271 views
Skip to first unread message

ax2groin

unread,
Dec 31, 2010, 5:39:22 PM12/31/10
to Clojure
I'm having trouble formulating a method to load JNI libraries into
System. I'm just getting started, so this is a newbie question.

I want something like this:

(defn get-jni-path
"Derive the path to DLLs from environmental variables"
[]
(let [path (System/getenv "APP_CONFIG_DIR")]
(str (.substring path 0 (- (.length path) (.length "Config")))
"bin/")))

(defn load-jni
"Load the required libraries into the System so that the JNI works."
[]
(let [paths (map #(str (get-jni-path) %) ["coms.dll", "sqlite.dll",
"utils.dll", "zlib.dll"])]
(doto System
(load paths))))


But obviously I cannot handle the "paths" like this. I'm sure it's a
simple answer, but I'm missing it.

Thanx,
msd

dysinger

unread,
Dec 31, 2010, 8:14:11 PM12/31/10
to Clojure
Msd,

something like this

java -Djava.library.path=/usr/local/lib -cp clojure-1.2.0.jar:src
clojure.main

or in lein add

:native-path "/usr/local/lib:/usr/lib"

to your project def

then you should be able to make the JNI/JNA calls

ax2groin

unread,
Jan 3, 2011, 2:22:55 PM1/3/11
to Clojure
Hmm, I see that the final draft of my question missed an essential
element, I am using Eclipse.

In any case, I've tried something really basic, and it fails:

(try (System/load "C:\\app/bin/coms.dll") (println "Native code
library failed to load."))

The file is there (I checked with an exists() call). Maybe this is an
eclipse problem, but I can do the same call in Java (in Eclipse) and
have no issues.

.Bill Smith

unread,
Jan 3, 2011, 2:53:43 PM1/3/11
to clo...@googlegroups.com
Question about your really basic example: it looks as if it will print "Native code library failed to load" if System/load succeeds, and otherwise will print nothing at all.  Is that what you intended?

ax2groin

unread,
Jan 3, 2011, 5:54:01 PM1/3/11
to Clojure
Of course not. I mentioned I'm new at this, right?

It seems I was doing that part right before. I'm getting
InvocationTargetException and NoClassDefFoundError, so I tried to work
my way from the start to see if I was missing something (which I
thought was a valid assumption, if exceptions were being swallowed).
My first instinct was that it wasn't loading the libraries correctly.

Or course, I'm still stuck. It clearly sees the classes, because my
import statements aren't throwing ClassNotFoundExceptions. The
exceptions I'm getting are bubbling up out of the JNI, apparently, but
I don't have any idea why. At this point I have ugly looking Clojure
code that looks as Java-like as possible, so that I'm doing the exact
same thing in the exact same order as I do in a Java example, but I
get exceptions when I do it in Clojure.

So, when I get to
(def my-client (Client.))
it throws. BTW, Java equivalent ... Client myClient = new Client();

It feels like something is fundamentally different in a way I cannot
conceive, like Java automatically handles something behind the scenes
and I don't realize it.

Thanks.

.Bill Smith

unread,
Jan 3, 2011, 9:24:20 PM1/3/11
to clo...@googlegroups.com
As far as I know, Clojure doesn't talk straight JNI.  In other words, there isn't a Clojure equivalent to the "native" keyword in Java.  (If I'm mistaken about that, someone please speak up.)

Nonetheless, Clojure *can* use native libraries.  Your Clojure code can interact with a Java wrapper that loads a native library and declares native methods.  There's also JNA; if you Google for Clojure and JNA, you'll find examples/instructions.

Bill Smith

Bill Robertson

unread,
Jan 3, 2011, 9:30:32 PM1/3/11
to Clojure
I would suggest working through simple a example in just java, just so
you can figure out how to get your dlls loaded and then calling them.
Once you work out the configuration/setup kinks I would add clojure on
top of that.

I would also suggest you use jna instead of straight up jni. If it
fits your use-case it ought to take a lot of the hassle out.

Good luck.

ax2groin

unread,
Jan 4, 2011, 12:33:18 PM1/4/11
to Clojure
Thanks for the suggestions. I'll look at the JNA soon to see if that
fits. But I already have working examples of Java code which uses the
JNI wrapper classes (generated by swig - by someone else). I'm not
making direct JNI calls myself, but trying to instantiate the Java
classes that are a part of this generated library. That's my confusion
and frustration, because seemingly identical code works in Java, but
doesn't work for me in Clojure ... either in Eclipse or from a command-
line, actually.

George Jahad

unread,
Jan 5, 2011, 12:01:11 AM1/5/11
to Clojure

> At this point I have ugly looking Clojure code that looks as
>Java-like as possible, so that I'm doing the exact same thing in the
>exact same order as I do in a Java example, but I get exceptions when
>I do it in Clojure.

if they are short enough, post both the working java and broken
clojure versions. i'm bet someone on this list will spot your
problem.

ax2groin

unread,
Jan 6, 2011, 8:01:44 PM1/6/11
to Clojure
Sorry for the late response, but I haven't had time to play with
things in a couple days.

First discovery is that I probably cannot use the library path
variable, because some of the DLLs have to be loaded in a specific
order. Specifically, there is a "clientswig.dll" that has to be loaded
last. Going back to the old style of loading them manually inside the
Clojure code, I still have a problem, though.

The problem now seems to be with the JAR file that I need to be using.
I get a NoClassDefFoundError on a class within the JAR: "Could not
initialize class ...ClientModuleJNI".

I have included the JAR in the build path as I traditionally would in
Eclipse (Properties -> Java Build Path -> Libraries -> Add JARs). I've
also tried launching from the command line and get the same error.

I've mangled the code below to hide company-specific information, but
this is what I'm doing right now.

--- In Clojure ---

(ns app)

(def path "C:\\SVN\\lib3rdParty\\")
(try (System/load (str path "client.dll")) (catch UnsatisfiedLinkError
e (println "Failed library load.")))
(try (System/load (str path "utils.dll")) (catch UnsatisfiedLinkError
e (println "Failed library load.")))
(try (System/load (str path "clientswig.dll")) (catch
UnsatisfiedLinkError e (println "Failed library load.")))

(import '(com.app Client ClientSession))

(def my-client (Client.))

--- In Java ---

public final class AlertClient extends Client {

// Load the JNI
static {
try {
path = "C:\\SVN\\lib3rdParty\\";
String[] libraries = { "client.dll", "utils.dll",
"csclientswig.dll" };
for (int i = 0; i < libraries.length; ++i) {
String libPath = path + libraries[i];
System.load(libPath);
}
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n"
+ e);
System.exit(1);
}
}

public AlertClient() throws Exception {
super();
}
}
Reply all
Reply to author
Forward
0 new messages