Marrying NixOS to libgdx

plapadoo
plapadoo
Published in
3 min readNov 4, 2017

Some of us at plapadoo decided to use NixOS as their Linux distribution of choice. This comes with many advantages, but when it comes to software that uses any kind of precompiled binaries, you usually have to go the extra mile. This post is about libgdx, a game engine which we use for one of our projects.

The Problem

libgdx uses binaries in (at least) three different places:

  1. It uses lwjgl as backend library for the graphics part.
  2. It uses OpenAL to access the sound card.
  3. It also has its own libraries to do some OS-specific stuff.

But libgdx is a Java library, so assuming you can start the application using java -jar myprogram.jar, how does the Java code find the native code, and how does it load it? It turns out that libgdx takes an unusual route:

  • It searches in the class path for a jar file that contains the native files (on Linux, .so files)
  • The contents of this jar file are extracted to a directory below /tmp, containing the user name and the CRC hash of the jar file (for example, /tmp/libgdxphilipp-c1f3d4.
  • The file(s) in this directory are loaded via a Java call to System.load().

With NixOS, this is suboptimal, because the binaries have hard-coded paths to the linker and, in case of lwjgl, X libraries. So this fails, with no good indication about what’s wrong.

Solution(s)

To solve this, we could patch the precompiled binaries to “un-hard-code” the binary paths. But a better solution is to write Nix derivations to compile lwjgl, as well as gdx itself (they are open-source, after all!). Writing these derivations is pretty easy, since all the required dependencies are already contained in nixpkgs. You can find the results in our gdx overlay. Using these, we can, for example, enter a nix shell, causing the libraries to be built.

Secondly, we need to tell gdx to not use its own extract-and-load logic and do it ourselves. I’ll describe this for libgdx. lwjgl and OpenAL are handled just the same. To locate gdx in the nix store, we use the following command:

nix-build --no-out-link '<nixpkgs>' -A gdx

This path, plus the name of the library, gets us the absolute library location. Teaching libgdx to load it from there involves just one line of Java scalpelling:

System.load(nixosPath+"/lib/libgdx.so");SharedLibraryLoader.setLoaded("gdx");

As you might have guessed, the last line instructs gdx to assume the library is already loaded. This code has to be called at the top of your main function.

Caveats and afterword

In our Java project, we actually call the nix-build command above, using the Java process API. This is certainly not great, since NixOS’ syntax or event its command structure might change. Also, the custom loading code is only necessary on NixOS, not on other distributions. We currently use a command line parameter to enable it.

This isn’t terribly complicated, but if anyone has an easier solution or suggestions, please comment.

--

--