Attempting to install the Minecraft launcher on NixOS

Today, I write about my attempts to install the Minecraft launcher on NixOS.

If you know me well enough and have read my previous posts on my blog, you’ll know that I’m a bit of a fan of Minecraft. And of course, in December 2018, Mojang released the new Minecraft launcher which is currently used to start the game. Unfortunately, for NixOS users, we do not have the luxury of using the new Minecraft launcher, as programs have to be downloaded via the Nix package manager.

Picture the scene. I’m sitting at my desk, admiring my new installation of NixOS and wonder to myself if it is capable of playing Minecraft (you know, considering it’s a game written in Java and “Java runs on all operating systems”). So, I run the command nix search minecraft to search for Minecraft and surprise surprise, I see the following output:

* nixpkgs.mcrcon (mcrcon-0.0.5)
  Minecraft console client with Bukkit coloring support.

* nixpkgs.minecraft (minecraft)
  A sandbox-building game

* nixpkgs.minecraft-server (minecraft-server)
  Minecraft Server

  ...

Aha! Minecraft! Just what I want! So I proceed through the regular procedure I go through to install new programs, which is to open my configuration.nix file, scroll to environment.systemPackages and add minecraft to the list of system packages. To my dismay, I discover that the Minecraft application that is included in the nixpkgs repository is not in fact, the glorious new updated Minecraft launcher. It is none other than the old, boring, bland Java based Minecraft launcher which unfortunately, did not even display its web-view element correctly.

Now, there is nothing wrong with the old, Java based launcher (as in, it works exactly as intended), but there’s something very satisfying with the crisp modern UI and the brief overview of the new release information and events which are shown in the new launcher.

The journey to get a new launcher (Attempt 1)

At this point in time, I feel it’s about time that NixOS has access to the new Minecraft launcher. I feel that doing so would bring a sense of contribution to the Nix community and they certainly can do with a new Minecraft launcher in their nixpkgs repository. Where do I begin? Well, firstly I need to get some sort of binary or “downloadable file” which I can use as a start to port over to NixOS. I go through the downloads page on Minecraft’s website until I find the list of downloads for different operating systems, under alternative downloads. From there, one download catches my attention. A downloadable .deb file for Debian/Ubuntu. It just so happens that the NixOS wiki has a page on packaging binaries, which includes a walked-through example of unpacking a .deb file and turning it into a Nix expression which can be used to install the program on NixOS.

So, I download the file and begin following the tutorial as laid out by the NixOS wiki. Extract the contents of the .deb file and run Nix’s patchelf command to tell the binary where the dynamic loader is located (because the regular ELF interpreter is stored in a different location on NixOS, meaning that running regular binaries are impossible without being patched). Everything goes as planned and I move onto the next step: linking the extra dynamic libraries to the binary.

I use the patchelf --print-needed command, as stated in the tutorial to find a list of libraries that are required by the binary in order to run. Now, this is the part where things get a little… complicated. I run the command and it shows this giant list of libraries which are required to run the Minecraft launcher. No problem there. The problem arises from having to find out which packages Nix keeps these libraries. I use none other than the “easy to remember” nix-locate -1 -w command to find the packages I want, one at a time, before realising that there’s a tool called “de-generate” which can find the packages I want for all of the libraries for me. Perfect! I go through the process of using this tool to find a list of packages and honestly, it looks like it just works. I use the Nix repl tool to generate a list of paths which indicates where the libraries are for the launcher and I patch the launcher file to include the new paths.

At this point in the tutorial, it states that you can just run the program (so, using ./minecraft-launcher) and everything should work. In fact, nowhere in the wiki page does it mention what to do if it doesn’t work. And of course, … it didn’t work. Instead, my shell complained that the library libcef.so was not found. When unpackaging the Minecraft launcher, I discovered that this specific library was included with the binary minecraft-launcher. Not a problem, all I have to do is add it to the library path! I add the path of the extracted package to the list of paths and run the ./minecraft-launcher command again. No dice. At this point, I’ve done all that I can and give up. There’s nothing I can possibly do. It’s over. I added the library to the path and it just doesn’t work. What else could I possibly do?

The journey to get a new launcher (Attempt 2)

So, a few months later I decide to work on this Nix derivation for the new Minecraft launcher again. No particular reason why - I just felt that there was probably something I missed. Perhaps using the de-generate tool was not the best thing to do and I should do it manually. So, one afternoon I head down to my university campus, meet up with some of my computer science peers and get to work on trying to successfully run the Minecraft launcher binary.

I grab a pen and paper and explain to them the situation and begin working on manually locating each and every package for each library. Surprisingly, this did not take that long and I soon realise that I’ve made it back to where I started - libcef.so could not be found. So I think to myself:

If I can’t find libcef.so, how do programs which use libcef.so find that library?

This train of thought leads me to discover a program called Brackets (It’s a code editor if you were wondering) which uses the command patchelf --set-rpath "${bracketsLibs}" $out/opt/brackets/lib/libcef.so in its “postFixup” stage of building the derivation for Nix. I take a good note of this and realise that because libcef.so is also an executable file, it too needs to be patched! By patching this file, I manage to overcome the first of many obstacles that stood in my way of installing the new Minecraft launcher on NixOS.

