Qt development environment on a flake system

Hello, how do I create an environment to build a Qt application on a flake system? I’ve used nix-shell in the past (I’ve lost the exact invocation in history and I’m bumping into not being able to run it anymore…).

I think I’ve used something like this, which now fails:

 $  nix-shell -p libsForQt5.qt5.qmake -p libsForQt5.qt5.qtserialport
warning: Nix search path entry '/nix/var/nix/profiles/per-user/root/channels/nixos' does not exist, ignoring
error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I)

       at «string»:1:25:

            1| {...}@args: with import <nixpkgs> args; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (libsForQt5.qt5.qmake) (libsForQt5.qt5.qtserialport) ]; } ""
             |                         ^
(use '--show-trace' to show detailed location information)

Running:

nix shell nixpkgs#libsForQt5.qt5.qmake  nixpkgs#libsForQt5.qt5.qtserialport`

Doesn’t provide neither the qmake binary nor does it seem to provide the libQt5SerialPort.so.5 library.

I’ve read I may be supposed to use nix develop now, but I don’t know how. Note I don’t want to be creating a flake.nix or anything, I just want a quick environment to build the app for now.

Try nix shell nixpkgs#qt5.full maybe

nix shell mainly just sets PATH so it is not similar to nix-shell, other than in name.

If you really want to use the new nix command, you will need something like the following:

nix develop --impure --expr 'let pkgs = import (builtins.getFlake "nixpkgs/nixos-unstable") {}; in pkgs.mkShell { nativeBuildInputs = with pkgs; [ libsForQt5.qt5.qmake ]; buildInputs = with pkgs; [ libsForQt5.qt5.qtserialport ]; }'

But just like the nix-shell, this is not enough. Qt also requires certain runtime environment so for actually running the program after building it, you will need to replicate the environment set by wrapQtAppsHook.

1 Like

Thanks, the command works for building (after adding the rest if the deps). The program indeed doesn’t run, it probably needs the wrapQtAppsHook you’ve mentioned. AFAIR it was running fine when I did the analogous thing with nix-shell before.

Another thing is this command is obviously very clunky and hard to piece together, was the simple way of achieving this removed on purpose?

What do you think is the easiest way to get the program running? Like actually writing a flake for it?

My issue is this:

  1. I install and configure NixOS
  2. I want to build and run a “simple” application
    => I need to become an expert on both the Nix language as well as the NixOS way the things are set up

It’s extremely frustrating and googling usually finds really complex solutions to more or less different problems, so not really that helpful…

The issue with nix-shell is while it was convenient, it was doing a lot of magic in the background that was extremely confusing. In addition, it hard depends on Nixpkgs, which is annoying.

Since one of the goals of the new nix command is to be consistent and easily understandable, the ability to string up an ad-hoc shell derivation from arguments had to be removed. At least until an acceptable interface is designed.

If I wanted simple, I would create a tiny shell.nix using mkShell similar to above and enter it with nix-shell:

{
  pkgs ? import <nixpkgs> {},
}:

pkgs.mkShell {
  nativeBuildInputs = with pkgs; [
    libsForQt5.qt5.qmake
  ];
  buildInputs = with pkgs; [
    libsForQt5.qt5.qtserialport
  ];
}

But personally, I prefer pinning the Nixpkgs and other dependencies. I would choose the experimental flakes for that, even though flake.nix requires a bit more boilerplate:

{
  description = "My Qt app";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  };

  outputs = { self, nixpkgs }:
    let
      system = "x86_64-linux";

      pkgs = import nixpkgs {
        inherit system;
        config = { };
      };
    in {
      devShells.${system}.default = pkgs.mkShell {
        nativeBuildInputs = with pkgs; [
          libsForQt5.qt5.qmake
        ];
        buildInputs = with pkgs; [
          libsForQt5.qt5.qtserialport
        ];
      };
    };
}

That might have been due to environment contamination from e.g. your terminal emulator or the desktop environment. Unfortunately, since we control the Qt runtime with environment variables, they will get inherited. Even when the app is built against a different version of libraries.

I would recommend doing the wrapping hack in any case:

pkgs.mkShell {
  nativeBuildInputs = with pkgs; [
    libsForQt5.qt5.qmake

    # For setting Qt environment variables.
    qt5.wrapQtAppsHook
    makeWrapper
  ];

  buildInputs = with pkgs; [
    libsForQt5.qt5.qtserialport
  ];

  shellHook = ''
    # Add Qt-related environment variables.
    # https://discourse.nixos.org/t/python-qt-woes/11808/10
    setQtEnvironment=$(mktemp)
    random=$(openssl rand -base64 20 | sed "s/[^a-zA-Z0-9]//g")
    makeWrapper "$(type -p sh)" "$setQtEnvironment" "''${qtWrapperArgs[@]}" --argv0 "$random"
    sed "/$random/d" -i "$setQtEnvironment"
    source "$setQtEnvironment"
  '';
}
4 Likes

Thanks a lot for your help, really appreciated!

The app works now, the qt workaround helped. My current shell.nix:

let pkgs = import (builtins.getFlake "nixpkgs/nixos-unstable") {}; in pkgs.mkShell {
  nativeBuildInputs = with pkgs; [
    libsForQt5.qt5.qmake

    # For setting Qt environment variables.
    qt5.wrapQtAppsHook
    makeWrapper
  ];

  buildInputs = with pkgs; [
    libsForQt5.qt5.qtconnectivity
    libsForQt5.qt5.qtgamepad
    libsForQt5.qt5.qtgraphicaleffects
    libsForQt5.qt5.qtlocation
    libsForQt5.qt5.qtquickcontrols2
    libsForQt5.qt5.qtserialport
  ];

  shellHook = '' 
    # Add Qt-related environment variables. 
    # https://discourse.nixos.org/t/python-qt-woes/11808/10 
    setQtEnvironment=$(mktemp) 
    random=$(openssl rand -base64 20 | sed "s/[^a-zA-Z0-9]//g") 
    makeWrapper "$(type -p sh)" "$setQtEnvironment" "''${qtWrapperArgs[@]}" --argv0 "$random" 
    sed "/$random/d" -i "$setQtEnvironment" 
    source "$setQtEnvironment" 
  ''; 
}

It just gives me this warning:

warning: Nix search path entry '/nix/var/nix/profiles/per-user/root/channels/nixos' does not exist, ignoring
error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I)

       at «string»:1:9:

            1| (import <nixpkgs> {}).bashInteractive
             |         ^
will use bash from your environment

Tried to google it but to no avail.

Yeah, that is yet another nix-shell’s dependency on Nixpkgs. When you do not have nixpkgs in NIX_PATH, you have the following options:

  • switch to flakes
  • add nixpkgs channel, for example: nix-channel --add https://nixos.org/channels/nixos-unstable nixpkgs && nix-channel --update
  • ignore the warning

Since I do not want channels on my systems, I usually ignore the warning for my non-flake project.

1 Like