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 <joerg.bornemann@qt.io>
(cherry picked from commit 5ce44934b3cf07f4bfbf006bb4666cd481577c2c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Oliver Wolff 2025-04-08 15:26:54 +02:00 committed by Qt Cherry-pick Bot
parent 189d5ebbda
commit 95f659aeda

View File

@ -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<QString, QString>
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<QString, QString>
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) {