Despite making great progress and achieving a task which caused me to give up the first time, I begin debugging the other error messages which occur when running the ./minecraft-launcher command.

For some totally bizarre reason, a library called libcurl could not be found. No problem, I search for the library using nix-locate and, I add curl to the list of library dependencies and rebuild the Nix derivation. Again, upon running the launcher, the same error appears - libcurl cannot be found. Okay… a little strange, but there is an alternative library called curlFull which I could install, so I try using that one instead (my train of thought being that maybe curl on its own doesn’t have all of the capabilities that this Minecraft launcher needs?). Once again, libcurl cannot be found. At this point, I’m ready to give up again. I tell my friends that all hope is lost and we decide to call it a night and head off for some dinner while I think about the problem.

The journey to get a new launcher (Attempt 3)

I arrive back home, completely defeated as a whole day (afternoon) had been used up trying to get this launcher working and it was still in a dead state. I turn on my main desktop and find some C/C++ decompiler called Snowman and run it on the minecraft-launcher executable. Despite taking its time, it produces a pretty helpful result which informs me of something I had never thought of.

The Minecraft launcher doesn’t state that it needs libcurl in its dependencies… yet it still uses it. It also came to my attention that by default, Nix will try to optimise dependencies and remove non-required dependencies after patching a file. See the problem? Nix was removing libcurl from the dependencies because the Minecraft launcher doesn’t state that it needs it, although it does! By adding the line dontPatchELF = true; to my Nix build script (default.nix), Minecraft manages to start without the libcurl error. I continue working through the other errors, which seems to include something to do with the Chrome sandbox.

I discover that the Minecraft launcher comes packaged with a Chrome sandbox executable which is used to open Chrome (Google Chrome) without a window so its processing power can be used by other programs. This program also causes many issues to arise, such as messed up sound (multiple instances of AudioManager), hardware acceleration issues and of course, a straight up segfault.

After what seems like days of debugging and running the program through valgrind (A memory checker for C/C++ programs which I discovered at university), I manage to patch the issues bit by bit. By installing libglvnd, I am able to fix the warning message of hardware acceleration issues for the chrome sandbox. I also ensure that the chrome sandbox is properly patched by setting the dynamic loader.

I discover more errors, in particular, one which produces the following error message: Invalid node channel message. I do my research online to find many many posts about this issue. Some people saying it’s due to fonts, so I ensure that I include a bunch of fonts in my build script. This doesn’t make any progress, so I do a good day’s worth of research and by using valgrind, I add the glibc library which I believe resolves the issue. (Maybe it doesn’t. I can’t quite remember).

Admitting defeat

After absolutely everything I have thrown at this Nix derivation for the new Minecraft launcher, I give up. I made it to a point where running the ./minecraft-launcher command causes a segfault and no ideas in how to fix it.

Of course, I run the program through valgrind which produces a result which seems to reflect on the issue:

... (Omitted lines)

==23084== Process terminating with default action of signal 11 (SIGSEGV)
==23084==  Bad permissions for mapped region at address 0x1036
==23084==    at 0x1036: ???
==23084==    by 0x4006EA7: open_verify.constprop.7 (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x40075E5: open_path (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x4008985: _dl_map_object (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x400CF81: openaux (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x401938A: _dl_catch_exception (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x400D1CA: _dl_map_object_deps (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x4003C4F: dl_main (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x40184F8: _dl_sysdep_start (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x40020A9: _dl_start (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)
==23084==    by 0x4001207: ??? (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-2.27.so)

I try adding the glibc library to the path and that does not improve the situation. I stare at the rest of the error message produced by valgrind to find that there’s some “Jump to the invalid address 0x1036” and some SIGINT error here or there… something about an open operation or something… Running valgrind again produces a different error:

==32334== Process terminating with default action of signal 11 (SIGSEGV)
==32334==  Access not within mapped region at address 0x0
==32334==    at 0x5135DF: ??? (in /nix/store/1klpzcib8qindyv3ggl8jhvhb695ydmf-minecraft-launcher-2.1.2482/opt/minecraft-launcher/minecraft-launcher)
==32334==    by 0x4B2B46: ??? (in /nix/store/1klpzcib8qindyv3ggl8jhvhb695ydmf-minecraft-launcher-2.1.2482/opt/minecraft-launcher/minecraft-launcher)
==32334==    by 0x4375EC: ??? (in /nix/store/1klpzcib8qindyv3ggl8jhvhb695ydmf-minecraft-launcher-2.1.2482/opt/minecraft-launcher/minecraft-launcher)
==32334==    by 0xD0DEB8D: (below main) (in /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/libc-2.27.so)

The point is, I don’t know. This is outside of my “area of expertise”. I don’t know much about C or C++ and the Minecraft launcher is unfortunately compiled. There’s not much I can possibly think of that can resolve this issue.

And although it ends on a bit of a sad note, that’s where things end I guess. I gave up and wasn’t able to resolve the issue of the segfault for the Minecraft launcher on NixOS.

Written on June 1, 2019