summaryrefslogtreecommitdiffstats
path: root/src/tools/windeployqt/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/windeployqt/main.cpp')
-rw-r--r--src/tools/windeployqt/main.cpp1212
1 files changed, 725 insertions, 487 deletions
diff --git a/src/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp
index 8a4263b6d0..dca9132e15 100644
--- a/src/tools/windeployqt/main.cpp
+++ b/src/tools/windeployqt/main.cpp
@@ -3,6 +3,8 @@
#include "utils.h"
#include "qmlutils.h"
+#include "qtmoduleinfo.h"
+#include "qtplugininfo.h"
#include <QtCore/QCommandLineOption>
#include <QtCore/QCommandLineParser>
@@ -24,187 +26,59 @@
#include <QtCore/private/qconfig_p.h>
-#include <bitset>
#include <algorithm>
+#include <cstdio>
#include <iostream>
#include <iterator>
-#include <cstdio>
+#include <unordered_map>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-using ModuleBitset = std::bitset<77>;
+static QtModuleInfoStore qtModuleEntries;
-enum QtModule
-{
- QtBluetoothModule,
- QtConcurrentModule,
- QtCoreModule,
- QtDesignerComponents,
- QtDesignerModule,
- QtGuiModule,
- QtHelpModule,
- QtMultimediaModule,
- QtMultimediaWidgetsModule,
- QtMultimediaQuickModule,
- QtNetworkModule,
- QtNfcModule,
- QtOpenGLModule,
- QtOpenGLWidgetsModule,
- QtPositioningModule,
- QtPrintSupportModule,
- QtQmlModule,
- QtQuickModule,
- QtQuickParticlesModule,
- QtScriptModule,
- QtScriptToolsModule,
- QtSensorsModule,
- QtSerialPortModule,
- QtSqlModule,
- QtSvgModule,
- QtSvgWidgetsModule,
- QtTestModule,
- QtWidgetsModule,
- QtWinExtrasModule,
- QtXmlModule,
- QtQuickWidgetsModule,
- QtWebSocketsModule,
- QtWebEngineCoreModule,
- QtWebEngineModule,
- QtWebEngineWidgetsModule,
- QtQmlToolingModule,
- Qt3DCoreModule,
- Qt3DRendererModule,
- Qt3DQuickModule,
- Qt3DQuickRendererModule,
- Qt3DInputModule,
- QtLocationModule,
- QtWebChannelModule,
- QtTextToSpeechModule,
- QtSerialBusModule,
- QtGamePadModule,
- Qt3DAnimationModule,
- QtWebViewModule,
- Qt3DExtrasModule,
- QtShaderToolsModule,
- QtUiToolsModule,
- QtCore5CompatModule,
- QtChartsModule,
- QtDataVisualizationModule,
- QtRemoteObjectsModule,
- QtScxmlModule,
- QtNetworkAuthorizationModule,
- QtMqttModule,
- QtPdfModule,
- QtPdfQuickModule,
- QtPdfWidgetsModule,
- QtDBusModule,
- QtStateMachineModule,
- Qt3DLogicModule,
- QtPositioningQuickModule,
- QtSensorsQuickModule,
- QtWebEngineQuickModule,
- QtWebViewQuickModule,
- QtQuickControlsModule,
- QtQuickDialogsModule,
- QtQuickLayoutsModule,
- QtQuickShapesModule,
- QtQuickTestModule,
- QtQuickTimelineModule,
- QtQuick3DModule,
- QtOpcUaModule
-};
+#define DECLARE_KNOWN_MODULE(name) \
+ static size_t Qt##name ## ModuleId = QtModule::InvalidId
-struct QtModuleEntry {
- quint64 module;
- const char *option;
- const char *libraryName;
- const char *translation;
-};
+DECLARE_KNOWN_MODULE(3DQuick);
+DECLARE_KNOWN_MODULE(Core);
+DECLARE_KNOWN_MODULE(Designer);
+DECLARE_KNOWN_MODULE(DesignerComponents);
+DECLARE_KNOWN_MODULE(Gui);
+DECLARE_KNOWN_MODULE(Qml);
+DECLARE_KNOWN_MODULE(QmlTooling);
+DECLARE_KNOWN_MODULE(Quick);
+DECLARE_KNOWN_MODULE(WebEngineCore);
+DECLARE_KNOWN_MODULE(Widgets);
-static QtModuleEntry qtModuleEntries[] = {
- { QtBluetoothModule, "bluetooth", "Qt6Bluetooth", nullptr },
- { QtConcurrentModule, "concurrent", "Qt6Concurrent", "qtbase" },
- { QtCoreModule, "core", "Qt6Core", "qtbase" },
- { QtDesignerModule, "designer", "Qt6Designer", nullptr },
- { QtDesignerComponents, "designercomponents", "Qt6DesignerComponents", nullptr },
- { QtGamePadModule, "gamepad", "Qt6Gamepad", nullptr },
- { QtGuiModule, "gui", "Qt6Gui", "qtbase" },
- { QtHelpModule, "qthelp", "Qt6Help", "qt_help" },
- { QtMultimediaModule, "multimedia", "Qt6Multimedia", "qtmultimedia" },
- { QtMultimediaWidgetsModule, "multimediawidgets", "Qt6MultimediaWidgets", "qtmultimedia" },
- { QtMultimediaQuickModule, "multimediaquick", "Qt6MultimediaQuick_p", "qtmultimedia" },
- { QtNetworkModule, "network", "Qt6Network", "qtbase" },
- { QtNfcModule, "nfc", "Qt6Nfc", nullptr },
- { QtOpenGLModule, "opengl", "Qt6OpenGL", nullptr },
- { QtOpenGLWidgetsModule, "openglwidgets", "Qt6OpenGLWidgets", nullptr },
- { QtPositioningModule, "positioning", "Qt6Positioning", nullptr },
- { QtPrintSupportModule, "printsupport", "Qt6PrintSupport", nullptr },
- { QtQmlModule, "qml", "Qt6Qml", "qtdeclarative" },
- { QtQmlToolingModule, "qmltooling", "qmltooling", nullptr },
- { QtQuickModule, "quick", "Qt6Quick", "qtdeclarative" },
- { QtQuickParticlesModule, "quickparticles", "Qt6QuickParticles", nullptr },
- { QtQuickWidgetsModule, "quickwidgets", "Qt6QuickWidgets", nullptr },
- { QtScriptModule, "script", "Qt6Script", "qtscript" },
- { QtScriptToolsModule, "scripttools", "Qt6ScriptTools", "qtscript" },
- { QtSensorsModule, "sensors", "Qt6Sensors", nullptr },
- { QtSerialPortModule, "serialport", "Qt6SerialPort", "qtserialport" },
- { QtSqlModule, "sql", "Qt6Sql", "qtbase" },
- { QtSvgModule, "svg", "Qt6Svg", nullptr },
- { QtSvgWidgetsModule, "svgwidgets", "Qt6SvgWidgets", nullptr },
- { QtTestModule, "test", "Qt6Test", "qtbase" },
- { QtWebSocketsModule, "websockets", "Qt6WebSockets", nullptr },
- { QtWidgetsModule, "widgets", "Qt6Widgets", "qtbase" },
- { QtWinExtrasModule, "winextras", "Qt6WinExtras", nullptr },
- { QtXmlModule, "xml", "Qt6Xml", "qtbase" },
- { QtWebEngineCoreModule, "webenginecore", "Qt6WebEngineCore", nullptr },
- { QtWebEngineModule, "webengine", "Qt6WebEngine", "qtwebengine" },
- { QtWebEngineWidgetsModule, "webenginewidgets", "Qt6WebEngineWidgets", nullptr },
- { Qt3DCoreModule, "3dcore", "Qt63DCore", nullptr },
- { Qt3DRendererModule, "3drenderer", "Qt63DRender", nullptr },
- { Qt3DQuickModule, "3dquick", "Qt63DQuick", nullptr },
- { Qt3DQuickRendererModule, "3dquickrenderer", "Qt63DQuickRender", nullptr },
- { Qt3DInputModule, "3dinput", "Qt63DInput", nullptr },
- { Qt3DAnimationModule, "3danimation", "Qt63DAnimation", nullptr },
- { Qt3DExtrasModule, "3dextras", "Qt63DExtras", nullptr },
- { QtLocationModule, "geoservices", "Qt6Location", nullptr },
- { QtWebChannelModule, "webchannel", "Qt6WebChannel", nullptr },
- { QtTextToSpeechModule, "texttospeech", "Qt6TextToSpeech", nullptr },
- { QtSerialBusModule, "serialbus", "Qt6SerialBus", nullptr },
- { QtWebViewModule, "webview", "Qt6WebView", nullptr },
- { QtShaderToolsModule, "shadertools", "Qt6ShaderTools", nullptr },
- { QtUiToolsModule, "uitools", "Qt6UiTools", nullptr },
- { QtCore5CompatModule, "core5compat", "Qt6Core5Compat", nullptr },
- { QtChartsModule, "charts", "Qt6Charts", nullptr },
- { QtDataVisualizationModule, "datavisualization", "Qt6DataVisualization", nullptr },
- { QtRemoteObjectsModule, "remoteobjects", "Qt6RemoteObjects", nullptr },
- { QtScxmlModule, "scxml", "Qt6Scxml", nullptr },
- { QtNetworkAuthorizationModule, "networkauthorization", "Qt6NetworkAuth", nullptr },
- { QtMqttModule, "mqtt", "Qt6Mqtt", nullptr },
- { QtPdfModule, "pdf", "Qt6Pdf", nullptr },
- { QtPdfQuickModule, "pdfquick", "Qt6PdfQuick", nullptr },
- { QtPdfWidgetsModule, "pdfwidgets", "Qt6PdfWidgets", nullptr },
- { QtDBusModule, "dbus", "Qt6DBus", nullptr },
- { QtStateMachineModule, "statemachine", "Qt6StateMachine", nullptr },
- { Qt3DLogicModule, "3dlogic", "Qt63DLogic", nullptr },
- { QtPositioningQuickModule, "positioningquick", "Qt6PositioningQuick", nullptr },
- { QtSensorsQuickModule, "sensorsquick", "Qt6SensorsQuick", nullptr },
- { QtWebEngineQuickModule, "webenginequick", "Qt6WebEngineQuick", nullptr },
- { QtWebViewQuickModule, "webviewquick", "Qt6WebViewQuick", nullptr },
- { QtQuickControlsModule, "quickcontrols", "Qt6QuickControls2", nullptr },
- { QtQuickDialogsModule, "quickdialogs", "Qt6QuickDialogs2", nullptr },
- { QtQuickLayoutsModule, "quicklayouts", "Qt6QuickLayouts", nullptr },
- { QtQuickShapesModule, "quickshapes", "Qt6QuickShapes", nullptr },
- { QtQuickTestModule, "quicktest", "Qt6QuickTest", nullptr },
- { QtQuickTimelineModule, "quicktimeline", "Qt6QuickTimeline", nullptr },
- { QtQuick3DModule, "quick3d", "Qt6Quick3D", nullptr },
- { QtOpcUaModule, "opcua", "Qt6OpcUa", nullptr }
-};
+#define DEFINE_KNOWN_MODULE(name) \
+ m[QLatin1String("Qt6" #name)] = &Qt##name ## ModuleId
-enum QtPlugin {
- QtVirtualKeyboardPlugin = 0x1
-};
+static void assignKnownModuleIds()
+{
+ std::unordered_map<QString, size_t *> m;
+ DEFINE_KNOWN_MODULE(3DQuick);
+ DEFINE_KNOWN_MODULE(Core);
+ DEFINE_KNOWN_MODULE(Designer);
+ DEFINE_KNOWN_MODULE(DesignerComponents);
+ DEFINE_KNOWN_MODULE(Gui);
+ DEFINE_KNOWN_MODULE(Qml);
+ DEFINE_KNOWN_MODULE(QmlTooling);
+ DEFINE_KNOWN_MODULE(Quick);
+ DEFINE_KNOWN_MODULE(WebEngineCore);
+ DEFINE_KNOWN_MODULE(Widgets);
+ for (size_t i = 0; i < qtModuleEntries.size(); ++i) {
+ const QtModule &module = qtModuleEntries.moduleById(i);
+ auto it = m.find(module.name);
+ if (it == m.end())
+ continue;
+ *(it->second) = i;
+ }
+}
+
+#undef DECLARE_KNOWN_MODULE
+#undef DEFINE_KNOWN_MODULE
static const char webEngineProcessC[] = "QtWebEngineProcess";
@@ -214,14 +88,43 @@ static inline QString webProcessBinary(const char *binaryName, Platform p)
return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess;
}
+static QString moduleNameToOptionName(const QString &moduleName)
+{
+ QString result = moduleName
+ .mid(3) // strip the "Qt6" prefix
+ .toLower();
+ if (result == u"help"_s)
+ result.prepend("qt"_L1);
+ return result;
+}
+
static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
{
QByteArray result;
for (const auto &qtModule : qtModuleEntries) {
- if (mask.test(qtModule.module)) {
+ if (mask.test(qtModule.id)) {
if (!result.isEmpty())
result.append(' ');
- result.append(option ? qtModule.option : qtModule.libraryName);
+ result.append(option
+ ? moduleNameToOptionName(qtModule.name).toUtf8()
+ : qtModule.name.toUtf8());
+ if (qtModule.internal)
+ result.append("Internal");
+ }
+ }
+ return result;
+}
+
+static QString formatQtPlugins(const PluginInformation &pluginInfo)
+{
+ QString result(u'\n');
+ for (const auto &pair : pluginInfo.typeMap()) {
+ result += pair.first;
+ result += u": \n";
+ for (const QString &plugin : pair.second) {
+ result += u" ";
+ result += plugin;
+ result += u'\n';
}
}
return result;
@@ -229,14 +132,17 @@ static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
static Platform platformFromMkSpec(const QString &xSpec)
{
- if (xSpec == "linux-g++"_L1)
- return Unix;
if (xSpec.startsWith("win32-"_L1)) {
if (xSpec.contains("clang-g++"_L1))
return WindowsDesktopClangMinGW;
if (xSpec.contains("clang-msvc++"_L1))
return WindowsDesktopClangMsvc;
- return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvc;
+ if (xSpec.contains("arm"_L1))
+ return WindowsDesktopMsvcArm;
+ if (xSpec.contains("G++"_L1))
+ return WindowsDesktopMinGW;
+
+ return WindowsDesktopMsvc;
}
return UnknownPlatform;
}
@@ -277,10 +183,12 @@ struct Options {
bool quickImports = true;
bool translations = true;
bool systemD3dCompiler = true;
+ bool systemDxc = true;
bool compilerRunTime = false;
- unsigned disabledPlugins = 0;
bool softwareRasterizer = true;
- Platform platform = WindowsDesktopMsvc;
+ bool ffmpeg = true;
+ PluginSelections pluginSelections;
+ Platform platform = WindowsDesktopMsvcIntel;
ModuleBitset additionalLibraries;
ModuleBitset disabledLibraries;
unsigned updateFileFlags = 0;
@@ -292,6 +200,8 @@ struct Options {
QStringList languages;
QString libraryDirectory;
QString pluginDirectory;
+ QString openSslRootDirectory;
+ QString qmlDirectory;
QStringList binaries;
JsonOutput *json = nullptr;
ListOption list = ListNone;
@@ -300,6 +210,8 @@ struct Options {
bool dryRun = false;
bool patchQt = true;
bool ignoreLibraryErrors = false;
+ bool deployInsightTrackerPlugin = false;
+ bool forceOpenSslPlugin = false;
};
// Return binary to be deployed from folder, ignore pre-existing web engine process.
@@ -325,9 +237,96 @@ static QString msgFileDoesNotExist(const QString & file)
enum CommandLineParseFlag {
CommandLineParseError = 0x1,
- CommandLineParseHelpRequested = 0x2
+ CommandLineParseHelpRequested = 0x2,
+ CommandLineVersionRequested = 0x4
};
+static QCommandLineOption createQMakeOption()
+{
+ return {
+ u"qmake"_s,
+ u"Use specified qmake instead of qmake from PATH. Deprecated, use qtpaths instead."_s,
+ u"path"_s
+ };
+}
+
+static QCommandLineOption createQtPathsOption()
+{
+ return {
+ u"qtpaths"_s,
+ u"Use specified qtpaths.exe instead of qtpaths.exe from PATH."_s,
+ u"path"_s
+ };
+}
+
+static QCommandLineOption createVerboseOption()
+{
+ return {
+ u"verbose"_s,
+ u"Verbose level (0-2)."_s,
+ u"level"_s
+ };
+}
+
+static int parseEarlyArguments(const QStringList &arguments, Options *options,
+ QString *errorMessage)
+{
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
+
+ QCommandLineOption qmakeOption = createQMakeOption();
+ parser.addOption(qmakeOption);
+
+ QCommandLineOption qtpathsOption = createQtPathsOption();
+ parser.addOption(qtpathsOption);
+
+ QCommandLineOption verboseOption = createVerboseOption();
+ parser.addOption(verboseOption);
+
+ // Deliberately don't check for errors. We want to ignore options we don't know about.
+ parser.parse(arguments);
+
+ if (parser.isSet(qmakeOption) && parser.isSet(qtpathsOption)) {
+ *errorMessage = QStringLiteral("-qmake and -qtpaths are mutually exclusive.");
+ return CommandLineParseError;
+ }
+
+ if (parser.isSet(qmakeOption) && optVerboseLevel >= 1)
+ std::wcerr << "Warning: -qmake option is deprecated. Use -qtpaths instead.\n";
+
+ if (parser.isSet(qtpathsOption) || parser.isSet(qmakeOption)) {
+ const QString qtpathsArg = parser.isSet(qtpathsOption) ? parser.value(qtpathsOption)
+ : parser.value(qmakeOption);
+
+ const QString qtpathsBinary = QDir::cleanPath(qtpathsArg);
+ const QFileInfo fi(qtpathsBinary);
+ if (!fi.exists()) {
+ *errorMessage = msgFileDoesNotExist(qtpathsBinary);
+ return CommandLineParseError;
+ }
+
+ if (!fi.isExecutable()) {
+ *errorMessage = u'"' + QDir::toNativeSeparators(qtpathsBinary)
+ + QStringLiteral("\" is not an executable.");
+ return CommandLineParseError;
+ }
+ options->qtpathsBinary = qtpathsBinary;
+ }
+
+ if (parser.isSet(verboseOption)) {
+ bool ok;
+ const QString value = parser.value(verboseOption);
+ optVerboseLevel = value.toInt(&ok);
+ if (!ok || optVerboseLevel < 0) {
+ *errorMessage = QStringLiteral("Invalid value \"%1\" passed for verbose level.")
+ .arg(value);
+ return CommandLineParseError;
+ }
+ }
+
+ return 0;
+}
+
static inline int parseArguments(const QStringList &arguments, QCommandLineParser *parser,
Options *options, QString *errorMessage)
{
@@ -340,24 +339,16 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
"installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n\n"
"If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>"_s);
const QCommandLineOption helpOption = parser->addHelpOption();
- parser->addVersionOption();
+ const QCommandLineOption versionOption = parser->addVersionOption();
QCommandLineOption dirOption(QStringLiteral("dir"),
QStringLiteral("Use directory instead of binary directory."),
QStringLiteral("directory"));
parser->addOption(dirOption);
- QCommandLineOption qmakeOption(QStringLiteral("qmake"),
- QStringLiteral("Use specified qmake instead of qmake from PATH. "
- "Deprecated, use qtpaths instead."),
- QStringLiteral("path"));
- parser->addOption(qmakeOption);
-
- QCommandLineOption qtpathsOption(
- QStringLiteral("qtpaths"),
- QStringLiteral("Use specified qtpaths.exe instead of qtpaths.exe from PATH."),
- QStringLiteral("path"));
- parser->addOption(qtpathsOption);
+ // Add early options to have them available in the help text.
+ parser->addOption(createQMakeOption());
+ parser->addOption(createQtPathsOption());
QCommandLineOption libDirOption(QStringLiteral("libdir"),
QStringLiteral("Copy libraries to path."),
@@ -369,6 +360,17 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("path"));
parser->addOption(pluginDirOption);
+ const QCommandLineOption translationDirOption(
+ u"translationdir"_s,
+ u"Copy translations to path."_s,
+ u"path"_s);
+ parser->addOption(translationDirOption);
+
+ QCommandLineOption qmlDeployDirOption(QStringLiteral("qml-deploy-dir"),
+ QStringLiteral("Copy qml files to path."),
+ QStringLiteral("path"));
+ parser->addOption(qmlDeployDirOption);
+
QCommandLineOption debugOption(QStringLiteral("debug"),
QStringLiteral("Assume debug binaries."));
parser->addOption(debugOption);
@@ -404,6 +406,30 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Skip plugin deployment."));
parser->addOption(noPluginsOption);
+ QCommandLineOption includeSoftPluginsOption(QStringLiteral("include-soft-plugins"),
+ QStringLiteral("Include in the deployment all relevant plugins by taking into account all soft dependencies."));
+ parser->addOption(includeSoftPluginsOption);
+
+ QCommandLineOption skipPluginTypesOption(QStringLiteral("skip-plugin-types"),
+ QStringLiteral("A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
+ QStringLiteral("plugin types"));
+ parser->addOption(skipPluginTypesOption);
+
+ QCommandLineOption addPluginTypesOption(QStringLiteral("add-plugin-types"),
+ QStringLiteral("A comma-separated list of plugin types that will be added to deployment (imageformats,iconengines)"),
+ QStringLiteral("plugin types"));
+ parser->addOption(addPluginTypesOption);
+
+ QCommandLineOption includePluginsOption(QStringLiteral("include-plugins"),
+ QStringLiteral("A comma-separated list of individual plugins that will be added to deployment (scene2d,qjpeg)"),
+ QStringLiteral("plugins"));
+ parser->addOption(includePluginsOption);
+
+ QCommandLineOption excludePluginsOption(QStringLiteral("exclude-plugins"),
+ QStringLiteral("A comma-separated list of individual plugins that will not be deployed (qsvg,qpdf)"),
+ QStringLiteral("plugins"));
+ parser->addOption(excludePluginsOption);
+
QCommandLineOption noLibraryOption(QStringLiteral("no-libraries"),
QStringLiteral("Skip library deployment."));
parser->addOption(noLibraryOption);
@@ -436,15 +462,15 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Skip deployment of the system D3D compiler."));
parser->addOption(noSystemD3DCompilerOption);
+ QCommandLineOption noSystemDxcOption(QStringLiteral("no-system-dxc-compiler"),
+ QStringLiteral("Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
+ parser->addOption(noSystemDxcOption);
+
QCommandLineOption compilerRunTimeOption(QStringLiteral("compiler-runtime"),
QStringLiteral("Deploy compiler runtime (Desktop only)."));
parser->addOption(compilerRunTimeOption);
- QCommandLineOption noVirtualKeyboardOption(QStringLiteral("no-virtualkeyboard"),
- QStringLiteral("Disable deployment of the Virtual Keyboard."));
- parser->addOption(noVirtualKeyboardOption);
-
QCommandLineOption noCompilerRunTimeOption(QStringLiteral("no-compiler-runtime"),
QStringLiteral("Do not deploy compiler runtime (Desktop only)."));
parser->addOption(noCompilerRunTimeOption);
@@ -457,6 +483,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Do not deploy the software rasterizer library."));
parser->addOption(suppressSoftwareRasterizerOption);
+ QCommandLineOption noFFmpegOption(QStringLiteral("no-ffmpeg"),
+ QStringLiteral("Do not deploy the FFmpeg libraries."));
+ parser->addOption(noFFmpegOption);
+
+ QCommandLineOption forceOpenSslOption(QStringLiteral("force-openssl"),
+ QStringLiteral("Deploy openssl plugin but ignore openssl library dependency"));
+ parser->addOption(forceOpenSslOption);
+
+ QCommandLineOption openSslRootOption(QStringLiteral("openssl-root"),
+ QStringLiteral("Directory containing openSSL libraries."),
+ QStringLiteral("directory"));
+ parser->addOption(openSslRootOption);
+
+
QCommandLineOption listOption(QStringLiteral("list"),
"Print only the names of the files copied.\n"
"Available options:\n"
@@ -470,22 +510,29 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("option"));
parser->addOption(listOption);
- QCommandLineOption verboseOption(QStringLiteral("verbose"),
- QStringLiteral("Verbose level (0-2)."),
- QStringLiteral("level"));
- parser->addOption(verboseOption);
+ // Add early option to have it available in the help text.
+ parser->addOption(createVerboseOption());
parser->addPositionalArgument(QStringLiteral("[files]"),
QStringLiteral("Binaries or directory containing the binary."));
+ QCommandLineOption deployInsightTrackerOption(QStringLiteral("deploy-insighttracker"),
+ QStringLiteral("Deploy insight tracker plugin."));
+ // The option will be added to the parser if the module is available (see block below)
+ bool insightTrackerModuleAvailable = false;
+
OptionPtrVector enabledModuleOptions;
OptionPtrVector disabledModuleOptions;
- const int qtModulesCount = int(sizeof(qtModuleEntries) / sizeof(QtModuleEntry));
+ const size_t qtModulesCount = qtModuleEntries.size();
enabledModuleOptions.reserve(qtModulesCount);
disabledModuleOptions.reserve(qtModulesCount);
- for (int i = 0; i < qtModulesCount; ++i) {
- const QString option = QLatin1StringView(qtModuleEntries[i].option);
- const QString name = QLatin1StringView(qtModuleEntries[i].libraryName);
+ for (const QtModule &module : qtModuleEntries) {
+ const QString option = moduleNameToOptionName(module.name);
+ const QString name = module.name;
+ if (name == u"InsightTracker") {
+ parser->addOption(deployInsightTrackerOption);
+ insightTrackerModuleAvailable = true;
+ }
const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module.");
CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription));
parser->addOption(*enabledOption.data());
@@ -500,6 +547,8 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
const bool success = parser->parse(arguments);
if (parser->isSet(helpOption))
return CommandLineParseHelpRequested;
+ if (parser->isSet(versionOption))
+ return CommandLineVersionRequested;
if (!success) {
*errorMessage = parser->errorText();
return CommandLineParseError;
@@ -507,28 +556,43 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
options->libraryDirectory = parser->value(libDirOption);
options->pluginDirectory = parser->value(pluginDirOption);
+ options->translationsDirectory = parser->value(translationDirOption);
+ options->qmlDirectory = parser->value(qmlDeployDirOption);
options->plugins = !parser->isSet(noPluginsOption);
options->libraries = !parser->isSet(noLibraryOption);
options->translations = !parser->isSet(noTranslationOption);
if (parser->isSet(translationOption))
options->languages = parser->value(translationOption).split(u',');
options->systemD3dCompiler = !parser->isSet(noSystemD3DCompilerOption);
+ options->systemDxc = !parser->isSet(noSystemDxcOption);
options->quickImports = !parser->isSet(noQuickImportOption);
// default to deployment of compiler runtime for windows desktop configurations
- if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc
+ if (options->platform == WindowsDesktopMinGW || options->platform.testFlags(WindowsDesktopMsvc)
|| parser->isSet(compilerRunTimeOption))
options->compilerRunTime = true;
if (parser->isSet(noCompilerRunTimeOption))
options->compilerRunTime = false;
- if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) {
+ if (options->compilerRunTime && options->platform != WindowsDesktopMinGW
+ && !options->platform.testFlags(WindowsDesktopMsvc)) {
*errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
return CommandLineParseError;
}
- if (parser->isSet(noVirtualKeyboardOption))
- options->disabledPlugins |= QtVirtualKeyboardPlugin;
+ options->pluginSelections.includeSoftPlugins = parser->isSet(includeSoftPluginsOption);
+
+ if (parser->isSet(skipPluginTypesOption))
+ options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
+
+ if (parser->isSet(addPluginTypesOption))
+ options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
+
+ if (parser->isSet(includePluginsOption))
+ options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
+
+ if (parser->isSet(excludePluginsOption))
+ options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
if (parser->isSet(releaseWithDebugInfoOption))
std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete.";
@@ -554,6 +618,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(suppressSoftwareRasterizerOption))
options->softwareRasterizer = false;
+ if (parser->isSet(noFFmpegOption))
+ options->ffmpeg = false;
+
+ if (parser->isSet(forceOpenSslOption))
+ options->forceOpenSslPlugin = true;
+
+ if (parser->isSet(openSslRootOption))
+ options->openSslRootDirectory = parser->value(openSslRootOption);
+
+ if (options->forceOpenSslPlugin && !options->openSslRootDirectory.isEmpty()) {
+ *errorMessage = QStringLiteral("force-openssl and openssl-root are mutually exclusive");
+ return CommandLineParseError;
+ }
+
if (parser->isSet(forceOption))
options->updateFileFlags |= ForceUpdateFile;
if (parser->isSet(dryRunOption)) {
@@ -563,19 +641,21 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
options->patchQt = !parser->isSet(noPatchQtOption);
options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
+ if (insightTrackerModuleAvailable)
+ options->deployInsightTrackerPlugin = parser->isSet(deployInsightTrackerOption);
- for (int i = 0; i < qtModulesCount; ++i) {
- if (parser->isSet(*enabledModuleOptions.at(i)))
- options->additionalLibraries[qtModuleEntries[i].module] = 1;
- if (parser->isSet(*disabledModuleOptions.at(i)))
- options->disabledLibraries[qtModuleEntries[i].module] = 1;
+ for (const QtModule &module : qtModuleEntries) {
+ if (parser->isSet(*enabledModuleOptions.at(module.id)))
+ options->additionalLibraries[module.id] = 1;
+ if (parser->isSet(*disabledModuleOptions.at(module.id)))
+ options->disabledLibraries[module.id] = 1;
}
// Add some dependencies
- if (options->additionalLibraries.test(QtQuickModule))
- options->additionalLibraries[QtQmlModule] = 1;
- if (options->additionalLibraries.test(QtDesignerComponents))
- options->additionalLibraries[QtDesignerModule] = 1;
+ if (options->additionalLibraries.test(QtQuickModuleId))
+ options->additionalLibraries[QtQmlModuleId] = 1;
+ if (options->additionalLibraries.test(QtDesignerComponentsModuleId))
+ options->additionalLibraries[QtDesignerModuleId] = 1;
if (parser->isSet(listOption)) {
const QString value = parser->value(listOption);
@@ -596,16 +676,6 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(jsonOption) || options->list) {
optVerboseLevel = 0;
options->json = new JsonOutput;
- } else {
- if (parser->isSet(verboseOption)) {
- bool ok;
- const QString value = parser->value(verboseOption);
- optVerboseLevel = value.toInt(&ok);
- if (!ok || optVerboseLevel < 0) {
- *errorMessage = QStringLiteral("Invalid value \"%1\" passed for verbose level.").arg(value);
- return CommandLineParseError;
- }
- }
}
const QStringList posArgs = parser->positionalArguments();
@@ -617,33 +687,6 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(dirOption))
options->directory = parser->value(dirOption);
- if (parser->isSet(qmakeOption) && parser->isSet(qtpathsOption)) {
- *errorMessage = QStringLiteral("-qmake and -qtpaths are mutually exclusive.");
- return CommandLineParseError;
- }
-
- if (parser->isSet(qmakeOption) && optVerboseLevel >= 1)
- std::wcerr << "Warning: -qmake option is deprecated. Use -qpaths instead.\n";
-
- if (parser->isSet(qtpathsOption) || parser->isSet(qmakeOption)) {
- const QString qtpathsArg = parser->isSet(qtpathsOption) ? parser->value(qtpathsOption)
- : parser->value(qmakeOption);
-
- const QString qtpathsBinary = QDir::cleanPath(qtpathsArg);
- const QFileInfo fi(qtpathsBinary);
- if (!fi.exists()) {
- *errorMessage = msgFileDoesNotExist(qtpathsBinary);
- return CommandLineParseError;
- }
-
- if (!fi.isExecutable()) {
- *errorMessage = u'"' + QDir::toNativeSeparators(qtpathsBinary)
- + QStringLiteral("\" is not an executable.");
- return CommandLineParseError;
- }
- options->qtpathsBinary = qtpathsBinary;
- }
-
if (parser->isSet(qmlDirOption))
options->qmlDirectories = parser->values(qmlDirOption);
@@ -691,14 +734,17 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (const QString &library : libraries)
options->binaries.append(path + u'/' + library);
} else {
- if (fi.absolutePath() != options->directory)
+ if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
multipleDirs = true;
options->binaries.append(path);
}
}
- if (multipleDirs)
- std::wcerr << "Warning: using binaries from different directories\n";
- options->translationsDirectory = options->directory + "/translations"_L1;
+ if (multipleDirs) {
+ std::wcerr << "Warning: using binaries from different directories, deploying to following path: "
+ << options->directory << '\n' << "To disable this warning, use the --dir option\n";
+ }
+ if (options->translationsDirectory.isEmpty())
+ options->translationsDirectory = options->directory + "/translations"_L1;
return 0;
}
@@ -715,12 +761,16 @@ static inline QString lineBreak(QString s)
return s;
}
-static inline QString helpText(const QCommandLineParser &p)
+static inline QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
{
QString result = p.helpText();
// Replace the default-generated text which is too long by a short summary
// explaining how to enable single libraries.
- const qsizetype moduleStart = result.indexOf("\n --bluetooth"_L1);
+ if (qtModuleEntries.size() == 0)
+ return result;
+ const QtModule &firstModule = qtModuleEntries.moduleById(0);
+ const QString firstModuleOption = moduleNameToOptionName(firstModule.name);
+ const qsizetype moduleStart = result.indexOf("\n --"_L1 + firstModuleOption);
const qsizetype argumentsStart = result.lastIndexOf("\nArguments:"_L1);
if (moduleStart >= argumentsStart)
return result;
@@ -730,7 +780,18 @@ static inline QString helpText(const QCommandLineParser &p)
"the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
ModuleBitset mask;
moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
- moduleHelp += u'\n';
+ moduleHelp += u"\n\n";
+ moduleHelp +=
+ u"Qt plugins can be included or excluded individually or by type.\n"
+ u"To deploy or block plugins individually, use the --include-plugins\n"
+ u"and --exclude-plugins options (--include-plugins qjpeg,qsvgicon)\n"
+ u"You can also use the --skip-plugin-types or --add-plugin-types to\n"
+ u"achieve similar results with entire plugin groups, like imageformats, e.g.\n"
+ u"(--add-plugin-types imageformats,iconengines). Exclusion always takes\n"
+ u"precedence over inclusion, and types take precedence over specific plugins.\n"
+ u"For example, including qjpeg, but skipping imageformats, will NOT deploy qjpeg.\n"
+ u"\nDetected available plugins:\n";
+ moduleHelp += formatQtPlugins(pluginInfo);
result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp);
return result;
}
@@ -754,7 +815,8 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin
QStringList dependentLibs;
if (directDependencyCount)
*directDependencyCount = 0;
- if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug, machineArch)) {
+ if (!readPeExecutable(binary, errorMessage, &dependentLibs, wordSize, isDebug,
+ platform == WindowsDesktopMinGW, machineArch)) {
errorMessage->prepend("Unable to find dependent libraries of "_L1 +
QDir::toNativeSeparators(binary) + " :"_L1);
return false;
@@ -819,13 +881,19 @@ public:
SkipSources = 0x2
};
- explicit QmlDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
+ explicit QmlDirectoryFileEntryFunction(
+ const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
: m_flags(flags), m_qmlNameFilter(QmlDirectoryFileEntryFunction::qmlNameFilters(flags))
- , m_dllFilter(platform, debugMatchMode)
+ , m_dllFilter(platform, debugMatchMode), m_moduleSourcePath(moduleSourcePath)
{}
QStringList operator()(const QDir &dir) const
{
+ if (moduleSourceDir(dir).canonicalPath() != m_moduleSourcePath) {
+ // If we're in a different module, return nothing.
+ return {};
+ }
+
QStringList result;
const QStringList &libraries = m_dllFilter(dir);
for (const QString &library : libraries) {
@@ -841,6 +909,17 @@ public:
}
private:
+ static QDir moduleSourceDir(const QDir &dir)
+ {
+ QDir moduleSourceDir = dir;
+ while (!moduleSourceDir.exists(QStringLiteral("qmldir"))) {
+ if (!moduleSourceDir.cdUp()) {
+ return {};
+ }
+ }
+ return moduleSourceDir;
+ }
+
static inline QStringList qmlNameFilters(unsigned flags)
{
QStringList result;
@@ -857,66 +936,10 @@ private:
const unsigned m_flags;
NameFilterFileEntryFunction m_qmlNameFilter;
DllDirectoryFileEntryFunction m_dllFilter;
+ QString m_moduleSourcePath;
};
-struct PluginModuleMapping
-{
- const char *directoryName;
- quint64 module;
-};
-
-static const PluginModuleMapping pluginModuleMappings[] =
-{
-#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
- {"gamepads", QtGamePadModule},
-#endif
- {"accessible", QtGuiModule},
- {"iconengines", QtGuiModule},
- {"imageformats", QtGuiModule},
- {"platforms", QtGuiModule},
- {"platforminputcontexts", QtGuiModule},
- {"virtualkeyboard", QtGuiModule},
- {"geoservices", QtLocationModule},
- {"audio", QtMultimediaModule},
- {"mediaservice", QtMultimediaModule},
- {"multimedia", QtMultimediaModule},
- {"playlistformats", QtMultimediaModule},
- {"networkaccess", QtNetworkModule},
- {"networkinformation", QtNetworkModule},
- {"tls", QtNetworkModule},
- {"position", QtPositioningModule},
- {"printsupport", QtPrintSupportModule},
- {"scenegraph", QtQuickModule},
- {"qmltooling", QtQuickModule | QtQmlToolingModule},
- {"sensors", QtSensorsModule},
- {"sensorgestures", QtSensorsModule},
- {"canbus", QtSerialBusModule},
- {"sqldrivers", QtSqlModule},
-#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
- {"texttospeech", QtTextToSpeechModule},
-#endif
- {"qtwebengine", QtWebEngineModule | QtWebEngineCoreModule | QtWebEngineWidgetsModule},
- {"styles", QtWidgetsModule},
- {"sceneparsers", Qt3DRendererModule},
- {"renderers", Qt3DRendererModule | QtShaderToolsModule},
- {"renderplugins", Qt3DRendererModule},
- {"geometryloaders", Qt3DRendererModule},
- {"webview", QtWebViewModule},
- {"designer", QtUiToolsModule},
- {"scxmldatamodel", QtScxmlModule},
- {"opcua", QtOpcUaModule}
-};
-
-static inline quint64 qtModuleForPlugin(const QString &subDirName)
-{
- const auto end = std::end(pluginModuleMappings);
- const auto result =
- std::find_if(std::begin(pluginModuleMappings), end,
- [&subDirName] (const PluginModuleMapping &m) { return subDirName == QLatin1StringView(m.directoryName); });
- return result != end ? result->module : 0; // "designer"
-}
-
-static quint64 qtModule(QString module, const QString &infix)
+static qint64 qtModule(QString module, const QString &infix)
{
// Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0'
const qsizetype lastSlashPos = module.lastIndexOf(u'/');
@@ -931,126 +954,189 @@ static quint64 qtModule(QString module, const QString &infix)
module.truncate(endPos);
// That should leave us with 'Qt6Core<d>'.
for (const auto &qtModule : qtModuleEntries) {
- const QLatin1StringView libraryName(qtModule.libraryName);
+ const QString &libraryName = qtModule.name;
if (module == libraryName
|| (module.size() == libraryName.size() + 1 && module.startsWith(libraryName))) {
- return qtModule.module;
+ return qtModule.id;
}
}
- return 0;
+ std::wcerr << "Warning: module " << qPrintable(module) << " could not be found\n";
+ return -1;
}
// Return the path if a plugin is to be deployed
-static QString deployPlugin(const QString &plugin, const QDir &subDir,
- ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
- unsigned disabledPlugins,
- const QString &libraryLocation, const QString &infix,
- Platform platform)
+static QString deployPlugin(const QString &plugin, const QDir &subDir, const bool dueToModule,
+ const DebugMatchMode &debugMatchMode, ModuleBitset *pluginNeededQtModules,
+ const ModuleBitset &disabledQtModules,
+ const PluginSelections &pluginSelections, const QString &libraryLocation,
+ const QString &infix, Platform platform,
+ bool deployInsightTrackerPlugin, bool deployOpenSslPlugin)
{
+ const QString subDirName = subDir.dirName();
// Filter out disabled plugins
- if ((disabledPlugins & QtVirtualKeyboardPlugin)
- && plugin.startsWith("qtvirtualkeyboardplugin"_L1)) {
+ if (optVerboseLevel && pluginSelections.disabledPluginTypes.contains(subDirName)) {
+ std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n';
+ return {};
+ }
+ if (optVerboseLevel && subDirName == u"generic" && plugin.contains(u"qinsighttracker")
+ && !deployInsightTrackerPlugin) {
+ std::wcout << "Skipping plugin " << plugin
+ << ". Use -deploy-insighttracker if you want to use it.\n";
+ return {};
+ }
+ if (optVerboseLevel && subDirName == u"tls" && plugin.contains(u"qopensslbackend")
+ && !deployOpenSslPlugin) {
+ std::wcout << "Skipping plugin " << plugin
+ << ". Use -force_openssl or specify -openssl-root if you want to use it.\n";
+ return {};
+ }
+
+ const int dotIndex = plugin.lastIndexOf(u'.');
+ // Strip the .dll from the name, and an additional 'd' if it's a debug library with the 'd'
+ // suffix
+ const int stripIndex = debugMatchMode == MatchDebug && platformHasDebugSuffix(platform)
+ ? dotIndex - 1
+ : dotIndex;
+ const QString pluginName = plugin.first(stripIndex);
+
+ if (optVerboseLevel && pluginSelections.excludedPlugins.contains(pluginName)) {
+ std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n';
+ return {};
+ }
+
+ // By default, only deploy qwindows.dll
+ if (subDirName == u"platforms"
+ && !(pluginSelections.includedPlugins.contains(pluginName)
+ || (pluginSelections.enabledPluginTypes.contains(subDirName)))
+ && !pluginName.startsWith(u"qwindows")) {
return {};
}
const QString pluginPath = subDir.absoluteFilePath(plugin);
+
+ // If dueToModule is false, check if the user included the plugin or the entire type. In the
+ // former's case, only deploy said plugin and not all plugins of that type.
+ const bool requiresPlugin = pluginSelections.includedPlugins.contains(pluginName)
+ || pluginSelections.enabledPluginTypes.contains(subDirName);
+ if (!dueToModule && !requiresPlugin)
+ return {};
+
// Deploy QUiTools plugins as is without further dependency checking.
// The user needs to ensure all required libraries are present (would
// otherwise pull QtWebEngine for its plugin).
- if (subDir.dirName() == u"designer")
+ if (subDirName == u"designer")
return pluginPath;
QStringList dependentQtLibs;
- ModuleBitset neededModules;
QString errorMessage;
if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
&errorMessage, &dependentQtLibs)) {
- for (int d = 0; d < dependentQtLibs.size(); ++ d)
- neededModules[qtModule(dependentQtLibs.at(d), infix)] = 1;
+ for (int d = 0; d < dependentQtLibs.size(); ++d) {
+ const qint64 module = qtModule(dependentQtLibs.at(d), infix);
+ if (module >= 0)
+ (*pluginNeededQtModules)[module] = 1;
+ }
} else {
std::wcerr << "Warning: Cannot determine dependencies of "
<< QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
}
- ModuleBitset missingModules;
- missingModules = neededModules & disabledQtModules;
- if (missingModules.any()) {
+ ModuleBitset disabledNeededQtModules;
+ disabledNeededQtModules = *pluginNeededQtModules & disabledQtModules;
+ if (disabledNeededQtModules.any()) {
if (optVerboseLevel) {
std::wcout << "Skipping plugin " << plugin
<< " due to disabled dependencies ("
- << formatQtModules(missingModules).constData() << ").\n";
+ << formatQtModules(disabledNeededQtModules).constData() << ").\n";
}
return {};
}
- missingModules = (neededModules & ~*usedQtModules);
- if (missingModules.any()) {
- *usedQtModules |= missingModules;
- if (optVerboseLevel) {
- std::wcout << "Adding " << formatQtModules(missingModules).constData()
- << " for " << plugin << '\n';
- }
- }
return pluginPath;
}
+static bool needsPluginType(const QString &subDirName, const PluginInformation &pluginInfo,
+ const PluginSelections &pluginSelections)
+{
+ bool needsTypeForPlugin = false;
+ for (const QString &plugin: pluginSelections.includedPlugins) {
+ if (pluginInfo.isTypeForPlugin(subDirName, plugin))
+ needsTypeForPlugin = true;
+ }
+ return (pluginSelections.enabledPluginTypes.contains(subDirName) || needsTypeForPlugin);
+}
+
QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
- unsigned disabledPlugins,
+ const PluginInformation &pluginInfo, const PluginSelections &pluginSelections,
const QString &qtPluginsDirName, const QString &libraryLocation,
- const QString &infix,
- DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin)
+ const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform,
+ QString *platformPlugin, bool deployInsightTrackerPlugin,
+ bool deployOpenSslPlugin)
{
if (qtPluginsDirName.isEmpty())
return QStringList();
QDir pluginsDir(qtPluginsDirName);
QStringList result;
+ bool missingQtModulesAdded = false;
const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &subDirFi : pluginDirs) {
const QString subDirName = subDirFi.fileName();
- const quint64 module = qtModuleForPlugin(subDirName);
- if (usedQtModules->test(module)) {
- const DebugMatchMode debugMatchMode = (module & QtWebEngineCoreModule)
+ const size_t module = qtModuleEntries.moduleIdForPluginType(subDirName);
+ if (module == QtModule::InvalidId) {
+ if (optVerboseLevel > 1) {
+ std::wcerr << "No Qt module found for plugin type \"" << subDirName << "\".\n";
+ }
+ continue;
+ }
+ const bool dueToModule = usedQtModules->test(module);
+ if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
+ const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all.
: debugMatchModeIn;
QDir subDir(subDirFi.absoluteFilePath());
- // Filter out disabled plugins
- if ((disabledPlugins & QtVirtualKeyboardPlugin) && subDirName == "virtualkeyboard"_L1)
- continue;
- if (disabledQtModules.test(QtQmlToolingModule) && subDirName == "qmltooling"_L1)
- continue;
- // Filter for platform or any.
- QString filter;
+ if (optVerboseLevel)
+ std::wcout << "Adding in plugin type " << subDirFi.baseName() << " for module: " << qtModuleEntries.moduleById(module).name << '\n';
+
const bool isPlatformPlugin = subDirName == "platforms"_L1;
- if (isPlatformPlugin) {
- switch (platform) {
- case WindowsDesktopMsvc:
- case WindowsDesktopMinGW:
- filter = QStringLiteral("qwindows");
- if (!infix.isEmpty())
- filter += infix;
- break;
- case Unix:
- filter = QStringLiteral("libqxcb");
- break;
- case UnknownPlatform:
- break;
- }
- } else {
- filter = u"*"_s;
- }
- const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter);
+ const QStringList plugins =
+ findSharedLibraries(subDir, platform, debugMatchMode, QString());
for (const QString &plugin : plugins) {
+ ModuleBitset pluginNeededQtModules;
const QString pluginPath =
- deployPlugin(plugin, subDir, usedQtModules, disabledQtModules,
- disabledPlugins, libraryLocation, infix, platform);
+ deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
+ disabledQtModules, pluginSelections, libraryLocation, infix,
+ platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
if (!pluginPath.isEmpty()) {
- if (isPlatformPlugin)
+ if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
*platformPlugin = subDir.absoluteFilePath(plugin);
result.append(pluginPath);
+
+ const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
+ if (missingModules.any()) {
+ *usedQtModules |= missingModules;
+ missingQtModulesAdded = true;
+ if (optVerboseLevel) {
+ std::wcout << "Adding " << formatQtModules(missingModules).constData()
+ << " for " << plugin << " from plugin type: " << subDirName << '\n';
+ }
+ }
}
} // for filter
} // type matches
} // for plugin folder
+
+ // If missing Qt modules were added during plugin deployment make additional pass, because we may need
+ // additional plugins.
+ if (pluginSelections.includeSoftPlugins && missingQtModulesAdded) {
+ if (optVerboseLevel) {
+ std::wcout << "Performing additional pass of finding Qt plugins due to updated Qt module list: "
+ << formatQtModules(*usedQtModules).constData() << "\n";
+ }
+ return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
+ libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
+ deployInsightTrackerPlugin, deployOpenSslPlugin);
+ }
+
return result;
}
@@ -1058,9 +1144,8 @@ static QStringList translationNameFilters(const ModuleBitset &modules, const QSt
{
QStringList result;
for (const auto &qtModule : qtModuleEntries) {
- if (modules.test(qtModule.module) && qtModule.translation) {
- const QString name = QLatin1StringView(qtModule.translation) +
- u'_' + prefix + ".qm"_L1;
+ if (modules.test(qtModule.id) && !qtModule.translationCatalog.isEmpty()) {
+ const QString name = qtModule.translationCatalog + u'_' + prefix + ".qm"_L1;
if (!result.contains(name))
result.push_back(name);
}
@@ -1100,7 +1185,12 @@ static bool deployTranslations(const QString &sourcePath, const ModuleBitset &us
if (options.json)
options.json->addFile(sourcePath + u'/' + targetFile, absoluteTarget);
arguments.append(QDir::toNativeSeparators(targetFilePath));
- const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationNameFilters(usedQtModules, prefix));
+ const QStringList translationFilters = translationNameFilters(usedQtModules, prefix);
+ if (translationFilters.isEmpty()){
+ std::wcerr << "Warning: translation catalogs are all empty, skipping translation deployment\n";
+ return true;
+ }
+ const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationFilters);
for (const QFileInfo &langQmFileFi : langQmFiles) {
if (options.json) {
options.json->addFile(langQmFileFi.absoluteFilePath(),
@@ -1120,6 +1210,62 @@ static bool deployTranslations(const QString &sourcePath, const ModuleBitset &us
return true;
}
+static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
+{
+ const std::vector<QLatin1StringView> ffmpegHints = { "avcodec"_L1, "avformat"_L1, "avutil"_L1,
+ "swresample"_L1, "swscale"_L1 };
+ const QStringList bundledLibs =
+ findSharedLibraries(qtBinDir, platform, MatchDebugOrRelease, {});
+
+ QStringList ffmpegLibs;
+ for (const QLatin1StringView &libHint : ffmpegHints) {
+ const QStringList ffmpegLib = bundledLibs.filter(libHint, Qt::CaseInsensitive);
+
+ if (ffmpegLib.empty()) {
+ std::wcerr << "Warning: Cannot find FFmpeg libraries. Multimedia features will not work as expected.\n";
+ return {};
+ } else if (ffmpegLib.size() != 1u) {
+ std::wcerr << "Warning: Multiple versions of FFmpeg libraries found. Multimedia features will not work as expected.\n";
+ return {};
+ }
+
+ const QChar slash(u'/');
+ QFileInfo ffmpegLibPath{ qtBinDir + slash + ffmpegLib.front() };
+ ffmpegLibs.append(ffmpegLibPath.absoluteFilePath());
+ }
+
+ return ffmpegLibs;
+}
+
+// Find the openssl libraries Qt executables depend on.
+static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
+{
+ const std::vector<QLatin1StringView> libHints = { "libcrypto"_L1, "libssl"_L1 };
+ const QChar slash(u'/');
+ const QString openSslBinDir = openSslRootDir + slash + "bin"_L1;
+ const QStringList openSslRootLibs =
+ findSharedLibraries(openSslBinDir, platform, MatchDebugOrRelease, {});
+
+ QStringList result;
+ for (const QLatin1StringView &libHint : libHints) {
+ const QStringList lib = openSslRootLibs.filter(libHint, Qt::CaseInsensitive);
+
+ if (lib.empty()) {
+ std::wcerr << "Warning: Cannot find openssl libraries.\n";
+ return {};
+ } else if (lib.size() != 1u) {
+ std::wcerr << "Warning: Multiple versions of openssl libraries found.\n";
+ return {};
+ }
+
+ QFileInfo libPath{ openSslBinDir + slash + lib.front() };
+ result.append(libPath.absoluteFilePath());
+ }
+
+ return result;
+}
+
+
struct DeployResult
{
operator bool() const { return success; }
@@ -1132,20 +1278,14 @@ struct DeployResult
};
static QString libraryPath(const QString &libraryLocation, const char *name,
- const QString &qtLibInfix, Platform platform, bool debug)
+ const QString &infix, Platform platform, bool debug)
{
QString result = libraryLocation + u'/';
- if (platform & WindowsBased) {
- result += QLatin1StringView(name);
- result += qtLibInfix;
- if (debug && platformHasDebugSuffix(platform))
- result += u'd';
- } else if (platform.testFlag(UnixBased)) {
- result += QStringLiteral("lib");
- result += QLatin1StringView(name);
- result += qtLibInfix;
- }
- result += sharedLibrarySuffix(platform);
+ result += QLatin1StringView(name);
+ result += infix;
+ if (debug && platformHasDebugSuffix(platform))
+ result += u'd';
+ result += sharedLibrarySuffix();
return result;
}
@@ -1186,29 +1326,51 @@ static QString vcRedistDir()
return QString();
}
-static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned short machineArch)
+static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
{
+ //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found.
QStringList result;
- switch (platform) {
- case WindowsDesktopMinGW: { // MinGW: Add runtime libraries
- static const char *minGwRuntimes[] = {"*gcc_", "*stdc++", "*winpthread"};
- const QString gcc = findInPath(QStringLiteral("g++.exe"));
- if (gcc.isEmpty()) {
- std::wcerr << "Warning: Cannot find GCC installation directory. g++.exe must be in the path.\n";
- break;
+ const bool isClang = platform == WindowsDesktopClangMinGW;
+ QStringList filters;
+ const QString suffix = u'*' + sharedLibrarySuffix();
+ for (const auto &minGWRuntime : runtimeFilters)
+ filters.append(minGWRuntime + suffix);
+
+ QFileInfoList dlls = QDir(qtBinDir).entryInfoList(filters, QDir::Files);
+ if (dlls.isEmpty()) {
+ std::wcerr << "Warning: Runtime libraries not found in Qt binary folder, defaulting to looking in path\n";
+ const QString binaryPath = isClang ? findInPath("clang++.exe"_L1) : findInPath("g++.exe"_L1);
+ if (binaryPath.isEmpty()) {
+ std::wcerr << "Warning: Cannot find " << (isClang ? "Clang" : "GCC") << " installation directory, " << (isClang ? "clang++" : "g++") << ".exe must be in the path\n";
+ return {};
}
- const QString binPath = QFileInfo(gcc).absolutePath();
- QStringList filters;
- const QString suffix = u'*' + sharedLibrarySuffix(platform);
- for (auto minGwRuntime : minGwRuntimes)
- filters.append(QLatin1StringView(minGwRuntime) + suffix);
- const QFileInfoList &dlls = QDir(binPath).entryInfoList(filters, QDir::Files);
- for (const QFileInfo &dllFi : dlls)
- result.append(dllFi.absoluteFilePath());
+ const QString binaryFolder = QFileInfo(binaryPath).absolutePath();
+ dlls = QDir(binaryFolder).entryInfoList(filters, QDir::Files);
}
+
+ for (const QFileInfo &dllFi : dlls)
+ result.append(dllFi.absoluteFilePath());
+
+ return result;
+}
+
+static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
+{
+ QStringList result;
+ switch (platform) {
+ case WindowsDesktopMinGW: {
+ const QStringList minGWRuntimes = { "*gcc_"_L1, "*stdc++"_L1, "*winpthread"_L1 };
+ result.append(findMinGWRuntimePaths(qtBinDir, platform, minGWRuntimes));
+ break;
+ }
+ case WindowsDesktopClangMinGW: {
+ const QStringList clangMinGWRuntimes = { "*unwind"_L1, "*c++"_L1 };
+ result.append(findMinGWRuntimePaths(qtBinDir, platform, clangMinGWRuntimes));
break;
+ }
#ifdef Q_OS_WIN
- case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages.
+ case WindowsDesktopMsvcIntel:
+ case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages.
QString vcRedistDirName = vcRedistDir();
if (vcRedistDirName.isEmpty())
break;
@@ -1264,16 +1426,6 @@ static inline int qtVersion(const QMap<QString, QString> &qtpathsVariables)
return (majorVersion << 16) | (minorVersion << 8) | patchVersion;
}
-// Determine the Qt lib infix from the library path of "Qt6Core<qtblibinfix>[d].dll".
-static inline QString qtlibInfixFromCoreLibName(const QString &path, bool isDebug, Platform platform)
-{
- const qsizetype startPos = path.lastIndexOf(u'/') + 8;
- qsizetype endPos = path.lastIndexOf(u'.');
- if (isDebug && (platform & WindowsBased))
- endPos--;
- return endPos > startPos ? path.mid(startPos, endPos - startPos) : QString();
-}
-
// Deploy a library along with its .pdb debug info file (MSVC) should it exist.
static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory,
const Options &options, QString *errorMessage)
@@ -1306,16 +1458,14 @@ static QString getIcuVersion(const QString &libName)
}
static DeployResult deploy(const Options &options, const QMap<QString, QString> &qtpathsVariables,
- QString *errorMessage)
+ const PluginInformation &pluginInfo, QString *errorMessage)
{
DeployResult result;
const QChar slash = u'/';
const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
- const QString libraryLocation = options.platform == Unix
- ? qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBS"))
- : qtBinDir;
+ const QString libraryLocation = qtBinDir;
const QString infix = qtpathsVariables.value(QLatin1StringView(qmakeInfixKey));
const int version = qtVersion(qtpathsVariables);
Q_UNUSED(version);
@@ -1362,19 +1512,17 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// Determine application type, check Quick2 is used by looking at the
// direct dependencies (do not be fooled by QtWebKit depending on it).
- QString qtLibInfix;
for (int m = 0; m < dependentQtLibs.size(); ++m) {
- const quint64 module = qtModule(dependentQtLibs.at(m), infix);
- result.directlyUsedQtLibraries[module] = 1;
- if (module == QtCoreModule)
- qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform);
+ const qint64 module = qtModule(dependentQtLibs.at(m), infix);
+ if (module >= 0)
+ result.directlyUsedQtLibraries[module] = 1;
}
- const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModule);
- const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModule);
- const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModule);
- const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModule))
- && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModule)));
+ const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
+ const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModuleId);
+ const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModuleId);
+ const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModuleId))
+ && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModuleId)));
if (optVerboseLevel) {
std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' '
@@ -1396,7 +1544,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral("Qt6Core"), Qt::CaseInsensitive)
+ dependentQtLibs.filter(QStringLiteral("Qt5WebKit"), Qt::CaseInsensitive);
for (const QString &qtLib : qtLibs) {
- QStringList icuLibs = findDependentLibraries(qtLib, options.platform, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive);
+ QStringList icuLibs = findDependentLibraries(qtLib, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive);
if (!icuLibs.isEmpty()) {
// Find out the ICU version to add the data library icudtXX.dll, which does not show
// as a dependency.
@@ -1405,7 +1553,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
if (optVerboseLevel > 1)
std::wcout << "Adding ICU version " << icuVersion << '\n';
QString icuLib = QStringLiteral("icudt") + icuVersion
- + QLatin1StringView(windowsSharedLibrarySuffix);;
+ + QLatin1StringView(windowsSharedLibrarySuffix);
// Some packages contain debug dlls of ICU libraries even though it's a C
// library and the official packages do not differentiate (QTBUG-87677)
if (result.isDebug) {
@@ -1448,7 +1596,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
const QmlImportScanResult scanResult =
runQmlImportScanner(qmlDirectory, qmlImportPaths,
- result.directlyUsedQtLibraries.test(QtWidgetsModule),
+ result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
options.platform, debugMatchMode, errorMessage);
if (!scanResult.ok)
return result;
@@ -1478,8 +1626,9 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// QtModule enumeration (and thus controlled by flags) and others.
QStringList deployedQtLibraries;
for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
- if (const quint64 qtm = qtModule(dependentQtLibs.at(i), infix))
- result.usedQtLibraries[qtm] = 1;
+ const qint64 module = qtModule(dependentQtLibs.at(i), infix);
+ if (module >= 0)
+ result.usedQtLibraries[module] = 1;
else
deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
}
@@ -1487,24 +1636,40 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
ModuleBitset disabled = options.disabledLibraries;
if (!usesQml2) {
- disabled[QtQmlModule] = 1;
- disabled[QtQuickModule] = 1;
+ disabled[QtQmlModuleId] = 1;
+ disabled[QtQuickModuleId] = 1;
+ }
+
+ QStringList openSslLibs;
+ if (!options.openSslRootDirectory.isEmpty()) {
+ openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
+ if (openSslLibs.isEmpty()) {
+ *errorMessage = QStringLiteral("Unable to find openSSL libraries in ")
+ + options.openSslRootDirectory;
+ return result;
+ }
+
+ deployedQtLibraries.append(openSslLibs);
}
+ const bool deployOpenSslPlugin = options.forceOpenSslPlugin || !openSslLibs.isEmpty();
+
const QStringList plugins = findQtPlugins(
&result.deployedQtLibraries,
// For non-QML applications, disable QML to prevent it from being pulled in by the
// qtaccessiblequick plugin.
- disabled,
- options.disabledPlugins, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
- libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin);
+ disabled, pluginInfo,
+ options.pluginSelections, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
+ libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
+ options.deployInsightTrackerPlugin, deployOpenSslPlugin);
// Apply options flags and re-add library names.
QString qtGuiLibrary;
for (const auto &qtModule : qtModuleEntries) {
- if (result.deployedQtLibraries.test(qtModule.module)) {
- const QString library = libraryPath(libraryLocation, qtModule.libraryName, qtLibInfix, options.platform, result.isDebug);
+ if (result.deployedQtLibraries.test(qtModule.id)) {
+ const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
+ options.platform, result.isDebug);
deployedQtLibraries.append(library);
- if (qtModule.module == QtGuiModule)
+ if (qtModule.id == QtGuiModuleId)
qtGuiLibrary = library;
}
}
@@ -1518,13 +1683,13 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
if (optVerboseLevel > 1)
std::wcout << "Plugins: " << plugins.join(u',') << '\n';
- if ((result.deployedQtLibraries.test(QtGuiModule)) && platformPlugin.isEmpty()) {
+ if (result.deployedQtLibraries.test(QtGuiModuleId) && platformPlugin.isEmpty()) {
*errorMessage =QStringLiteral("Unable to find the platform plugin.");
return result;
}
if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) {
- const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, options.platform, errorMessage);
+ const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty();
if (options.softwareRasterizer && !dependsOnOpenGl) {
const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1StringView(windowsSharedLibrarySuffix));
@@ -1539,15 +1704,28 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
deployedQtLibraries.push_back(d3dCompiler);
}
}
+ if (options.systemDxc) {
+ const QStringList dxcLibs = findDxc(options.platform, qtBinDir, wordSize);
+ if (!dxcLibs.isEmpty())
+ deployedQtLibraries.append(dxcLibs);
+ else
+ std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
+ }
} // Windows
+ // Add FFmpeg if we deploy the FFmpeg backend
+ if (options.ffmpeg
+ && !plugins.filter(QStringLiteral("ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
+ deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
+ }
+
// Update libraries
if (options.libraries) {
const QString targetPath = options.libraryDirectory.isEmpty() ?
options.directory : options.libraryDirectory;
QStringList libraries = deployedQtLibraries;
if (options.compilerRunTime)
- libraries.append(compilerRunTimeLibs(options.platform, result.isDebug, machineArch));
+ libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug, machineArch));
for (const QString &qtLib : std::as_const(libraries)) {
if (!updateLibrary(qtLib, targetPath, options, errorMessage))
return result;
@@ -1555,7 +1733,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
#if !QT_CONFIG(relocatable)
if (options.patchQt && !options.dryRun) {
- const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", qtLibInfix,
+ const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", infix,
options.platform, result.isDebug)).fileName();
if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
std::wcerr << "Warning: " << *errorMessage << '\n';
@@ -1595,20 +1773,26 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
// for WebKit1-applications. Check direct dependency only.
if (options.quickImports && usesQml2) {
+ const QString targetPath = options.qmlDirectory.isEmpty()
+ ? options.directory + QStringLiteral("/qml")
+ : options.qmlDirectory;
+ if (!createDirectory(targetPath, errorMessage, options.dryRun))
+ return result;
for (const QmlImportScanResult::Module &module : std::as_const(qmlScanResult.modules)) {
- const QString installPath = module.installPath(options.directory);
+ const QString installPath = module.installPath(targetPath);
if (optVerboseLevel > 1)
std::wcout << "Installing: '" << module.name
<< "' from " << module.sourcePath << " to "
<< QDir::toNativeSeparators(installPath) << '\n';
- if (installPath != options.directory && !createDirectory(installPath, errorMessage))
+ if (installPath != targetPath && !createDirectory(installPath, errorMessage, options.dryRun))
return result;
unsigned updateFileFlags = options.updateFileFlags
| SkipQmlDesignerSpecificsDirectories;
unsigned qmlDirectoryFileFlags = 0;
if (options.deployPdb)
qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
- if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform,
+ if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
+ options.platform,
debugMatchMode,
qmlDirectoryFileFlags),
installPath, updateFileFlags, options.json, errorMessage)) {
@@ -1618,7 +1802,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
} // optQuickImports
if (options.translations) {
- if (!options.dryRun && !createDirectory(options.translationsDirectory, errorMessage))
+ if (!createDirectory(options.translationsDirectory, errorMessage, options.dryRun))
return result;
if (!deployTranslations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS")),
result.deployedQtLibraries, options.translationsDirectory, options,
@@ -1632,7 +1816,8 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
}
static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, const char *binaryName,
- const Options &sourceOptions, QString *errorMessage)
+ const PluginInformation &pluginInfo, const Options &sourceOptions,
+ QString *errorMessage)
{
// Copy the web process and its dependencies
const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform);
@@ -1644,29 +1829,32 @@ static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, con
options.binaries.append(options.directory + u'/' + webProcess);
options.quickImports = false;
options.translations = false;
- return deploy(options, qtpathsVariables, errorMessage);
+ return deploy(options, qtpathsVariables, pluginInfo, errorMessage);
}
static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
- const Options &options, bool isDebug, QString *errorMessage)
+ const PluginInformation &pluginInfo, const Options &options,
+ bool isDebug, QString *errorMessage)
{
- static const char *installDataFiles[] = {"icudtl.dat",
- "qtwebengine_devtools_resources.pak",
- "qtwebengine_resources.pak",
- "qtwebengine_resources_100p.pak",
- "qtwebengine_resources_200p.pak"};
+ static const char *installDataFiles[] = { "icudtl.dat",
+ "qtwebengine_devtools_resources.pak",
+ "qtwebengine_resources.pak",
+ "qtwebengine_resources_100p.pak",
+ "qtwebengine_resources_200p.pak",
+ isDebug ? "v8_context_snapshot.debug.bin"
+ : "v8_context_snapshot.bin" };
QByteArray webEngineProcessName(webEngineProcessC);
if (isDebug && platformHasDebugSuffix(options.platform))
webEngineProcessName.append('d');
if (optVerboseLevel)
std::wcout << "Deploying: " << webEngineProcessName.constData() << "...\n";
- if (!deployWebProcess(qtpathsVariables, webEngineProcessName, options, errorMessage))
+ if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
return false;
const QString resourcesSubDir = QStringLiteral("/resources");
const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_DATA"))
+ resourcesSubDir + u'/';
const QString resourcesTargetDir(options.directory + resourcesSubDir);
- if (!createDirectory(resourcesTargetDir, errorMessage))
+ if (!createDirectory(resourcesTargetDir, errorMessage, options.dryRun))
return false;
for (auto installDataFile : installDataFiles) {
if (!updateFile(resourcesSourceDir + QLatin1StringView(installDataFile),
@@ -1683,7 +1871,7 @@ static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
}
if (options.translations) {
// Copy the whole translations directory.
- return createDirectory(options.translationsDirectory, errorMessage)
+ return createDirectory(options.translationsDirectory, errorMessage, options.dryRun)
&& updateFile(translations.absoluteFilePath(), options.translationsDirectory,
options.updateFileFlags, options.json, errorMessage);
}
@@ -1696,7 +1884,7 @@ static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
}
const QString webEngineTranslationsDir = options.translationsDirectory + u'/'
+ translations.fileName();
- if (!createDirectory(webEngineTranslationsDir, errorMessage))
+ if (!createDirectory(webEngineTranslationsDir, errorMessage, options.dryRun))
return false;
return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir,
options.updateFileFlags, options.json, errorMessage);
@@ -1722,55 +1910,105 @@ int main(int argc, char **argv)
Options options;
QString errorMessage;
- { // Command line
- QCommandLineParser parser;
- QString errorMessage;
- const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
- if (result & CommandLineParseError)
- std::wcerr << errorMessage << "\n\n";
- if (result & CommandLineParseHelpRequested)
- std::fputs(qPrintable(helpText(parser)), stdout);
- if (result & CommandLineParseError)
+ // Early parse the --qmake and --qtpaths options, because they are needed to determine the
+ // options that select/deselect Qt modules.
+ {
+ int result = parseEarlyArguments(QCoreApplication::arguments(), &options, &errorMessage);
+ if (result & CommandLineParseError) {
+ std::wcerr << "Error: " << errorMessage << "\n";
return 1;
- if (result & CommandLineParseHelpRequested)
- return 0;
+ }
}
const QMap<QString, QString> qtpathsVariables =
queryQtPaths(options.qtpathsBinary, &errorMessage);
const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
- options.platform = platformFromMkSpec(xSpec);
-
if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
|| !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
std::wcerr << "Unable to query qtpaths: " << errorMessage << '\n';
return 1;
}
+ options.platform = platformFromMkSpec(xSpec);
+ // We are on MSVC and not crosscompiling. We need the host arch
+ if (options.platform == WindowsDesktopMsvc) {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ switch (si.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ case PROCESSOR_ARCHITECTURE_IA64:
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ options.platform |= IntelBased;
+ break;
+ case PROCESSOR_ARCHITECTURE_ARM:
+ case PROCESSOR_ARCHITECTURE_ARM64:
+ options.platform |= ArmBased;
+ break;
+ default:
+ options.platform = UnknownPlatform;
+ }
+ }
if (options.platform == UnknownPlatform) {
std::wcerr << "Unsupported platform " << xSpec << '\n';
return 1;
}
+ // Read the Qt module information from the Qt installation directory.
+ const QString modulesDir
+ = qtpathsVariables.value(QLatin1String("QT_INSTALL_ARCHDATA"))
+ + QLatin1String("/modules");
+ const QString translationsDir
+ = qtpathsVariables.value(QLatin1String("QT_INSTALL_TRANSLATIONS"));
+ if (!qtModuleEntries.populate(modulesDir, translationsDir, optVerboseLevel > 1,
+ &errorMessage)) {
+ std::wcerr << "Error: " << errorMessage << "\n";
+ return 1;
+ }
+ assignKnownModuleIds();
+
+ // Read the Qt plugin types information from the Qt installation directory.
+ PluginInformation pluginInfo{};
+ pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
+
+ // Parse the full command line.
+ {
+ QCommandLineParser parser;
+ QString errorMessage;
+ const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
+ if (result & CommandLineParseError)
+ std::wcerr << errorMessage << "\n\n";
+ if (result & CommandLineVersionRequested) {
+ std::fputs(QT_VERSION_STR "\n", stdout);
+ return 0;
+ }
+ if (result & CommandLineParseHelpRequested)
+ std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
+ if (result & CommandLineParseError)
+ return 1;
+ if (result & CommandLineParseHelpRequested)
+ return 0;
+ }
+
// Create directories
- if (!createDirectory(options.directory, &errorMessage)) {
+ if (!createDirectory(options.directory, &errorMessage, options.dryRun)) {
std::wcerr << errorMessage << '\n';
return 1;
}
if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory
- && !createDirectory(options.libraryDirectory, &errorMessage)) {
+ && !createDirectory(options.libraryDirectory, &errorMessage, options.dryRun)) {
std::wcerr << errorMessage << '\n';
return 1;
}
- const DeployResult result = deploy(options, qtpathsVariables, &errorMessage);
+ const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
if (!result) {
std::wcerr << errorMessage << '\n';
return 1;
}
- if (result.deployedQtLibraries.test(QtWebEngineCoreModule)) {
- if (!deployWebEngineCore(qtpathsVariables, options, result.isDebug, &errorMessage)) {
+ if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
+ if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
+ &errorMessage)) {
std::wcerr << errorMessage << '\n';
return 1;
}