Skip to content

Commit

Permalink
WIP: Loads qt plugin paths as registered...
Browse files Browse the repository at this point in the history
This adds the list of Qt plugin paths into builds using `qtbase`.

The plugins list will be added to the Qt plugin path through the
additional patch.

This ensures that no special environment is required to get the desired
plugin path for Qt software.

This should fix all issues where Qt is unable to load its platform
plugin.

This may fix the issue where Qt tries to load a mismatched version of a
plugin.
  • Loading branch information
samueldr committed Jul 24, 2018
1 parent dae9cf6 commit b0d74d8
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 2 deletions.
1 change: 1 addition & 0 deletions pkgs/development/libraries/qt-5/5.11/default.nix
Expand Up @@ -39,6 +39,7 @@ let
patches = {
qtbase = [
./qtbase.patch
./qtbase-additional.patch
./qtbase-darwin.patch
./qtbase-revert-no-macos10.10.patch
];
Expand Down
32 changes: 32 additions & 0 deletions pkgs/development/libraries/qt-5/5.11/qtbase-additional.patch
@@ -0,0 +1,32 @@
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 5ae3fd62e5..ec3fccfc76 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -2533,6 +2533,27 @@ QStringList QCoreApplication::libraryPaths()
QStringList *app_libpaths = new QStringList;
coreappdata()->app_libpaths.reset(app_libpaths);

+ {
+ // Start at the binary; this allows us to *always* start by stripping the last part.
+ QStringList components = applicationFilePath().split(QDir::separator());
+
+ // We don't care about /nix/store/nix-support, only /nix/store/*/nix-support
+ // This is why we're checking for more than 3 parts. It will bail out once /nix/xtore/*/nix-support/qt-plugin-paths has been tested.
+ while (components.length() > 4) {
+ components.removeLast();
+ const QString support_plugin_paths = QDir::cleanPath(QDir::separator() + components.join(QDir::separator()) + QStringLiteral("/nix-support/qt-plugin-paths"));
+ if (QFile::exists(support_plugin_paths)) {
+ QFile file(support_plugin_paths);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream in(&file);
+ while (!in.atEnd()) {
+ app_libpaths->append(in.readLine());
+ }
+ }
+ }
+ }
+ }
+
// Add library paths derived from PATH
const QStringList paths = QFile::decodeName(qgetenv("PATH")).split(':');
const QString plugindir = QStringLiteral("../" NIXPKGS_QT_PLUGIN_PREFIX);
2 changes: 1 addition & 1 deletion pkgs/development/libraries/qt-5/5.9/default.nix
Expand Up @@ -37,7 +37,7 @@ let
srcs = import ./srcs.nix { inherit fetchurl; inherit mirror; };

patches = {
qtbase = [ ./qtbase.patch ] ++ optional stdenv.isDarwin ./qtbase-darwin.patch;
qtbase = [ ./qtbase.patch ./qtbase-additional.patch ] ++ optional stdenv.isDarwin ./qtbase-darwin.patch;
qtdeclarative = [ ./qtdeclarative.patch ];
qtscript = [ ./qtscript.patch ];
qtserialport = [ ./qtserialport.patch ];
Expand Down
32 changes: 32 additions & 0 deletions pkgs/development/libraries/qt-5/5.9/qtbase-additional.patch
@@ -0,0 +1,32 @@
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 5ae3fd62e5..ec3fccfc76 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -2533,6 +2533,27 @@ QStringList QCoreApplication::libraryPaths()
QStringList *app_libpaths = new QStringList;
coreappdata()->app_libpaths.reset(app_libpaths);

+ {
+ // Start at the binary; this allows us to *always* start by stripping the last part.
+ QStringList components = applicationFilePath().split(QDir::separator());
+
+ // We don't care about /nix/store/nix-support, only /nix/store/*/nix-support
+ // This is why we're checking for more than 3 parts. It will bail out once /nix/xtore/*/nix-support/qt-plugin-paths has been tested.
+ while (components.length() > 4) {
+ components.removeLast();
+ const QString support_plugin_paths = QDir::cleanPath(QDir::separator() + components.join(QDir::separator()) + QStringLiteral("/nix-support/qt-plugin-paths"));
+ if (QFile::exists(support_plugin_paths)) {
+ QFile file(support_plugin_paths);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream in(&file);
+ while (!in.atEnd()) {
+ app_libpaths->append(in.readLine());
+ }
+ }
+ }
+ }
+ }
+
// Add library paths derived from PATH
const QStringList paths = QFile::decodeName(qgetenv("PATH")).split(':');
const QString plugindir = QStringLiteral("../" NIXPKGS_QT_PLUGIN_PREFIX);
56 changes: 56 additions & 0 deletions pkgs/development/libraries/qt-5/hooks/qtbase-setup-hook.sh
Expand Up @@ -62,3 +62,59 @@ postPatchMkspecs() {
if [ -z "$dontPatchMkspecs" ]; then
postPhases="${postPhases}${postPhases:+ }postPatchMkspecs"
fi

_Qt_sortless_uniq() {
# `uniq`, but keeps initial order.
# This is to remove risks of combinatorial explosion of plugin paths.
cat -n | sort -uk2 | sort -nk1 | cut -f2-
}

_QtGetPluginPaths() {
# Lists all plugin paths for current Qt for given buildInputs and propagatedBuildInputs
local i
local _i
local o
local inputs

# FIXME : this causes output path cycles...
# I am unsure if it is even needed, though.
## Outputs self's plugins paths
#for o in $outputs; do
# o="${!o}/@qtPluginPrefix@"
# if [ -e "$o" ]; then
# echo "$o"
# fi
#done

inputs="$(
for i in $buildInputs $propagatedBuildInputs; do
echo "$i"
done | uniq
)"

for i in $inputs; do
_i="$i/@qtPluginPrefix@"
if [ -e "$_i" ]; then
echo "$_i"
fi
_i="$i/nix-support/qt-plugin-paths"
if [ -e "$_i" ]; then
cat "$_i"
fi
done
}

postAddPluginPaths() {
# Dumps all plugins paths to a nix-support file inside all outputs.
local o

for o in $outputs; do
o="${!o}/nix-support"
mkdir -p "$o"
_QtGetPluginPaths | _Qt_sortless_uniq > $o/qt-plugin-paths
done
}

if [ -z "$dontAddPluginPaths" ]; then
postPhases="${postPhases}${postPhases:+ }postAddPluginPaths"
fi
8 changes: 7 additions & 1 deletion pkgs/development/libraries/qt-5/modules/qtbase.nix
Expand Up @@ -382,7 +382,13 @@ stdenv.mkDerivation {
sed -i "$dev/lib/pkgconfig/Qt5Core.pc" \
-e "/^host_bins=/ c host_bins=$dev/bin"
''
);
)
+ ''
# Adds `qtbase-bin` as a basic dependency to *all* qtbase builds.
mkdir -p $dev/nix-support
echo "$bin/$qtPluginPrefix" >> $dev/nix-support/qt-plugin-paths
''
;

setupHook = ../hooks/qtbase-setup-hook.sh;

Expand Down

0 comments on commit b0d74d8

Please sign in to comment.