windeployqt: replace enum with bitset

we are running out of enum values for the flags.

Pick-to: 6.4
Change-Id: Idd7cabb0c46c0c95eb4a87d047defb15ddeef024
Reviewed-by: Timothée Keller <timothee.keller@qt.io>
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Oliver Wolff 2022-11-02 15:26:15 +01:00
parent a0110f3819
commit ac0cf6a5cc

View File

@ -24,6 +24,7 @@
#include <QtCore/private/qconfig_p.h> #include <QtCore/private/qconfig_p.h>
#include <bitset>
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
@ -33,73 +34,75 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
using ModuleBitset = std::bitset<62>;
enum QtModule enum QtModule
#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) #if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC)
: quint64 : quint64
#endif #endif
{ {
QtBluetoothModule = 0x0000000000000001, QtBluetoothModule,
QtConcurrentModule = 0x0000000000000002, QtConcurrentModule,
QtCoreModule = 0x0000000000000004, QtCoreModule,
QtDeclarativeModule = 0x0000000000000008, QtDeclarativeModule,
QtDesignerComponents = 0x0000000000000010, QtDesignerComponents,
QtDesignerModule = 0x0000000000000020, QtDesignerModule,
QtGuiModule = 0x0000000000000040, QtGuiModule,
QtHelpModule = 0x0000000000000080, QtHelpModule,
QtMultimediaModule = 0x0000000000000100, QtMultimediaModule,
QtMultimediaWidgetsModule = 0x0000000000000200, QtMultimediaWidgetsModule,
QtMultimediaQuickModule = 0x0000000000000400, QtMultimediaQuickModule,
QtNetworkModule = 0x0000000000000800, QtNetworkModule,
QtNfcModule = 0x0000000000001000, QtNfcModule,
QtOpenGLModule = 0x0000000000002000, QtOpenGLModule,
QtOpenGLWidgetsModule = 0x0000000000004000, QtOpenGLWidgetsModule,
QtPositioningModule = 0x0000000000008000, QtPositioningModule,
QtPrintSupportModule = 0x0000000000010000, QtPrintSupportModule,
QtQmlModule = 0x0000000000020000, QtQmlModule,
QtQuickModule = 0x0000000000040000, QtQuickModule,
QtQuickParticlesModule = 0x0000000000080000, QtQuickParticlesModule,
QtScriptModule = 0x0000000000100000, QtScriptModule,
QtScriptToolsModule = 0x0000000000200000, QtScriptToolsModule,
QtSensorsModule = 0x0000000000400000, QtSensorsModule,
QtSerialPortModule = 0x0000000000800000, QtSerialPortModule,
QtSqlModule = 0x0000000001000000, QtSqlModule,
QtSvgModule = 0x0000000002000000, QtSvgModule,
QtSvgWidgetsModule = 0x0000000004000000, QtSvgWidgetsModule,
QtTestModule = 0x0000000008000000, QtTestModule,
QtWidgetsModule = 0x0000000010000000, QtWidgetsModule,
QtWinExtrasModule = 0x0000000020000000, QtWinExtrasModule,
QtXmlModule = 0x0000000040000000, QtXmlModule,
QtQuickWidgetsModule = 0x0000000100000000, QtQuickWidgetsModule,
QtWebSocketsModule = 0x0000000200000000, QtWebSocketsModule,
QtWebEngineCoreModule = 0x0000000800000000, QtWebEngineCoreModule,
QtWebEngineModule = 0x0000001000000000, QtWebEngineModule,
QtWebEngineWidgetsModule = 0x0000002000000000, QtWebEngineWidgetsModule,
QtQmlToolingModule = 0x0000004000000000, QtQmlToolingModule,
Qt3DCoreModule = 0x0000008000000000, Qt3DCoreModule,
Qt3DRendererModule = 0x0000010000000000, Qt3DRendererModule,
Qt3DQuickModule = 0x0000020000000000, Qt3DQuickModule,
Qt3DQuickRendererModule = 0x0000040000000000, Qt3DQuickRendererModule,
Qt3DInputModule = 0x0000080000000000, Qt3DInputModule,
QtLocationModule = 0x0000100000000000, QtLocationModule,
QtWebChannelModule = 0x0000200000000000, QtWebChannelModule,
QtTextToSpeechModule = 0x0000400000000000, QtTextToSpeechModule,
QtSerialBusModule = 0x0000800000000000, QtSerialBusModule,
QtGamePadModule = 0x0001000000000000, QtGamePadModule,
Qt3DAnimationModule = 0x0002000000000000, Qt3DAnimationModule,
QtWebViewModule = 0x0004000000000000, QtWebViewModule,
Qt3DExtrasModule = 0x0008000000000000, Qt3DExtrasModule,
QtShaderToolsModule = 0x0010000000000000, QtShaderToolsModule,
QtUiToolsModule = 0x0020000000000000, QtUiToolsModule,
QtCore5CompatModule = 0x0040000000000000, QtCore5CompatModule,
QtChartsModule = 0x0080000000000000, QtChartsModule,
QtDataVisualizationModule = 0x0100000000000000, QtDataVisualizationModule,
QtRemoteObjectsModule = 0x0200000000000000, QtRemoteObjectsModule,
QtScxmlModule = 0x0400000000000000, QtScxmlModule,
QtNetworkAuthorizationModule = 0x0800000000000000, QtNetworkAuthorizationModule,
QtMqttModule = 0x1000000000000000, QtMqttModule,
QtPdfModule = 0x2000000000000000, QtPdfModule,
QtPdfQuickModule = 0x4000000000000000, QtPdfQuickModule,
QtPdfWidgetsModule = 0x8000000000000000 QtPdfWidgetsModule
}; };
struct QtModuleEntry { struct QtModuleEntry {
@ -186,11 +189,11 @@ static inline QString webProcessBinary(const char *binaryName, Platform p)
return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess; return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess;
} }
static QByteArray formatQtModules(quint64 mask, bool option = false) static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
{ {
QByteArray result; QByteArray result;
for (const auto &qtModule : qtModuleEntries) { for (const auto &qtModule : qtModuleEntries) {
if (mask & qtModule.module) { if (mask.test(qtModule.module)) {
if (!result.isEmpty()) if (!result.isEmpty())
result.append(' '); result.append(' ');
result.append(option ? qtModule.option : qtModule.libraryName); result.append(option ? qtModule.option : qtModule.libraryName);
@ -253,8 +256,8 @@ struct Options {
unsigned disabledPlugins = 0; unsigned disabledPlugins = 0;
bool softwareRasterizer = true; bool softwareRasterizer = true;
Platform platform = WindowsDesktopMsvc; Platform platform = WindowsDesktopMsvc;
quint64 additionalLibraries = 0; ModuleBitset additionalLibraries;
quint64 disabledLibraries = 0; ModuleBitset disabledLibraries;
unsigned updateFileFlags = 0; unsigned updateFileFlags = 0;
QStringList qmlDirectories; // Project's QML files. QStringList qmlDirectories; // Project's QML files.
QStringList qmlImportPaths; // Custom QML module locations. QStringList qmlImportPaths; // Custom QML module locations.
@ -538,16 +541,16 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (int i = 0; i < qtModulesCount; ++i) { for (int i = 0; i < qtModulesCount; ++i) {
if (parser->isSet(*enabledModuleOptions.at(i))) if (parser->isSet(*enabledModuleOptions.at(i)))
options->additionalLibraries |= qtModuleEntries[i].module; options->additionalLibraries[qtModuleEntries[i].module] = 1;
if (parser->isSet(*disabledModuleOptions.at(i))) if (parser->isSet(*disabledModuleOptions.at(i)))
options->disabledLibraries |= qtModuleEntries[i].module; options->disabledLibraries[qtModuleEntries[i].module] = 1;
} }
// Add some dependencies // Add some dependencies
if (options->additionalLibraries & QtQuickModule) if (options->additionalLibraries.test(QtQuickModule))
options->additionalLibraries |= QtQmlModule; options->additionalLibraries[QtQmlModule] = 1;
if (options->additionalLibraries & QtDesignerComponents) if (options->additionalLibraries.test(QtDesignerComponents))
options->additionalLibraries |= QtDesignerModule; options->additionalLibraries[QtDesignerModule] = 1;
if (parser->isSet(listOption)) { if (parser->isSet(listOption)) {
const QString value = parser->value(listOption); const QString value = parser->value(listOption);
@ -907,7 +910,7 @@ static quint64 qtModule(QString module, const QString &infix)
// Return the path if a plugin is to be deployed // Return the path if a plugin is to be deployed
static QString deployPlugin(const QString &plugin, const QDir &subDir, static QString deployPlugin(const QString &plugin, const QDir &subDir,
quint64 *usedQtModules, quint64 disabledQtModules, ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
unsigned disabledPlugins, unsigned disabledPlugins,
const QString &libraryLocation, const QString &infix, const QString &libraryLocation, const QString &infix,
Platform platform) Platform platform)
@ -926,18 +929,20 @@ static QString deployPlugin(const QString &plugin, const QDir &subDir,
return pluginPath; return pluginPath;
QStringList dependentQtLibs; QStringList dependentQtLibs;
quint64 neededModules = 0; ModuleBitset neededModules;
QString errorMessage; QString errorMessage;
if (findDependentQtLibraries(libraryLocation, pluginPath, platform, if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
&errorMessage, &dependentQtLibs)) { &errorMessage, &dependentQtLibs)) {
for (int d = 0; d < dependentQtLibs.size(); ++ d) for (int d = 0; d < dependentQtLibs.size(); ++ d)
neededModules |= qtModule(dependentQtLibs.at(d), infix); neededModules[qtModule(dependentQtLibs.at(d), infix)] = 1;
} else { } else {
std::wcerr << "Warning: Cannot determine dependencies of " std::wcerr << "Warning: Cannot determine dependencies of "
<< QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n'; << QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
} }
if (const quint64 missingModules = neededModules & disabledQtModules) { ModuleBitset missingModules;
missingModules = neededModules & disabledQtModules;
if (missingModules.any()) {
if (optVerboseLevel) { if (optVerboseLevel) {
std::wcout << "Skipping plugin " << plugin std::wcout << "Skipping plugin " << plugin
<< " due to disabled dependencies (" << " due to disabled dependencies ("
@ -946,7 +951,8 @@ static QString deployPlugin(const QString &plugin, const QDir &subDir,
return {}; return {};
} }
if (const quint64 missingModules = (neededModules & ~*usedQtModules)) { missingModules = (neededModules & ~*usedQtModules);
if (missingModules.any()) {
*usedQtModules |= missingModules; *usedQtModules |= missingModules;
if (optVerboseLevel) { if (optVerboseLevel) {
std::wcout << "Adding " << formatQtModules(missingModules).constData() std::wcout << "Adding " << formatQtModules(missingModules).constData()
@ -956,7 +962,7 @@ static QString deployPlugin(const QString &plugin, const QDir &subDir,
return pluginPath; return pluginPath;
} }
QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules, QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
unsigned disabledPlugins, unsigned disabledPlugins,
const QString &qtPluginsDirName, const QString &libraryLocation, const QString &qtPluginsDirName, const QString &libraryLocation,
const QString &infix, const QString &infix,
@ -970,7 +976,7 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules,
for (const QFileInfo &subDirFi : pluginDirs) { for (const QFileInfo &subDirFi : pluginDirs) {
const QString subDirName = subDirFi.fileName(); const QString subDirName = subDirFi.fileName();
const quint64 module = qtModuleForPlugin(subDirName); const quint64 module = qtModuleForPlugin(subDirName);
if (module & *usedQtModules) { if (usedQtModules->test(module)) {
const DebugMatchMode debugMatchMode = (module & QtWebEngineCoreModule) const DebugMatchMode debugMatchMode = (module & QtWebEngineCoreModule)
? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all. ? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all.
: debugMatchModeIn; : debugMatchModeIn;
@ -978,7 +984,7 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules,
// Filter out disabled plugins // Filter out disabled plugins
if ((disabledPlugins & QtVirtualKeyboardPlugin) && subDirName == "virtualkeyboard"_L1) if ((disabledPlugins & QtVirtualKeyboardPlugin) && subDirName == "virtualkeyboard"_L1)
continue; continue;
if (disabledQtModules & QtQmlToolingModule && subDirName == "qmltooling"_L1) if (disabledQtModules.test(QtQmlToolingModule) && subDirName == "qmltooling"_L1)
continue; continue;
// Filter for platform or any. // Filter for platform or any.
QString filter; QString filter;
@ -1014,11 +1020,11 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules,
return result; return result;
} }
static QStringList translationNameFilters(quint64 modules, const QString &prefix) static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
{ {
QStringList result; QStringList result;
for (const auto &qtModule : qtModuleEntries) { for (const auto &qtModule : qtModuleEntries) {
if ((qtModule.module & modules) && qtModule.translation) { if (modules.test(qtModule.module) && qtModule.translation) {
const QString name = QLatin1StringView(qtModule.translation) + const QString name = QLatin1StringView(qtModule.translation) +
u'_' + prefix + ".qm"_L1; u'_' + prefix + ".qm"_L1;
if (!result.contains(name)) if (!result.contains(name))
@ -1028,7 +1034,7 @@ static QStringList translationNameFilters(quint64 modules, const QString &prefix
return result; return result;
} }
static bool deployTranslations(const QString &sourcePath, quint64 usedQtModules, static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules,
const QString &target, const Options &options, const QString &target, const Options &options,
QString *errorMessage) QString *errorMessage)
{ {
@ -1086,9 +1092,9 @@ struct DeployResult
bool success = false; bool success = false;
bool isDebug = false; bool isDebug = false;
quint64 directlyUsedQtLibraries = 0; ModuleBitset directlyUsedQtLibraries;
quint64 usedQtLibraries = 0; ModuleBitset usedQtLibraries;
quint64 deployedQtLibraries = 0; ModuleBitset deployedQtLibraries;
}; };
static QString libraryPath(const QString &libraryLocation, const char *name, static QString libraryPath(const QString &libraryLocation, const char *name,
@ -1325,14 +1331,16 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
QString qtLibInfix; QString qtLibInfix;
for (int m = 0; m < directDependencyCount; ++m) { for (int m = 0; m < directDependencyCount; ++m) {
const quint64 module = qtModule(dependentQtLibs.at(m), infix); const quint64 module = qtModule(dependentQtLibs.at(m), infix);
result.directlyUsedQtLibraries |= module; result.directlyUsedQtLibraries[module] = 1;
if (module == QtCoreModule) if (module == QtCoreModule)
qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform); qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform);
} }
const bool usesQml2 = !(options.disabledLibraries & QtQmlModule) const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModule);
&& ((result.directlyUsedQtLibraries & (QtQmlModule | QtQuickModule | Qt3DQuickModule)) const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModule);
|| (options.additionalLibraries & QtQmlModule)); const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModule);
const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModule))
&& (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModule)));
if (optVerboseLevel) { if (optVerboseLevel) {
std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' ' std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' '
@ -1406,7 +1414,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n"; std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
const QmlImportScanResult scanResult = const QmlImportScanResult scanResult =
runQmlImportScanner(qmlDirectory, qmlImportPaths, runQmlImportScanner(qmlDirectory, qmlImportPaths,
result.directlyUsedQtLibraries & QtWidgetsModule, result.directlyUsedQtLibraries.test(QtWidgetsModule),
options.platform, debugMatchMode, errorMessage); options.platform, debugMatchMode, errorMessage);
if (!scanResult.ok) if (!scanResult.ok)
return result; return result;
@ -1437,24 +1445,29 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
QStringList deployedQtLibraries; QStringList deployedQtLibraries;
for (int i = 0 ; i < dependentQtLibs.size(); ++i) { for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
if (const quint64 qtm = qtModule(dependentQtLibs.at(i), infix)) if (const quint64 qtm = qtModule(dependentQtLibs.at(i), infix))
result.usedQtLibraries |= qtm; result.usedQtLibraries[qtm] = 1;
else else
deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag. deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
} }
result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries; result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
ModuleBitset disabled = options.disabledLibraries;
if (!usesQml2) {
disabled[QtQmlModule] = 1;
disabled[QtQuickModule] = 1;
}
const QStringList plugins = findQtPlugins( const QStringList plugins = findQtPlugins(
&result.deployedQtLibraries, &result.deployedQtLibraries,
// For non-QML applications, disable QML to prevent it from being pulled in by the // For non-QML applications, disable QML to prevent it from being pulled in by the
// qtaccessiblequick plugin. // qtaccessiblequick plugin.
options.disabledLibraries | (usesQml2 ? 0 : (QtQmlModule | QtQuickModule)), disabled,
options.disabledPlugins, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")), options.disabledPlugins, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin); libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin);
// Apply options flags and re-add library names. // Apply options flags and re-add library names.
QString qtGuiLibrary; QString qtGuiLibrary;
for (const auto &qtModule : qtModuleEntries) { for (const auto &qtModule : qtModuleEntries) {
if (result.deployedQtLibraries & qtModule.module) { if (result.deployedQtLibraries.test(qtModule.module)) {
const QString library = libraryPath(libraryLocation, qtModule.libraryName, qtLibInfix, options.platform, result.isDebug); const QString library = libraryPath(libraryLocation, qtModule.libraryName, qtLibInfix, options.platform, result.isDebug);
deployedQtLibraries.append(library); deployedQtLibraries.append(library);
if (qtModule.module == QtGuiModule) if (qtModule.module == QtGuiModule)
@ -1463,15 +1476,15 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
} }
if (optVerboseLevel >= 1) { if (optVerboseLevel >= 1) {
std::wcout << "Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData() std::wcout << "Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries.to_ullong()).constData()
<< "\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData() << "\nAll dependencies : " << formatQtModules(result.usedQtLibraries.to_ullong()).constData()
<< "\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() << '\n'; << "\nTo be deployed : " << formatQtModules(result.deployedQtLibraries.to_ullong()).constData() << '\n';
} }
if (optVerboseLevel > 1) if (optVerboseLevel > 1)
std::wcout << "Plugins: " << plugins.join(u',') << '\n'; std::wcout << "Plugins: " << plugins.join(u',') << '\n';
if ((result.deployedQtLibraries & QtGuiModule) && platformPlugin.isEmpty()) { if ((result.deployedQtLibraries.test(QtGuiModule)) && platformPlugin.isEmpty()) {
*errorMessage =QStringLiteral("Unable to find the platform plugin."); *errorMessage =QStringLiteral("Unable to find the platform plugin.");
return result; return result;
} }
@ -1545,7 +1558,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
} // optPlugins } // optPlugins
// Update Quick imports // Update Quick imports
const bool usesQuick1 = result.deployedQtLibraries & QtDeclarativeModule; const bool usesQuick1 = result.deployedQtLibraries.test(QtDeclarativeModule);
// Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports // Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
// for WebKit1-applications. Check direct dependency only. // for WebKit1-applications. Check direct dependency only.
if (options.quickImports && (usesQuick1 || usesQml2)) { if (options.quickImports && (usesQuick1 || usesQml2)) {
@ -1733,7 +1746,7 @@ int main(int argc, char **argv)
return 1; return 1;
} }
if (result.deployedQtLibraries & QtWebEngineCoreModule) { if (result.deployedQtLibraries.test(QtWebEngineCoreModule)) {
if (!deployWebEngineCore(qtpathsVariables, options, result.isDebug, &errorMessage)) { if (!deployWebEngineCore(qtpathsVariables, options, result.isDebug, &errorMessage)) {
std::wcerr << errorMessage << '\n'; std::wcerr << errorMessage << '\n';
return 1; return 1;