You have 2 options:

  • Package the missing app yourself and contribute it back to upstream.
  • Give up and just use Nix, the language package manager or just use guix shell and patchelf your way through.

Option 1 is fairly involved, depending on how big the dependency tree of your app is you’re probably not going to want to do this even if you manage to package the app and want to contribute it back you’ll have to get used to the mail workflow, how to use git send-email, patch guidelines… not that it’s particularly hard but if you’re just getting started I highly recommend taking it slow and contribute only once you feel comfortable.

We’ll explore option 2 in this post:

Use nix

Nix is the alternative to Guix if you want to keep using a functional package manager it has been around for a quite a while and the community is a bit bigger, there is also much more packages to choose from.

Just drop this snippet in your configuration.scm:

(service nix-service-type)

And then you can use the usual nix command to install stuff:

nix search nixpkgs#burpsuite
nix profile install nipkgs#burpsuite

I’ll leave you with my config for nix:

Here is my ~/.config/nix/nix.conf

experimental-features = nix-command flakes

The channels that I use

https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
https://nixos.org/channels/nixpkgs-unstable nixpkgs
https://tadfisher.github.io/android-nixpkgs android-nixpkgs

And my ~/.config/nixpkgs/config.nix file

  {
  allowUnfree = true;
  packageOverrides = pkgs: with pkgs; {
    myPackages = pkgs.buildEnv {
      name = "myPackages";
      paths = [
      scrcpy
      deno
      nodejs
      apktool
      ];
    };
  };
}

Finally you might encounter a weird little bug when you try to launch a nix command, it complains about a pseudo tty missing or something, there is an issue for that on https://issues.guix.gnu.org/ but basically you just have to restart the nix daemon.

sudo herd restart nix-daemon

Use your language package manager

Not much to say here, once you installed say python with guix you can just use pip to install apps not yet packaged in guix.

You might need to change your PATH to ~/.local/bin or wherever your language package manager is storing its binaries but that should be all.

Use Guix shell

If the app that you want is not packaged in Guix,Nix or a language package manager and you just have a binary to work with you’ll have to use ldd and patchelf the headers of that binary to make it work.

I’ll take the TextSynth server from Fabrice Bellard as an example, once you downloaded the ts_zip you’ll have multiple binaries to work with.

If you try to launch them directly it’s going to complain about a file not being there:

-bash: ./ts_sd: Aucun fichier ou dossier de ce type

But what this really means is that the binary complains about missing libraries, to found out which one you’ll have to use ldd, a tool that comes with glibc:lib on guix:

guix shell --check --pure --expression='(list (@@ (gnu packages gcc) gcc) "lib")' coreutils bash grep sed gcc-toolchain patchelf

Then run:

ldd ts_sd

# it yields something like
user@linux ~/Downloads/ts_server_free-2024-01-20 [env]$ ldd ts_sd
      linux-vdso.so.1 (0x00007ffe1655e000)
      libnc.so => /home/user/Downloads/ts_server_free-2024-01-20/./libnc.so (0x00007f1024a00000)
      libjpeg.so.62 => not found
      libm.so.6 => /gnu/store/ln6hxqjvz6m9gdd9s97pivlqck7hzs99-glibc-2.35/lib/libm.so.6 (0x00007f1024d3a000)
      libpthread.so.0 => /gnu/store/ln6hxqjvz6m9gdd9s97pivlqck7hzs99-glibc-2.35/lib/libpthread.so.0 (0x00007f1024d35000)
      libc.so.6 => /gnu/store/ln6hxqjvz6m9gdd9s97pivlqck7hzs99-glibc-2.35/lib/libc.so.6 (0x00007f1024804000)
      libdl.so.2 => /gnu/store/ln6hxqjvz6m9gdd9s97pivlqck7hzs99-glibc-2.35/lib/libdl.so.2 (0x00007f1024d2e000)
      /lib64/ld-linux-x86-64.so.2 => /gnu/store/ln6hxqjvz6m9gdd9s97pivlqck7hzs99-glibc-2.35/lib/ld-linux-x86-64.so.2 (0x00007f1024e19000)

So we know that libjpeg is missing, we use a guix search libjpeg command to see if it’s packaged in guix, fortunately for us it is and we add it to our command line like this:

guix shell --check --pure --expression='(list (@@ (gnu packages gcc) gcc) "lib")' coreutils bash grep sed gcc-toolchain patchelf libjpeg

Now you’ll need to patch the actual binary, one in the guix shell run:

patchelf --add-needed $LIBRARY_PATH/libjpeg.so.62 ts_server

Repeat the process until you have all the libraries that you need, at the end of the day this is what I needed to make it work on my machine:

  guix shell --check --pure --expression='(list (@@ (gnu packages gcc) gcc) "lib")' coreutils bash grep sed gcc-toolchain patchelf gtk+ dbus-glib libxt libevent openssl glibc file alsa-lib libmicrohttpd libjpeg cuda-toolkit@12.3.2 nvidia-driver

FIRST_PART=$(echo "$LIBRARY_PATH" | cut -d ":" -f1)
SECOND_PART=$(echo "$LIBRARY_PATH" | cut -d ":" -f2)

patchelf --set-interpreter $FIRST_PART/ld-linux-x86-64.so.2 ts_server
patchelf --add-needed $FIRST_PART/libjpeg.so.62 ts_server
patchelf --add-needed $FIRST_PART/libmicrohttpd.so.12 ts_server
patchelf --add-needed $FIRST_PART/libstdc++.so.6 ts_server
patchelf --add-needed $FIRST_PART/libgcc_s.so.1 ts_server

patchelf --add-needed $FIRST_PART/libcublasLt.so.12  libnc_cuda.so
patchelf --add-needed $FIRST_PART/libcuda.so.1 libnc_cuda.so

./ts_sd --cuda -m sd_v2.1.bin -o out.jpg "an astronaut riding a horse"

./ts_sd --cuda -m sd_v2.1.bin -o out.jpg "an astronaut riding a horse" -t bf16

Note that you could also have used the –emulate-fhs flag, what it does is basically recreate the usual /usr/lib /lib… file structure and with that I think you could have skipped the various patchelf steps.

What if you don’t want to guix shell every single time? Well you could actually turn this into it’s own package with the patchelf included, you have plenty of examples in the nonguix channel and the guix-games channel.