How To Use LWJGL From Clojure
February 16, 2013 — 3 minutes long
I recently decided to try my hand at 3D programming in Clojure, and I settled on trying out LWGJL. Unfortunately, accessing its API takes a bit more than adding dependencies to
project.clj, and after an hour of fiddling and searching I wanted to share my solution so that others might benefit.
- Download the stable release of LWJGL and copy the files from
native/within your project.
native/to the JVM’s library path.
First, The LWJGL Library
The first step, actually, is to update
lwjgl from Central. First we need to put
[org.lwjgl.lwjgl/lwjgl "2.8.5"] inside
:dependencies. If you’re starting a new Leiningen project,
project.clj might look something like this:
(defproject my-project "0.1.0-SNAPSHOT" ; ... :dependencies [[org.clojure/clojure "1.4.0"] [org.lwjgl.lwjgl/lwjgl "2.8.5"]])
You’ll probably want to find out what the current stable version is, and then replace
"2.8.5" with that.
Adding this satisfies the library portion of LWJGL, but if we were to stop here, we would probably end up with an error like
UnsatisfiedLinkError no lwjgl in java.library.path when trying to import LWJGL classes from Clojure.
Second, Native Extensions
LWJGL comes with several native extensions for Mac, Linux, and Windows, and it needs those available when running on the respective OS. For some reason, those files do not come with the download from Central and need to be “installed” by hand.
First we’ll create a directory at the top level of our project to hold the extensions. We can name it
native/, or whatever. The only important thing is that we remember that name so we can tell
java about it in a moment.
Go to the LWJGL downloads page and download the latest stable zip file. Extract the contents and copy every file within the
native/<my-OS> directory into our project’s
native/ directory. It’s important that the files are directly under
native/ and not in subdirectories, because
java won’t look inside those.
Third, Changing The JVM’s Library Path
project.clj file allows for a
:jvm-opts key-pair that that is used to set
java’s command-line flags. Here we need to tell the JVM to look inside the directory where our native extensions are located. In my case, I used
native/, so you can see that I told it about that. I also used Clojure’s
str to concatenate my custom library path to the beginning of the existing path. The new
project.clj looks something like this:
(defproject my-project "0.1.0-SNAPSHOT" ; ... :dependencies [[org.clojure/clojure "1.4.0"] [org.lwjgl.lwjgl/lwjgl "2.8.5"]]) :jvm-opts [~(str "-Djava.library.path=native/:" (System/getProperty "java.library.path"))])
Once this is completed, you should be able to
import away without issue.