Qt: Difference between revisions

From NixOS Wiki
imported>Tobias.bora
No edit summary
imported>Tobias.bora
No edit summary
Line 114: Line 114:
</syntaxHighlight>
</syntaxHighlight>


For actual python applications, you can also use something like (TODO: check difference between wrapGAppsHook and wrapQtAppsHook) :
For actual python applications, you can also use something like :
<syntaxHighlight>
<syntaxHighlight>
python3.pkgs.buildPythonApplication {
python3.pkgs.buildPythonApplication {
   pname = "gnome-music";
   pname = "blabla";
   version = "3.32.2";
   version = "3.32.2";


   nativeBuildInputs = [
   nativeBuildInputs = [
     wrapGAppsHook
     wrapQtAppsHook
    gobject-introspection
     ...
     ...
   ];
   ];
Line 130: Line 129:
   # Arguments to be passed to `makeWrapper`, only used by buildPython*
   # Arguments to be passed to `makeWrapper`, only used by buildPython*
   preFixup = ''
   preFixup = ''
    makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
        qtWrapperArgs+=("''${gappsWrapperArgs[@]}")
   '';
   '';
}
}

Revision as of 12:20, 29 October 2021

Development

If you want to develop qt applications in nixos you have to use nix-shell or direnv. For using nix-shell just run this command in the terminal:

nix-shell -p qt5Full -p qtcreator --run qtcreator

Tip: if it finds no Qt Kits, rm -rf ~/.config/QtProject* and start again.

For using direnv, create a shell.nix file in the root of your project and paste these lines into it:

# shell.nix
{ pkgs ? import <nixpkgs> {} }:
  pkgs.mkShell {
    buildInputs = [
                    pkgs.qt5.full
                    pkgs.qtcreator
                  ];
}

Tip: if you want use clang-format, add clang-format to buildinputs list.

Also create .envrc file and paste: use_nix into it.

Happy qt coding :)


Packaging

See for the entry in the nixpkgs manual.

Qt applications can't be called with callPackage, since they expect more inputs. Namely qtbase and wrapQtAppsHook. Instead they should be called with libsForQt5.callPackage.

./build/default.nix
{ stdenv, lib, qtbase, wrapQtAppsHook }: 

stdenv.mkDerivation {
  pname = "myapp";
  version = "1.0";

  buildInputs = [ qtbase ];
  nativeBuildInputs = [ wrapQtAppsHook ]; 
}
#nix-repl
myapp = callPackage ./build/myapp/default.nix { } # Will complain it wasn't called with qtbase, etc.
myapp = libsForQt5.callPackage ./build/myapp/default.nix { } # Should work


Projects using python (e.g. PyQt5)

It's possible to package a program that uses internally python and Qt (like PyQt5) by providing a python executable with the appropriate libraries like that myPython = python3.withPackages (pkgs: with pkgs; [ pyqt5 ]);. `wrapQtAppsHook` even seems to be optional when using `mkderivation` (at least this program can be run without) since anyway it does not patch scripts.

{ mkDerivation,
  lib,
  stdenv,
  fetchFromGitHub,
  jack2,
  which,
  python3,
  qtbase,
  qttools,
  wrapQtAppsHook,
  liblo,
  git,
}:
let
  myPython = python3.withPackages (pkgs: with pkgs; [ pyqt5 liblo pyliblo pyxdg ]);
in
mkDerivation rec {
  pname = "RaySession";
  version = "0.11.1";

  src = fetchFromGitHub {
    owner = "Houston4444";
    repo = pname;
    rev = "v${version}";
    sha256 = "sha256-EbDBuOcF0JQq/LOrakb040Yfrpdi3FOB1iczQTeXBkc=";
  };

  # This patch is required to be able to create a new session, but not a problem to compile and start the program
  # patches = [ ./copy_template_writable.patch ];

  # Otherwise lrelease-qt is not found:
  postPatch = ''
   substituteInPlace Makefile \
     --replace "lrelease-qt4" "${qttools.dev}/bin/lrelease" \
     --replace '$(DESTDIR)/' '$(DESTDIR)$(PREFIX)' # Otherwise problem with installing manual etc...
  '';

  nativeBuildInputs = [
    myPython
    wrapQtAppsHook # Not really useful since it will not pack scripts. And actually it seems that it's not required?
    which
    qttools
  ];
  propagatedBuildInputs = [ myPython qtbase jack2 git ];

  # Prefix must be set correctly due to sed -i "s?X-PREFIX-X?$(PREFIX)?"
  makeFlags = [ "PREFIX=$(out)" ]; # prefix does not work since due to line "install -d $(DESTDIR)/etc/xdg/"
}

Call it with

{ pkgs ? import <nixpkgs> {} }:
pkgs.libsForQt5.callPackage ./derivation.nix {}

For actual python applications, you can also use something like :

python3.pkgs.buildPythonApplication {
  pname = "blabla";
  version = "3.32.2";

  nativeBuildInputs = [
    wrapQtAppsHook
    ...
  ];

  dontWrapGApps = true;

  # Arguments to be passed to `makeWrapper`, only used by buildPython*
  preFixup = ''
        qtWrapperArgs+=("''${gappsWrapperArgs[@]}")
  '';
}

Troubleshooting

Cannot mix incompatible Qt library (version 0x_____) with this library (version 0x_____)

This is a known issue, see #30551 for the current status.

Starting with the 19.09 release, the issue should be fixed by #65526

This application failed to start because it could not find or load the Qt platform plugin ??? in ""

qt4

Qt4 depends on the environment variable QT_PLUGIN_PATH to find plugins. It is normally already

present in the environment on NixOS at least, but for example systemd user units are launched in a pretty empty environment. A solution is to use the command

systemctl --user import-environment QT_PLUGIN_PATH

from a sane environment. For example add it to the services.xserver.displayManager.sessionCommands option.

qt5

Warning: This recommendation is deprecated for 19.09 and up, see #65399. Failing packages should be updated to use wrapQtAppsHook.

Qt5 seems (?) to look for plugins in the PATH. This will fail from a systemd user unit for example, because their path is nearly empty by default. As an example, here is a workaround to have usbguard-applet launched from a systemd user unit:

/etc/nixos/configuration.nix
  systemd.user.services.usbguard-applet = {
    description = "USBGuard applet";
    partOf = [ "graphical-session.target" ];
    wantedBy = [ "graphical-session.target" ];
    path = [ "/run/current-system/sw/" ]; ### Fix empty PATH to find qt plugins
    serviceConfig = {
      ExecStart = "${pkgs.usbguard}/bin/usbguard-applet-qt";
    };
  };

qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in ""

Here is a concrete example:

qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in ""
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

The package will need to be fixed to use [the new https://github.com/NixOS/nixpkgs/issues/65399 wrapQtAppsHook]. The hook wraps every qt application with adding QT_PLUGIN_PATH and XDG_DATA_DIRS as well as XDG_CONFIG_DIRS.See wrap-qt-hook.sh in nixpkgs

Debugging methods

As a general rule, exporting QT_DEBUG_PLUGINS=1 make qt print where it looks for plugins.

If a plugin exists in a directory but is ignored with a message like QLibraryPrivate::loadPlugin failed on "/nix/store/...-teamspeak-client-3.1.6/lib/teamspeak/platforms/libqxcb.so" : "Cannot load library /nix/store/...-client-3.1.6/lib/teamspeak/platforms/libqxcb.so: " it can be that the library cannot be dlopen()ed because of dependencies/rpath issues and needs patchelfing. Exporting LD_DEBUG=libs may prove helpful in this scenario.