How to build QT binary with bundled libraries?

Update: I’ve had to abandon this because of distribution rights. Sorry for the noise.

I’m having some trouble packaging a binary with some .so files. The upstream tarball contains an ELF binary at the root and a lib directory, but AFAIK I should change this to a structure with the binary in a bin directory.

I tried to copy both files to $out and symlink the binary within bin, but running result/bin/thedarkaid gives exit code 1 and no error message. Running strace result/bin/thedarkaid shows that it seems to be looking for the binary in all the wrong places, not finding it, and finally trying to run the empty string:

execve("", [""], 0x556402a52780 /* 144 vars */) = -1 ENOENT (No such file or directory)

pkgs/games/the-dark-aid/default.nix:

{
  autoPatchelfHook,
  fetchzip,
  lib,
  libxcb,
  makeDesktopItem,
  makeWrapper,
  mkDerivation,
  pcre2,
  qt5,
  stdenv,
}: let
  pname = "the-dark-aid";
  version = "15_alpha";
  qtVersion = "5.12";

  desktopItem = makeDesktopItem {
    name = pname;
    desktopName = "The Dark Aid ${version} QT ${qtVersion}";
    exec = "thedarkaid";
    categories = ["Game" "RolePlaying"];
  };

  buildInputs = [
    libxcb
    qt5.qtbase
    qt5.qtwayland
    qt5.qtx11extras
  ];
in
  mkDerivation {
    inherit buildInputs pname version;

    src = fetchzip {
      url = "http://dsachargen.de/dev/thedarkaid_${version}_linux_qt${qtVersion}.tar.gz";
      hash = "sha256-/S80Gs5G/g6xVqjA7F3CCsxKWQMBhRqYr2e1RQ9ViDc=";
    };

    nativeBuildInputs = [
      autoPatchelfHook
      qt5.wrapQtAppsHook
    ];

    qtWrapperArgs = [
      ''--prefix LD_LIBRARY_PATH : "$out/lib:${lib.makeLibraryPath buildInputs}"''
      "--set-default QT_QPA_PLATFORM xcb"
    ];

    installPhase = ''
      runHook preInstall
      mkdir --parents "$out/bin"
      cp --recursive "$src/lib" "$src/thedarkaid" "$out/"
      cp --recursive "${desktopItem}/share" "$out/"
      ln --symbolic "$out/thedarkaid" "$out/bin/"
      runHook postInstall
    '';

    meta = {
      description = "The Dark Eye 5 character creator";
      homepage = "http://dsachargen.de/";
      downloadPage = "https://www.ulisses-ebooks.de/product/309175/The-Dark-Aid";
      sourceProvenance = [lib.sourceTypes.binaryNativeCode];
      license = lib.licenses.unfree;
      maintainers = [lib.maintainers.l0b0];
      platforms = lib.platforms.linux;
    };
  }

pkgs/top-level/all-packages.nix line:

  the-dark-aid = libsForQt5.callPackage ../games/the-dark-aid { };

I also tried to copy the binary into bin directly, but it tries to chdir to the lib directory, which fails:

QProcessPrivate::startDetached: failed to chdir to /nix/store/[…]-the-dark-aid-15_alpha/bin/lib/

Sorry, I dont have a computer to test, but here are a few thougts:

  • if the libraries are picked at runtime using dlopen, autopatchelf can’t see them so you might need to use runtimeDependencies, and disable the optimisations on rpath, dontPatchELF = true;. See also How to set `runtimeDependencies` for shared libraries? - #5 by tobiasBora
  • if the binary really expects lib to be in a subfolder, you can copy the whole program to $out/opt and add a wrapper (maybe a link would work as well) in $out/bin that calls stuff in $out/opt
1 Like