From b0d74d8486af62647dbe29778d6c6069cf36ea7a Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Tue, 24 Jul 2018 00:28:24 -0400 Subject: [PATCH] WIP: Loads qt plugin paths as registered... 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. --- .../libraries/qt-5/5.11/default.nix | 1 + .../qt-5/5.11/qtbase-additional.patch | 32 +++++++++++ .../libraries/qt-5/5.9/default.nix | 2 +- .../qt-5/5.9/qtbase-additional.patch | 32 +++++++++++ .../libraries/qt-5/hooks/qtbase-setup-hook.sh | 56 +++++++++++++++++++ .../libraries/qt-5/modules/qtbase.nix | 8 ++- 6 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 pkgs/development/libraries/qt-5/5.11/qtbase-additional.patch create mode 100644 pkgs/development/libraries/qt-5/5.9/qtbase-additional.patch diff --git a/pkgs/development/libraries/qt-5/5.11/default.nix b/pkgs/development/libraries/qt-5/5.11/default.nix index b50ff61219fd4..2e462029afba2 100644 --- a/pkgs/development/libraries/qt-5/5.11/default.nix +++ b/pkgs/development/libraries/qt-5/5.11/default.nix @@ -39,6 +39,7 @@ let patches = { qtbase = [ ./qtbase.patch + ./qtbase-additional.patch ./qtbase-darwin.patch ./qtbase-revert-no-macos10.10.patch ]; diff --git a/pkgs/development/libraries/qt-5/5.11/qtbase-additional.patch b/pkgs/development/libraries/qt-5/5.11/qtbase-additional.patch new file mode 100644 index 0000000000000..5cd8cbef93452 --- /dev/null +++ b/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); diff --git a/pkgs/development/libraries/qt-5/5.9/default.nix b/pkgs/development/libraries/qt-5/5.9/default.nix index e109fe447aa23..0c5878f256132 100644 --- a/pkgs/development/libraries/qt-5/5.9/default.nix +++ b/pkgs/development/libraries/qt-5/5.9/default.nix @@ -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 ]; diff --git a/pkgs/development/libraries/qt-5/5.9/qtbase-additional.patch b/pkgs/development/libraries/qt-5/5.9/qtbase-additional.patch new file mode 100644 index 0000000000000..5cd8cbef93452 --- /dev/null +++ b/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); diff --git a/pkgs/development/libraries/qt-5/hooks/qtbase-setup-hook.sh b/pkgs/development/libraries/qt-5/hooks/qtbase-setup-hook.sh index 3a558153988c3..10553ba30ba39 100644 --- a/pkgs/development/libraries/qt-5/hooks/qtbase-setup-hook.sh +++ b/pkgs/development/libraries/qt-5/hooks/qtbase-setup-hook.sh @@ -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 diff --git a/pkgs/development/libraries/qt-5/modules/qtbase.nix b/pkgs/development/libraries/qt-5/modules/qtbase.nix index 15e19c77567a0..dde5c8feb571d 100644 --- a/pkgs/development/libraries/qt-5/modules/qtbase.nix +++ b/pkgs/development/libraries/qt-5/modules/qtbase.nix @@ -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;