10
votes

On a 64-bit JVM, in Linux, whatever does the native library loading insists on trying to load the 32-bit library.

I'm asking this as a clojure and (even moreso) java n00b.

The answers I've found so far (Using lwjgl in Leiningen/Clojure seems to be the most prominent in search results) seem to be for older versions of lein, with issues swirling around the :native-dependencies or LD_LIBRARY_PATH in project.clj.

I'm re-inventing the wheel and translating the basic jME tutorials into clojure as a little personal homework assignment toward learning them both. In all the tutorials and examples I've found so far of people showing how they did this, this part seems to "just work."

(It worked fine for me under Windows, for that matter).

I'm using lein to build a new, empty project. I've set up dependencies on various versions of the jMonkeyEngine libraries on clojars. After 'lein deps', liblwjgl64.so and libopenal64.so wind up in the root of my project directory.

When I try to 'lein run', it shows the monkey splash screen for the settings, then it throws an exception when it tries to actually run because it's trying to load liblwjgl.so.

That file is present under target/native/linux and target/native/linux64 (though, oddly enough, not under target/native/linux32).

If I copy the file it wants into my project's root, the error changes to "wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)" which is the other set of discussions that google keeps giving me. The solutions mentioned there all seem to amount to "Switch to a 32-bit JVM to get Minecraft working", but I'd much rather get an actual clue about what's going on.

This problem is very consistent across every set of dependency libraries I could get my hands on in clojars (back to version 2, anyway...those had bigger issues that didn't seem to be worth digging into). The charles-stain set "Just Worked" for me on windows.

The best hypothesis I've been able to come up with so far runs something along these lines:

I suspect that a version must get specified at some point. http://docs.oracle.com/javase/7/docs/technotes/guides/javaws/developersguide/syntax.html#resources mentions a resources property that looks like a perfect fit, but this doesn't seem to have anything to do with JNLP. I'm wondering if there's a manifest file sitting around somewhere in a .jar that I haven't been able to find (here's where my n00bishness comes into play...I don't really have a clue what I'm looking for).

So, does anyone have any pointers about where I should look or who I should ask? I don't know enough to even know where to go from here. Would it make more sense to pester the jMonkeyEngine forums, #clojure, or the lwjgl mailing list (or whatever they use...I haven't actually looked into their side of things at all...should I?)

The next thing I'm going to try is bundling up the jME libraries into my own repository. That seems like a big, daunting enough task that I decided to ask on here while I'm tackling that angle.

I know this is vague, and I apologize for that. My google-fu has failed me. I'd appreciate any suggestions anyone can come up with.

Thanks in advance!

3

3 Answers

1
votes

I know this is an old question, but I found it upon deciding to work on a Clojure + jMonkeyEngine project. I spent some time fighting with the packages in clojars, then looking into what it would take to build my own maven package, and I found a page on the jMonkeyEngine wiki that had this stern warning:

Note that using jME3 with maven is neither recommended nor supported by the core jME team and the libraries in the maven repository might be outdated!

Later I found that I was able to successfully get a minimal JME app running by putting their jars directly in my project, and including them on the classpath using leiningen's :resource-paths config.

Find the jars by downloading the JME3 SDK, and looking in jmonkeyplatform/jmonkeyplatform/libs. Copy all of the jars into a "lib" folder inside of your project (yes you can remove the jars you won't use). Then configure your lein project like so:

(defproject my-jme-project "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.5.1"]]
  :resource-paths ["resources" "lib/*"])

Run lein-repl, and the following should launch a minimal JME3 app:

(import 'com.jme3.app.SimpleApplication)
(def app (proxy [SimpleApplication] [] (simpleInitApp [] nil)))
(.start app)
0
votes

Using native libraries with Java programs can be a pain at first, but it is not so very complicated in fact.

First of all, your error, wrong ELF class: ELFCLASS32 means that certain 64-bit program tried to load 32-bit shared library. This happens, obviously, when there is 32-bit library with the required name is present on the path where the program looks for the libraries, but the program itself is 64-bit. That's pretty much all for the explanation of the error.

Now, about the main part of the question. There are indeed several ways to use native libraries with Java applications, some of them involving even environment variables. But IMO the most easiest way is to specify Java system property java.library.path, which is intended exactly for managing native libraries. This property should point to the directory where all native libraries for the program are present. JVM will look into that directory for all required shared objects.

When you run JAR files directly, it is possible to specify system properties in command line, like this:

java -Djava.library.path=natives/linux64 -jar yourprogram.jar

Here, we're specifying a path to the libraries relative to the current directory. As far as I concerned, this is a preferred way to set properties for standalone applications, which usually started by scripts.

As for REPL, it seems it is possible to set JVM options for it inside project.clj, like this:

(defproject project "version"
  ...
  :jvm-opts ["-Djava.library.path=target/natives/linux64"])

I don't remember what is default working directory for the REPL, so this may need a little experimenting with the exact path, but you've got the point.

Right now I'm developing lwjgl program myself (though not in Clojure but in plain Java, using Maven), and all what was really required is extract native libraries from jars (maven-native-plugin does this) and set java.library.path for them.

BTW, it looks like that leiningen supports another important option in project.clj, :native-path, which seems to enable something like maven-native-plugin functionality: it specifies a directory to which all native dependencies should be extracted. Combining this with :jvm-opts should give you correct platform-independent REPL :)

0
votes

Still old question, but I got same problem, so I was able to setup jME3 on Closure by adding jCenter repository on project.cljfile:

(defproject example-project "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :repositories [["jcenter" "http://jcenter.bintray.com"]]
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [org.jmonkeyengine/jme3-core "3.1.0-beta1"]
                 [org.jmonkeyengine/jme3-desktop "3.1.0-beta1"]
                 [org.jmonkeyengine/jme3-lwjgl "3.1.0-beta1"]])