Python + Qt woes

Qt requires specific environment variables (e.g. QT_PLUGIN_PATH). If you are building a program, wrapQtAppsHook will fix that for you but for shells, I am not aware of a ready-made solution.

I do not think nix shell supports that (other than using an explicit expression like nix shell --impure --expr 'with import ./. {}; python38.withPackages(ps: with ps; [ pyqtgraph ])'). I am not even sure if the support was intentional in nix-shell or just a by-product of it stuffing -p values verbatim to buildInputs of an ad-hoc derivation.

As I understand it, the new Nix CLI aims to be simpler, and one of the approaches is separating the builder scripts from the build products:

  • In nix-shell, you were basically transplanted into the environment of mkDerivation builder, with buildInputs on PATH, environment variables set by various setup hooks, and even bash functions from stdenv available.

  • nix shell chooses cleaner method of just adding the binaries of requested packages to PATH, not touching much else of the environment. That is conceptually easier but useless for programs that need modified environment.

  • nix develop is closer to the nix-shell of old but if you want anything more complex, you need to create the shell derivation yourself: nix develop --impure --expr 'with import ./. {}; mkShell { buildInputs = [ (python38.withPackages (ps: with ps; [ pyqtgraph ])) qt5.wrapQtAppsHook makeWrapper bashInteractive ]; shellHook = \'\'bashdir=$(mktemp -d); makeWrapper "$(type -p bash)" "$bashdir/bash" "\'\'${qtWrapperArgs[@]}"; exec "$bashdir/bash"\'\'; }'

The craziness above actually takes the environment that wrapQtAppsHook would wrap binaries with and runs a new shell with that environment. But at that point, you probably want to save it into shell.nix.

let
   pkgs = with import ./. {};
in
  pkgs.mkShell {
    buildInputs = [
      (python38.withPackages (ps: with ps; [
        pyqtgraph
      ]))
      qt5.wrapQtAppsHook
      makeWrapper
      bashInteractive
    ];

    shellHook = ''
      bashdir=$(mktemp -d)
      makeWrapper "$(type -p bash)" "$bashdir/bash" "''${qtWrapperArgs[@]}"
      exec "$bashdir/bash"
    '';
  }
1 Like