···11# Qt {#sec-language-qt}
2233-This section describes the differences between Nix expressions for Qt libraries and applications and Nix expressions for other C++ software. Some knowledge of the latter is assumed.
33+Writing Nix expressions for Qt libraries and applications is largely similar as for other C++ software.
44+This section assumes some knowledge of the latter.
55+There are two problems that the Nixpkgs Qt infrastructure addresses,
66+which are not shared by other C++ software:
4755-There are primarily two problems which the Qt infrastructure is designed to address: ensuring consistent versioning of all dependencies and finding dependencies at runtime.
88+1. There are usually multiple supported versions of Qt in Nixpkgs.
99+ All of a package's dependencies must be built with the same version of Qt.
1010+ This is similar to the version constraints imposed on interpreted languages like Python.
1111+2. Qt makes extensive use of runtime dependency detection.
1212+ Runtime dependencies are made into build dependencies through wrappers.
613714## Nix expression for a Qt package (default.nix) {#qt-default-nix}
815916```{=docbook}
1017<programlisting>
1111-{ mkDerivation, qtbase }: <co xml:id='qt-default-nix-co-1' />
1818+{ stdenv, lib, qtbase, wrapQtAppsHook }: <co xml:id='qt-default-nix-co-1' />
12191313-mkDerivation { <co xml:id='qt-default-nix-co-2' />
2020+stdenv.mkDerivation {
1421 pname = "myapp";
1522 version = "1.0";
16231717- buildInputs = [ qtbase ]; <co xml:id='qt-default-nix-co-3' />
2424+ buildInputs = [ qtbase ];
2525+ nativeBuildInputs = [ wrapQtAppsHook ]; <co xml:id'qt-default-nix-co-2' />
1826}
1927</programlisting>
20282129 <calloutlist>
2230 <callout arearefs='qt-default-nix-co-1'>
2331 <para>
2424- Import <literal>mkDerivation</literal> and Qt (such as <literal>qtbase</literal> modules directly. <emphasis>Do not</emphasis> import Qt package sets; the Qt versions of dependencies may not be coherent, causing build and runtime failures.
3232+ Import Qt modules directly, that is: <literal>qtbase</literal>, <literal>qtdeclarative</literal>, etc.
3333+ <emphasis>Do not</emphasis> import Qt package sets such as <literal>qt5</literal>
3434+ because the Qt versions of dependencies may not be coherent, causing build and runtime failures.
2535 </para>
2636 </callout>
2727- <callout arearefs='qt-default-nix-co-2'>
2828- <para>
2929- Use <literal>mkDerivation</literal> instead of <literal>stdenv.mkDerivation</literal>. <literal>mkDerivation</literal> is a wrapper around <literal>stdenv.mkDerivation</literal> which applies some Qt-specific settings. This deriver accepts the same arguments as <literal>stdenv.mkDerivation</literal>; refer to <xref linkend='chap-stdenv' /> for details.
3030- </para>
3131- <para>
3232- To use another deriver instead of <literal>stdenv.mkDerivation</literal>, use <literal>mkDerivationWith</literal>:
3333-<programlisting>
3434-mkDerivationWith myDeriver {
3535- # ...
3636-}
3737-</programlisting>
3838- If you cannot use <literal>mkDerivationWith</literal>, please refer to <xref linkend='qt-runtime-dependencies' />.
3939- </para>
4040- </callout>
4141- <callout arearefs='qt-default-nix-co-3'>
4242- <para>
4343- <literal>mkDerivation</literal> accepts the same arguments as <literal>stdenv.mkDerivation</literal>, such as <literal>buildInputs</literal>.
4444- </para>
3737+ <callout arearefs="qt-default-nix-co-2'>
3838+ <para>
3939+ All Qt packages must include <literal>wrapQtAppsHook</literal> in
4040+ <literal>nativeBuildInputs</literal>, or you must explicitly set
4141+ <literal>dontWrapQtApps</literal>.
4242+ </para>
4543 </callout>
4644 </calloutlist>
4745```
48464947## Locating runtime dependencies {#qt-runtime-dependencies}
5050-Qt applications need to be wrapped to find runtime dependencies. If you cannot use `mkDerivation` or `mkDerivationWith` above, include `wrapQtAppsHook` in `nativeBuildInputs`:
4848+4949+Qt applications must be wrapped to find runtime dependencies.
5050+Include `wrapQtAppsHook` in `nativeBuildInputs`:
51515252```nix
5353+{ stdenv, wrapQtAppsHook }:
5454+5355stdenv.mkDerivation {
5456 # ...
5555-5657 nativeBuildInputs = [ wrapQtAppsHook ];
5758}
5859```
5959-Entries added to `qtWrapperArgs` are used to modify the wrappers created by `wrapQtAppsHook`. The entries are passed as arguments to [wrapProgram executable makeWrapperArgs](#fun-wrapProgram).
6060+6161+Add entries to `qtWrapperArgs` are to modify the wrappers created by
6262+`wrapQtAppsHook`:
60636164```nix
6262-mkDerivation {
6363- # ...
6565+{ stdenv, wrapQtAppsHook }:
64666767+stdenv.mkDerivation {
6868+ # ...
6969+ nativeBuildInputs = [ wrapQtAppsHook ];
6570 qtWrapperArgs = [ ''--prefix PATH : /path/to/bin'' ];
6671}
6772```
68736969-Set `dontWrapQtApps` to stop applications from being wrapped automatically. It is required to wrap applications manually with `wrapQtApp`, using the syntax of [wrapProgram executable makeWrapperArgs](#fun-wrapProgram):
7474+The entries are passed as arguments to [wrapProgram](#fun-wrapProgram).
7575+7676+Set `dontWrapQtApps` to stop applications from being wrapped automatically.
7777+Wrap programs manually with `wrapQtApp`, using the syntax of
7878+[wrapProgram](#fun-wrapProgram):
70797180```nix
7272-mkDerivation {
8181+{ stdenv, lib, wrapQtAppsHook }:
8282+8383+stdenv.mkDerivation {
7384 # ...
7474-8585+ nativeBuildInputs = [ wrapQtAppsHook ];
7586 dontWrapQtApps = true;
7687 preFixup = ''
7788 wrapQtApp "$out/bin/myapp" --prefix PATH : /path/to/bin
···7990}
8091```
81928282-> Note: `wrapQtAppsHook` ignores files that are non-ELF executables. This means that scripts won't be automatically wrapped so you'll need to manually wrap them as previously mentioned. An example of when you'd always need to do this is with Python applications that use PyQT.
9393+::: note
9494+`wrapQtAppsHook` ignores files that are non-ELF executables.
9595+This means that scripts won't be automatically wrapped so you'll need to manually wrap them as previously mentioned.
9696+An example of when you'd always need to do this is with Python applications that use PyQt.
9797+:::
83988484-Libraries are built with every available version of Qt. Use the `meta.broken` attribute to disable the package for unsupported Qt versions:
9999+## Adding a library to Nixpkgs
100100+Add Qt libraries to `qt5-packages.nix` to make them available for every
101101+supported Qt version.
851028686-```nix
8787-mkDerivation {
8888- # ...
8989-9090- # Disable this library with Qt < 5.9.0
9191- meta.broken = builtins.compareVersions qtbase.version "5.9.0" < 0;
9292-}
9393-```
9494-## Adding a library to Nixpkgs
9595-Qt libraries are added to `qt5-packages.nix` and are made available for every Qt
9696-version supported.
97103### Example adding a Qt library {#qt-library-all-packages-nix}
9810499105The following represents the contents of `qt5-packages.nix`.
···106112 # ...
107113}
108114```
115115+116116+Libraries are built with every available version of Qt.
117117+Use the `meta.broken` attribute to disable the package for unsupported Qt versions:
118118+119119+```nix
120120+{ stdenv, lib, qtbase }:
121121+122122+stdenv.mkDerivation {
123123+ # ...
124124+ # Disable this library with Qt < 5.9.0
125125+ meta.broken = lib.versionOlder qtbase.version "5.9.0";
126126+}
127127+```
128128+109129## Adding an application to Nixpkgs
110110-Applications that use Qt are also added to `qt5-packages.nix`. An alias is added
111111-in the top-level `all-packages.nix` pointing to the package with the desired Qt5 version.
130130+Add Qt applications to `qt5-packages.nix`. Add an alias to `all-packages.nix`
131131+to select the Qt 5 version used for the application.
112132113133### Example adding a Qt application {#qt-application-all-packages-nix}
114134
···4040 "SHARE_DIR=${placeholder "out"}/share"
4141 ];
42424343+ dontWrapQtApps = true;
4444+4345 meta = with lib; {
4446 description = "CsoundQt is a frontend for Csound with editor, integrated help, widgets and other features";
4547 homepage = "https://csoundqt.github.io/";
+2
pkgs/applications/audio/keyfinder/default.nix
···2121 --replace "\$\$[QT_INSTALL_PREFIX]" "$out"
2222 '';
23232424+ dontWrapQtApps = true;
2525+2426 enableParallelBuilding = true;
25272628 meta = with lib; {
···2727 kwindowsystem
2828 ];
29293030+ dontWrapQtApps = true;
3131+3032 meta = with lib; {
3133 description = "Mpris2 Client for Plasma5";
3234 homepage = "https://github.com/audoban/PlayBar2";
+2
pkgs/applications/audio/seq66/default.nix
···25252626 enableParallelBuilding = true;
27272828+ dontWrapQtApps = true;
2929+2830 meta = with lib; {
2931 homepage = "https://github.com/ahlstromcj/seq66";
3032 description = "Loop based midi sequencer with Qt GUI derived from seq24 and sequencer64";
+2
pkgs/applications/audio/spectmorph/default.nix
···12121313 nativeBuildInputs = [ pkg-config ];
14141515+ dontWrapQtApps = true;
1616+1517 meta = with lib; {
1618 description = "Allows to analyze samples of musical instruments, and to combine them (morphing) to construct hybrid sounds";
1719 homepage = "http://spectmorph.org";
···3939 ]
4040 ++ lib.optionals withQt [ "UI=qt" ]
4141 ++ lib.optionals withGtk [ "UI=gtk" ];
4242+4343+ dontWrapQtApps = true;
4444+4245 meta = with lib; {
4346 description = "Folding text editor, designed to hierarchically structure any kind of text file and especially source code";
4447 homepage = "https://tibleiz.net/code-browser/";
···109109 };
110110 # Wrapping is done with an external wrapper
111111 dontWrapPythonPrograms = true;
112112+ dontWrapQtApps = true;
112113 # Tests should succeed, but it's hard to get LD_LIBRARY_PATH right in order
113114 # for it to happen.
114115 doCheck = false;
+2
pkgs/applications/radio/unixcw/default.nix
···1212 buildInputs = [libpulseaudio alsaLib pkg-config qt5.qtbase];
1313 CFLAGS ="-lasound -lpulse-simple";
14141515+ dontWrapQtApps = true;
1616+1517 meta = with lib; {
1618 description = "sound characters as Morse code on the soundcard or console speaker";
1719 longDescription = ''
+2
pkgs/applications/science/logic/mcrl2/default.nix
···1313 nativeBuildInputs = [ cmake ];
1414 buildInputs = [ libGLU libGL qt5.qtbase boost ];
15151616+ dontWrapQtApps = true;
1717+1618 meta = with lib; {
1719 description = "A toolset for model-checking concurrent systems and protocols";
1820 longDescription = ''
···25252626 NIX_LDFLAGS = "-lsvn_fs-1";
27272828+ dontWrapQtApps = true;
2929+2830 meta = with lib; {
2931 homepage = "https://github.com/svn-all-fast-export/svn2git";
3032 description = "A fast-import based converter for an svn repo to git repos";
+2
pkgs/applications/video/obs-studio/obs-ndi.nix
···3131 "-DCMAKE_CXX_FLAGS=-I${obs-studio.src}/UI/obs-frontend-api"
3232 ];
33333434+ dontWrapQtApps = true;
3535+3436 meta = with lib; {
3537 description = "Network A/V plugin for OBS Studio";
3638 homepage = "https://github.com/Palakis/obs-ndi";
···1212 buildInputs = [ openssl qtbase ];
1313 nativeBuildInputs = [ cmake pkg-config ];
14141515+ dontWrapQtApps = true;
1616+1517 # Without this patch cmake fails with a "No known features for CXX compiler"
1618 # error on darwin
1719 patches = lib.optional stdenv.isDarwin ./move-project.patch ;
···11+if [[ -n "${__nix_qtbase-}" ]]; then
22+ # Throw an error if a different version of Qt was already set up.
33+ if [[ "$__nix_qtbase" != "@dev@" ]]; then
44+ echo >&2 "Error: detected mismatched Qt dependencies:"
55+ echo >&2 " @dev@"
66+ echo >&2 " $__nix_qtbase"
77+ exit 1
88+ fi
99+else # Only set up Qt once.
1010+__nix_qtbase="@dev@"
1111+112qtPluginPrefix=@qtPluginPrefix@
213qtQmlPrefix=@qtQmlPrefix@
314qtDocPrefix=@qtDocPrefix@
···516. @fix_qt_builtin_paths@
617. @fix_qt_module_paths@
7181919+# Disable debug symbols if qtbase was built without debugging.
2020+# This stops -dev paths from leaking into other outputs.
2121+if [ -z "@debug@" ]; then
2222+ NIX_CFLAGS_COMPILE="${NIX_CFLAGS_COMPILE-}${NIX_CFLAGS_COMPILE:+ }-DQT_NO_DEBUG"
2323+fi
2424+2525+# Integration with CMake:
2626+# Set the CMake build type corresponding to how qtbase was built.
2727+if [ -n "@debug@" ]; then
2828+ cmakeBuildType="Debug"
2929+else
3030+ cmakeBuildType="Release"
3131+fi
3232+833providesQtRuntime() {
934 [ -d "$1/$qtPluginPrefix" ] || [ -d "$1/$qtQmlPrefix" ]
1035}
···1944QMAKEMODULES=
2045export QMAKEMODULES
21464747+declare -Ag qmakePathSeen=()
2248qmakePathHook() {
4949+ # Skip this path if we have seen it before.
5050+ # MUST use 'if' because 'qmakePathSeen[$]' may be unset.
5151+ if [ -n "${qmakePathSeen[$1]-}" ]; then return; fi
5252+ qmakePathSeen[$1]=1
2353 if [ -d "$1/mkspecs" ]
2454 then
2555 QMAKEMODULES="${QMAKEMODULES}${QMAKEMODULES:+:}/mkspecs"
···3464# package depending on the building package. (This is necessary in case
3565# the building package does not provide runtime dependencies itself and so
3666# would not be propagated to the user environment.)
6767+declare -Ag qtEnvHostTargetSeen=()
3768qtEnvHostTargetHook() {
6969+ # Skip this path if we have seen it before.
7070+ # MUST use 'if' because 'qmakePathSeen[$]' may be unset.
7171+ if [ -n "${qtEnvHostTargetSeen[$1]-}" ]; then return; fi
7272+ qtEnvHostTargetSeen[$1]=1
3873 if providesQtRuntime "$1" && [ "z${!outputBin}" != "z${!outputDev}" ]
3974 then
4075 propagatedBuildInputs+=" $1"
···6499if [ -z "${dontPatchMkspecs-}" ]; then
65100 postPhases="${postPhases-}${postPhases:+ }postPatchMkspecs"
66101fi
102102+103103+qtPreHook() {
104104+ # Check that wrapQtAppsHook is used, or it is explicitly disabled.
105105+ if [[ -z "$__nix_wrapQtAppsHook" && -z "$dontWrapQtApps" ]]; then
106106+ echo >&2 "Error: wrapQtAppsHook is not used, and dontWrapQtApps is not set."
107107+ exit 1
108108+ fi
109109+}
110110+prePhases+=" qtPreHook"
111111+112112+fi
···11+if [[ -z "${__nix_wrapQtAppsHook-}" ]]; then
22+__nix_wrapQtAppsHook=1 # Don't run this hook more than once.
33+14# Inherit arguments given in mkDerivation
25qtWrapperArgs=( ${qtWrapperArgs-} )
36···100103}
101104102105fixupOutputHooks+=(wrapQtAppsHook)
106106+107107+fi
···2020 # On 0.9.7, they do not even build with QT4
2121 cmakeFlags = lib.optional (!doCheck) "-DENABLE_TESTS=OFF";
22222323+ dontWrapQtApps = true;
2424+2325 doCheck = false; # giving up for now
24262527 meta = with lib; {
+2
pkgs/development/libraries/vtk/generic.nix
···5757 export LD_LIBRARY_PATH="$(pwd)/lib";
5858 '';
59596060+ dontWrapQtApps = true;
6161+6062 # Shared libraries don't work, because of rpath troubles with the current
6163 # nixpkgs cmake approach. It wants to call a binary at build time, just
6264 # built and requiring one of the shared objects.
+2
pkgs/development/python-modules/ovito/default.nix
···30303131 propagatedBuildInputs = with python.pkgs; [ sphinx numpy sip pyqt5 matplotlib ase ];
32323333+ dontWrapQtApps = true;
3434+3335 meta = with lib; {
3436 description = "Scientific visualization and analysis software for atomistic simulation data";
3537 homepage = "https://www.ovito.org";
···2525 "-DBUILD_TESTS=OFF"
2626 ];
27272828+ dontWrapQtApps = true;
2929+2830 # The upstream build system consists of a `setup.py` whichs builds three
2931 # different python libraries and calls cmake as a subprocess. We call cmake
3032 # directly because that's easier to get working. However, the `setup.py`