No such file of directory when trying to execute binary file

Hello,

I’m trying to run the demo of Robo Instructus, which I downloaded here: https://bigabgames.itch.io/robo-instructus

After unzipping the archive I have the following files:

drwxr-xr-x    - little-dude 28 Feb  1:20 lib
.rw-r--r-- 2.3k little-dude 28 Feb  1:20 README.txt
.rwxr-xr-x 157M little-dude 28 Feb  1:20 robo_instructus
.rwxr-xr-x  151 little-dude 28 Feb  1:20 run-robo-instructus.sh

However, I cannot execute the binary:

❯ ./robo_instructus
zsh: no such file or directory: ./robo_instructus

Even using the script provided with the archive:

#!/usr/bin/env bash

dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LD_LIBRARY_PATH=$dir/lib:$LD_LIBRARY_PATH "$dir"/robo_instructus & disown

It gives:

❯ ./run-robo-instructus.sh
./run-robo-instructus.sh: line 4: /home/little-dude/robo-instructus-demo/robo_instructus: No such file or directory

After finding this SO question I thought it could be a problem with the executable being a 32-bits binary, but it actually is 64-bits:

❯ file robo_instructus
robo_instructus: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=12054b5cbdf015dc4c94a37051e2b7fb50c1301e, with debug_info, not stripped

That sounds a bit silly, but… do you know why I’m getting this error, and how I could run this binary on my system?

1 Like

You typically get this error when the dynamic loader cannot be found. There are several options: package the game and use e.g. autoPatchelfHook, patch the binary manually, or run the binary in a FHS environment. For the former two, see:

https://nixos.wiki/wiki/Packaging/Binaries

For running the binary in an FHS environment, trying stream-run is probably the first good try:

https://nixos.wiki/wiki/Steam

2 Likes

Thank you, I’m going through the “packaging binaries” tutorial right now, I’ll report back later!

There’s a bigger thread about this topic here if you’re curious: How to make NixOS so easy that people can be productive up front, without having to first learn the nix language?

The simplest is to try steam-run ./robo_instructus as already mentioned here but there are other solutions in the thread that might interest you as well

So I’m able to run the binary! Now I’d like to write a default.nix for it. I tried to adapt the given one, but the unpacking phase fails:

with import <nixpkgs> { };
stdenv.mkDerivation rec {
  buildInputs = [ pkgs.unzip ];
  name = "robo-instructus-demo";
  version = "1.0";

  src = [ ./robo-instructus-linux-demo.zip ];
  sourceRoot = ".";

  dontConfigure = true;
  dontBuild = true;

  installPhase = ''
    mkdir -p $out/{bin,lib}
    mv robo-instructus $out/bin/
    mv lib/* $out/lib/
  '';
  preFixup = let
    libPath = lib.makeLibraryPath [
      pkgs.alsaLib
      pkgs.glibc
      pkgs.xlibs.libxcb
      pkgs.xlibs.libX11
      pkgs.xlibs.libXcursor
      pkgs.xlibs.libXi
      pkgs.xlibs.libXrandr
      pkgs.libglvnd
      # FIXME:
      #
      # Somehow also include the path to the lib directory of the current
      # derivation's output path.
    ];
  in ''
    patchelf \
      --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
      --set-rpath "${libPath}" \
      $out/bin/robo-instructus
  '';

  meta = with stdenv.lib; {
    homepage = "https://code-industry.net/masterpdfeditor/";
    description = "A programming game";

    # FIXME: build fails if we set this to unfree, although in
    # /etc/nixos/configuration.nix I have:
    #
    #   nixpkgs.config.allowUnfree = true;
    #
    # license = licenses.unfree;

    platforms = platforms.linux;
    maintainers = [ "little-dude" ];
  };
}

The error:


[nix-shell:~/robo-instructus-demo/test]$ ls
default.nix  robo-instructus-linux-demo.zip

[nix-shell:~/robo-instructus-demo/test]$ nix-build 
these derivations will be built:
  /nix/store/sd4gw8ai7jh257yara3sj8k4m27978s3-robo-instructus-demo.drv
building '/nix/store/sd4gw8ai7jh257yara3sj8k4m27978s3-robo-instructus-demo.drv'...
unpacking sources
unpacking source archive /nix/store/mlf7jja8ns59hm7rwj611pjkxjppvagv-robo-instructus-linux-demo.zip
[/nix/store/mlf7jja8ns59hm7rwj611pjkxjppvagv-robo-instructus-linux-demo.zip]
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of /nix/store/mlf7jja8ns59hm7rwj611pjkxjppvagv-robo-instructus-linux-demo.zip or
        /nix/store/mlf7jja8ns59hm7rwj611pjkxjppvagv-robo-instructus-linux-demo.zip.zip, and cannot find /nix/store/mlf7jja8ns59hm7rwj611pjkxjppvagv-robo-instructus-linux-demo.zip.ZIP, period.
do not know how to unpack source archive /nix/store/mlf7jja8ns59hm7rwj611pjkxjppvagv-robo-instructus-linux-demo.zip
builder for '/nix/store/sd4gw8ai7jh257yara3sj8k4m27978s3-robo-instructus-demo.drv' failed with exit code 1
error: build of '/nix/store/sd4gw8ai7jh257yara3sj8k4m27978s3-robo-instructus-demo.drv' failed

Finally! I got a working version. The tricks was to set the dontPatchELF flag (not sure why):

# with import <nixpkgs> { config = { allowUnfree = true; }; };
with import <nixpkgs> {}; with pkgs;
stdenv.mkDerivation rec {
  name = "robo-instructus-demo";
  version = "1.0";
  buildInputs = [ pkgs.unzip 
      alsaLib
      glibc
      xlibs.libxcb
      xlibs.libX11
      xlibs.libXcursor
      xlibs.libXi
      xlibs.libXrandr
      libglvnd ];
  src = ./robo-instructus-linux-demo.zip ;
  sourceRoot = ".";
  dontConfigure = true;
  dontBuild = true;
  installPhase = ''
    mkdir -p $out/{bin,lib}
    mv robo_instructus $out/bin/robo-instructus-demo
    mv lib/* $out/lib/
  '';
  dontPatchELF = true;
  preFixup = let
    libPath = lib.makeLibraryPath [
      alsaLib
      glibc
      xlibs.libxcb
      xlibs.libX11.out
      xlibs.libXcursor
      xlibs.libXi
      xlibs.libXrandr
      libglvnd
    ];
  in ''
    rPath="${libPath}:$out/lib"
    echo $rPath
    patchelf \
      --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
      --set-rpath $rPath \
      $out/bin/robo-instructus-demo
  '';
  meta = with stdenv.lib; {
    homepage = "https://www.roboinstruct.us/";
    description = "A programming game";
    license = licenses.unfree;
    platforms = platforms.linux;
    maintainers = [ "little-dude" ];
  };
}

Does that look like a decent derivation?