From 95f659aedab4c063d5bd3d8fdd10a9ca9c4f489d Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Tue, 8 Apr 2025 15:26:54 +0200 Subject: [PATCH] windeployqt: Deploy Qt dependencies of local non Qt dependencies Before this patch we ignored every non Qt dependency we encountered while scannig the binaries. That led to missing Qt dependencies for more complex setups. With this patch we also take "local non Qt dependencies" into consideration. One example would be: - A developer has a project that consists of an executable and a dll, where both are built/copied into the same folder before deployment - The dll has different/additional Qt dependencies The old approach just ignored these additional Qt dependencies. The new approach checks for these local dependencies and finds the dll in the same folder as the executable. In this case windeployqt will now also scan this dll (and other local dlls) for Qt dependencies and deploy these as well as their plugins. [ChangeLog][Tools][Windeployqt] windeployqt now takes local non Qt dependencies into consideration during deployment. Fixes: QTBUG-135079 Pick-to: 6.8 Change-Id: Ia916dea78c6a5707ccecb61d996a0b7490215798 Reviewed-by: Joerg Bornemann (cherry picked from commit 5ce44934b3cf07f4bfbf006bb4666cd481577c2c) Reviewed-by: Qt Cherry-pick Bot --- src/tools/windeployqt/main.cpp | 48 +++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp index ddec54041dd..afd099403fc 100644 --- a/src/tools/windeployqt/main.cpp +++ b/src/tools/windeployqt/main.cpp @@ -806,8 +806,9 @@ static inline bool isQtModule(const QString &libName) } // Helper for recursively finding all dependent Qt libraries. -static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary, Platform platform, - QString *errorMessage, QStringList *result, +static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary, + Platform platform, QString *errorMessage, + QStringList *qtDependencies, QStringList *nonQtDependencies, unsigned *wordSize = nullptr, bool *isDebug = nullptr, unsigned short *machineArch = nullptr, int *directDependencyCount = nullptr, int recursionDepth = 0) @@ -823,20 +824,23 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin } // Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we // are run the 2nd time (updating). We want to check against the Qt bin dir libraries - const int start = result->size(); + const int start = qtDependencies->size(); for (const QString &lib : std::as_const(dependentLibs)) { if (isQtModule(lib)) { const QString path = normalizeFileName(qtBinDir + u'/' + QFileInfo(lib).fileName()); - if (!result->contains(path)) - result->append(path); + if (!qtDependencies->contains(path)) + qtDependencies->append(path); + } else if (nonQtDependencies && !nonQtDependencies->contains(lib)) { + nonQtDependencies->append(lib); } } - const int end = result->size(); + const int end = qtDependencies->size(); if (directDependencyCount) *directDependencyCount = end - start; // Recurse for (int i = start; i < end; ++i) - if (!findDependentQtLibraries(qtBinDir, result->at(i), platform, errorMessage, result, + if (!findDependentQtLibraries(qtBinDir, qtDependencies->at(i), platform, errorMessage, + qtDependencies, nonQtDependencies, nullptr, nullptr, nullptr, nullptr, recursionDepth + 1)) return false; return true; @@ -1030,7 +1034,7 @@ static QString deployPlugin(const QString &plugin, const QDir &subDir, const boo QStringList dependentQtLibs; QString errorMessage; if (findDependentQtLibraries(libraryLocation, pluginPath, platform, - &errorMessage, &dependentQtLibs)) { + &errorMessage, &dependentQtLibs, nullptr)) { for (int d = 0; d < dependentQtLibs.size(); ++d) { const qint64 module = qtModule(dependentQtLibs.at(d), infix); if (module >= 0) @@ -1474,17 +1478,37 @@ static DeployResult deploy(const Options &options, const QMap std::wcout << "Qt binaries in " << QDir::toNativeSeparators(qtBinDir) << '\n'; QStringList dependentQtLibs; + QStringList dependentNonQtLibs; bool detectedDebug; unsigned wordSize; unsigned short machineArch; int directDependencyCount = 0; - if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform, errorMessage, &dependentQtLibs, &wordSize, + if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform, + errorMessage, &dependentQtLibs, &dependentNonQtLibs, &wordSize, &detectedDebug, &machineArch, &directDependencyCount)) { return result; } for (int b = 1; b < options.binaries.size(); ++b) { - if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform, errorMessage, &dependentQtLibs, - nullptr, nullptr, nullptr)) { + if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform, + errorMessage, &dependentQtLibs, &dependentNonQtLibs, + nullptr, nullptr, nullptr, nullptr)) { + return result; + } + } + + // Also check Qt dependencies of "local non Qt dependencies" (dlls located in the same folder) + for (const QString &nonQtLib : dependentNonQtLibs) { + const QFileInfo fi(options.binaries.first()); + const QString path = fi.canonicalPath() + u'/' + nonQtLib; + if (!QFileInfo::exists(path)) + continue; + + if (optVerboseLevel) + std::wcout << "Adding local dependency" << path << '\n'; + + if (!findDependentQtLibraries(libraryLocation, path, options.platform, + errorMessage, &dependentQtLibs, &dependentNonQtLibs, + nullptr, nullptr, nullptr, nullptr)) { return result; } } @@ -1603,7 +1627,7 @@ static DeployResult deploy(const Options &options, const QMap qmlScanResult.append(scanResult); // Additional dependencies of QML plugins. for (const QString &plugin : std::as_const(qmlScanResult.plugins)) { - if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &detectedDebug, &machineArch)) + if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, nullptr, &wordSize, &detectedDebug, &machineArch)) return result; } if (optVerboseLevel >= 1) {