Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 23 additions & 34 deletions doc/languages-frameworks/qt.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,61 @@
Writing Nix expressions for Qt libraries and applications is largely similar as for other C++ software.
This section assumes some knowledge of the latter.

The major caveat with Qt applications is that Qt uses a plugin system to load additional modules at runtime,
from a list of well-known locations. In Nixpkgs, we patch QtCore to instead use an environment variable,
and wrap Qt applications to set it to the right paths. This effectively makes the runtime dependencies
pure and explicit at build-time, at the cost of introducing an extra indirection.
The major caveat with Qt applications is that Qt uses a plugin system to load additional modules at runtime.
In Nixpkgs, we wrap Qt applications to inject environment variables telling Qt where to discover the required plugins and QML modules.

This effectively makes the runtime dependencies pure and explicit at build-time, at the cost of introducing
an extra indirection.

## Nix expression for a Qt package (default.nix) {#qt-default-nix}

```nix
{ stdenv, lib, qtbase, wrapQtAppsHook }:
{ stdenv, lib, qt6, wrapQtAppsHook }:

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

buildInputs = [ qtbase ];
nativeBuildInputs = [ wrapQtAppsHook ];
buildInputs = [ qt6.qtbase ];
nativeBuildInputs = [ qt6.wrapQtAppsHook ];
}

@Aleksanaa Aleksanaa Feb 8, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also provide an example for Qt5.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need one? It feels pretty obvious to me.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay then.

```

It is important to import Qt modules directly, that is: `qtbase`, `qtdeclarative`, etc. *Do not* import Qt package sets such as `qt5` because the Qt versions of dependencies may not be coherent, causing build and runtime failures.

Additionally all Qt packages must include `wrapQtAppsHook` in `nativeBuildInputs`, or you must explicitly set `dontWrapQtApps`.

`pkgs.callPackage` does not provide injections for `qtbase` or the like.
Instead you want to either use `pkgs.libsForQt5.callPackage`, or `pkgs.qt6Packages.callPackage`, depending on the Qt version you want to use.
Any Qt package should include `wrapQtAppsHook` in `nativeBuildInputs`, or explicitly set `dontWrapQtApps` to bypass generating the wrappers.
Comment thread
K900 marked this conversation as resolved.
Outdated

For example (from [here](https://github.com/NixOS/nixpkgs/blob/2f9286912cb215969ece465147badf6d07aa43fe/pkgs/top-level/all-packages.nix#L30106))
::: {.note}
Graphical Linux applications should also include `qtwayland` in `buildInputs`, to ensure the Wayland platform plugin is available.

```nix
zeal-qt5 = libsForQt5.callPackage ../data/documentation/zeal { };
zeal-qt6 = qt6Packages.callPackage ../data/documentation/zeal { };
zeal = zeal-qt5;
```
This may become default in the future, see [NixOS/nixpkgs#269674](https://github.com/NixOS/nixpkgs/pull/269674).
:::

## Locating runtime dependencies {#qt-runtime-dependencies}
## Packages supporting multiple Qt versions {#qt-versions}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header ids are here so that documentation links don't become invalid. We can manually add anchors for previous ids:

Suggested change
## Packages supporting multiple Qt versions {#qt-versions}
[]{#qt-runtime-dependencies}
## Packages supporting multiple Qt versions {#qt-versions}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just github diffs being shitty, the next header still has that anchor.


Qt applications must be wrapped to find runtime dependencies.
Include `wrapQtAppsHook` in `nativeBuildInputs`:
If your package is a library that can be built with multiple Qt versions, you may want to take Qt modules as separate arguments (`qtbase`, `qtdeclarative` etc.), and invoke the package from `pkgs/top-level/qt5-packages.nix` or `pkgs/top-level/qt6-packages.nix` using the respective `callPackage` functions.

```nix
{ stdenv, wrapQtAppsHook }:
Applications should generally be built with upstream's preferred Qt version.

stdenv.mkDerivation {
# ...
nativeBuildInputs = [ wrapQtAppsHook ];
}
```
## Locating additional runtime dependencies {#qt-runtime-dependencies}

Add entries to `qtWrapperArgs` are to modify the wrappers created by
`wrapQtAppsHook`:

```nix
{ stdenv, wrapQtAppsHook }:
{ stdenv, qt6 }:

stdenv.mkDerivation {
# ...
nativeBuildInputs = [ wrapQtAppsHook ];
nativeBuildInputs = [ qt6.wrapQtAppsHook ];
qtWrapperArgs = [ ''--prefix PATH : /path/to/bin'' ];
}
```

The entries are passed as arguments to [wrapProgram](#fun-wrapProgram).

Set `dontWrapQtApps` to stop applications from being wrapped automatically.
Wrap programs manually with `wrapQtApp`, using the syntax of
[wrapProgram](#fun-wrapProgram):
If you need more control over the wrapping process, set `dontWrapQtApps` to disable automatic wrapper generation,
and then create wrappers manually in `fixupPhase`, using `wrapQtApp`, which itself is a small wrapper over [wrapProgram](#fun-wrapProgram):

The `makeWrapper` arguments required for Qt are also exposed in the environment as `$qtWrapperArgs`.

```nix
{ stdenv, lib, wrapQtAppsHook }:
Expand Down