I’m going to keep updating this when I make any progress. Today, I managed to manually patch the bundled java executable, making it run just fine. This uses the method that @gbi linked to in his first response.
I’m still looking into how I can make package this and make it easy to work with. Some thoughts are gathered at the end of the post, but they’re far from final.
Manual patching
Following this detailed StackExchange reply on patching binaries for NixOS, I managed to manually patch the Java executable that comes with the Enonic distribution.
Here are the steps I took (Enonic XP 7.6.1):
-
Find out which interpreter it’s using:
$ patchelf --print-interpreter ./java /lib64/ld-linux-x86-64.so.2
-
Find out where I can get this interpreter.
According to the stack exchange response, it’s available with
glibc
. However, it’s also provided by$NIX_CC
(presumably for convenience). In an expression, you should probably useglibc
, but when dirty patching like this,$NIX_CC
will have to do.$ cat $NIX_CC/nix-support/dynamic-linker /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib/ld-linux-x86-64.so.2
-
Set the interpreter
patchelf --set-interpreter (cat $NIX_CC/nix-support/dynamic-linker) ./java
-
Find out that it’s not able to load all required libraries.
When trying to run it with this interpreter, I’m told that:
$ ./java ./java: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
-
Use
ldd
to find out what libraries it can’t find$ ldd ./java linux-vdso.so.1 (0x00007ffc2ede1000) libz.so.1 => not found libpthread.so.0 => /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib/libpthread.so.0 (0x00007f261425b000) libjli.so => /home/thomas/.enonic/distributions/enonic-xp-linux-sdk-7.6.1/jdk/bin/./../lib/jli/libjli.so (0x00007f261404a000) libdl.so.2 => /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib/libdl.so.2 (0x00007f2614045000) libc.so.6 => /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib/libc.so.6 (0x00007f2613e86000) /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib/ld-linux-x86-64.so.2 => /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib64/ld-linux-x86-64.so.2 (0x00007f2614482000) libz.so.1 => not found
As it turns out, it can’t find
libz.so.1
-
Find out if I have this lib available in the store, and if so: where.
$ find /nix/store -name libz.so.1 /nix/store/rldppqna2kya26zpdrl7p1wlbz0jgvj3-zlib-1.2.11/lib/libz.so.1 /nix/store/3yglmszn58qwj3dw94b0z9iy18vxaa1w-zlib-1.2.11/lib/libz.so.1 /nix/store/s06clkz6r628iqzab3plng138dln85h0-zlib-1.2.11/lib/libz.so.1 /nix/store/7bgshg2z70fpcc7adxfag1lgf45yamxh-zlib-1.2.11/lib/libz.so.1 /nix/store/zkswvy1ya0nf5k6108av1zbyp2ns577v-zlib-1.2.11/lib/libz.so.1 /nix/store/1srmyg1a8cxqwd0hd24rj6kw4lqd61yq-zlib-1.2.11/lib/libz.so.1
As it turns out, I’ve got a bunch of copies of it. For a derivation, we’d probably specify
zlib
as a runtime dependency. For the dirty patch, though, we can use one of the above libs. -
Add the path to the found
libz.so.1
library to the executable’srpath
$ patchelf --set-rpath /nix/store/s06clkz6r628iqzab3plng138dln85h0-zlib-1.2.11/lib/:(patchelf --print-rpath ./java) ./java
At this point, the executable should work as expected.
Automatic patching + packaging
Of course, it would be swell if we could package it properly or at least provide an overlay that would take care of it, but that may require more thinking.
Based on the above, I’d probably need glibc
and zlip
as buildInputs
. For nativeBuildInputs
: autoPatchelfHook
and tar
. The distribution is available here https://repo.enonic.com/public/com/enonic/xp/enonic-xp-linux-sdk/7.6.1/ in both tar and zip formats. Either use unzip
or tar -xvf
.
This extracts the XP distribution. The path to the Java file to patch here would be: <distribution>/jdk/bin/java
. If autoPatchelfHook
is able to patch the Java executable on its own, that’s great. Otherwise: we might have to do it manually (using patchelf
), though I don’t know how that would work.
Now, the packaged app would end up in the Nix store, so we’d probably also want to create a symbolic link to the store directory from the expected ~/.enonic/distributions/enonic-xp-linux-sdk-x.y.z
directory.
For now, assuming Linux should be alright. Support macOS (Nix darwin) could be a stretch goal.
Based on the Stack Exchange answer, I think the derivation would look something like this (but this is very much not finished):
{ stdenv, unzip, glibc, zlib, autoPatchelfHook }:
let
version = "7.6.1";
url =
"https://repo.enonic.com/public/com/enonic/xp/enonic-xp-linux-sdk/${version}/enonic-xp-linux-sdk-7.6.1.tgz";
in stdenv.mkDerivation {
name = "enonic-xp-${version}";
inherit version;
src = fetchTarball {
sha256 = "0vmmqd9d4w0zis839wg62251vvvcd3jmvb3rg1p0bgcl3b2qy5dk";
inherit url;
};
nativeBuildInputs = [ autoPatchelfHook ];
buildInputs = [ glibc zlib ];
# add unpackPhase and installPhaase here
meta = with stdenv.lib; {
description = "Enonic XP distribution";
homepage = "https://enonic.com";
license = licenses.gplv3;
maintainers = with stdenv.lib.maintainers; [ ];
platforms = [ "x86_64-linux" ];
};
}