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.cpp1277
1 files changed, 790 insertions, 487 deletions
diff --git a/src/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp
index cb884cc366..837d4c7bbc 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>
@@ -22,137 +24,61 @@
#define IMAGE_FILE_MACHINE_ARM64 0xaa64
#endif
+#include <QtCore/private/qconfig_p.h>
+
#include <algorithm>
+#include <cstdio>
#include <iostream>
#include <iterator>
-#include <cstdio>
+#include <unordered_map>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-enum QtModule
-#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC)
- : quint64
-#endif
-{
- QtBluetoothModule = 0x0000000000000001,
- QtConcurrentModule = 0x0000000000000002,
- QtCoreModule = 0x0000000000000004,
- QtDeclarativeModule = 0x0000000000000008,
- QtDesignerComponents = 0x0000000000000010,
- QtDesignerModule = 0x0000000000000020,
- QtGuiModule = 0x0000000000000040,
- QtHelpModule = 0x0000000000000080,
- QtMultimediaModule = 0x0000000000000100,
- QtMultimediaWidgetsModule = 0x0000000000000200,
- QtMultimediaQuickModule = 0x0000000000000400,
- QtNetworkModule = 0x0000000000000800,
- QtNfcModule = 0x0000000000001000,
- QtOpenGLModule = 0x0000000000002000,
- QtOpenGLWidgetsModule = 0x0000000000004000,
- QtPositioningModule = 0x0000000000008000,
- QtPrintSupportModule = 0x0000000000010000,
- QtQmlModule = 0x0000000000020000,
- QtQuickModule = 0x0000000000040000,
- QtQuickParticlesModule = 0x0000000000080000,
- QtScriptModule = 0x0000000000100000,
- QtScriptToolsModule = 0x0000000000200000,
- QtSensorsModule = 0x0000000000400000,
- QtSerialPortModule = 0x0000000000800000,
- QtSqlModule = 0x0000000001000000,
- QtSvgModule = 0x0000000002000000,
- QtSvgWidgetsModule = 0x0000000004000000,
- QtTestModule = 0x0000000008000000,
- QtWidgetsModule = 0x0000000010000000,
- QtWinExtrasModule = 0x0000000020000000,
- QtXmlModule = 0x0000000040000000,
- QtQuickWidgetsModule = 0x0000000100000000,
- QtWebSocketsModule = 0x0000000200000000,
- QtWebEngineCoreModule = 0x0000000800000000,
- QtWebEngineModule = 0x0000001000000000,
- QtWebEngineWidgetsModule = 0x0000002000000000,
- QtQmlToolingModule = 0x0000004000000000,
- Qt3DCoreModule = 0x0000008000000000,
- Qt3DRendererModule = 0x0000010000000000,
- Qt3DQuickModule = 0x0000020000000000,
- Qt3DQuickRendererModule = 0x0000040000000000,
- Qt3DInputModule = 0x0000080000000000,
- QtLocationModule = 0x0000100000000000,
- QtWebChannelModule = 0x0000200000000000,
- QtTextToSpeechModule = 0x0000400000000000,
- QtSerialBusModule = 0x0000800000000000,
- QtGamePadModule = 0x0001000000000000,
- Qt3DAnimationModule = 0x0002000000000000,
- QtWebViewModule = 0x0004000000000000,
- Qt3DExtrasModule = 0x0008000000000000,
- QtShaderToolsModule = 0x0010000000000000
-};
+static QtModuleInfoStore qtModuleEntries;
-struct QtModuleEntry {
- quint64 module;
- const char *option;
- const char *libraryName;
- const char *translation;
-};
+#define DECLARE_KNOWN_MODULE(name) \
+ static size_t Qt##name ## ModuleId = QtModule::InvalidId
-static QtModuleEntry qtModuleEntries[] = {
- { QtBluetoothModule, "bluetooth", "Qt6Bluetooth", nullptr },
- { QtConcurrentModule, "concurrent", "Qt6Concurrent", "qtbase" },
- { QtCoreModule, "core", "Qt6Core", "qtbase" },
- { QtDeclarativeModule, "declarative", "Qt6Declarative", "qtquick1" },
- { 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 }
-};
+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);
-enum QtPlugin {
- QtVirtualKeyboardPlugin = 0x1
-};
+#define DEFINE_KNOWN_MODULE(name) \
+ m[QLatin1String("Qt6" #name)] = &Qt##name ## ModuleId
+
+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";
@@ -162,14 +88,43 @@ static inline QString webProcessBinary(const char *binaryName, Platform p)
return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess;
}
-static QByteArray formatQtModules(quint64 mask, bool option = false)
+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 & 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;
@@ -177,8 +132,6 @@ static QByteArray formatQtModules(quint64 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;
@@ -225,12 +178,14 @@ struct Options {
bool quickImports = true;
bool translations = true;
bool systemD3dCompiler = true;
+ bool systemDxc = true;
bool compilerRunTime = false;
- unsigned disabledPlugins = 0;
bool softwareRasterizer = true;
+ bool ffmpeg = true;
+ PluginSelections pluginSelections;
Platform platform = WindowsDesktopMsvc;
- quint64 additionalLibraries = 0;
- quint64 disabledLibraries = 0;
+ ModuleBitset additionalLibraries;
+ ModuleBitset disabledLibraries;
unsigned updateFileFlags = 0;
QStringList qmlDirectories; // Project's QML files.
QStringList qmlImportPaths; // Custom QML module locations.
@@ -240,6 +195,8 @@ struct Options {
QStringList languages;
QString libraryDirectory;
QString pluginDirectory;
+ QString openSslRootDirectory;
+ QString qmlDirectory;
QStringList binaries;
JsonOutput *json = nullptr;
ListOption list = ListNone;
@@ -248,6 +205,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.
@@ -268,14 +227,101 @@ static inline QString findBinary(const QString &directory, Platform platform)
static QString msgFileDoesNotExist(const QString & file)
{
- return u'"' + QDir::toNativeSeparators(file) + QStringLiteral("\" does not exist.");
+ return u'"' + QDir::toNativeSeparators(file) + "\" does not exist."_L1;
}
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)
{
@@ -283,29 +329,21 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
using OptionPtrVector = QList<CommandLineOptionPtr>;
parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
- parser->setApplicationDescription(QStringLiteral("Qt Deploy Tool ") + QT_VERSION_STR ""_L1
- + "\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n"
+ parser->setApplicationDescription(u"Qt Deploy Tool " QT_VERSION_STR
+ "\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n"
"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>"_L1);
+ "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."),
@@ -317,6 +355,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);
@@ -352,6 +401,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);
@@ -384,15 +457,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);
@@ -405,6 +478,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"
@@ -418,22 +505,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());
@@ -448,6 +542,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;
@@ -455,12 +551,15 @@ 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
@@ -475,8 +574,19 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
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.";
@@ -502,6 +612,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)) {
@@ -511,19 +635,21 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
options->patchQt = !parser->isSet(noPatchQtOption);
options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
-
- for (int i = 0; i < qtModulesCount; ++i) {
- if (parser->isSet(*enabledModuleOptions.at(i)))
- options->additionalLibraries |= qtModuleEntries[i].module;
- if (parser->isSet(*disabledModuleOptions.at(i)))
- options->disabledLibraries |= qtModuleEntries[i].module;
+ if (insightTrackerModuleAvailable)
+ options->deployInsightTrackerPlugin = parser->isSet(deployInsightTrackerOption);
+
+ 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 & QtQuickModule)
- options->additionalLibraries |= QtQmlModule;
- if (options->additionalLibraries & QtDesignerComponents)
- options->additionalLibraries |= QtDesignerModule;
+ 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);
@@ -544,16 +670,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();
@@ -565,33 +681,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);
@@ -625,6 +714,7 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
} // directory.
// Remaining files or plugin directories
+ bool multipleDirs = false;
for (int i = 1; i < posArgs.size(); ++i) {
const QFileInfo fi(QDir::cleanPath(posArgs.at(i)));
const QString path = fi.absoluteFilePath();
@@ -638,10 +728,17 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (const QString &library : libraries)
options->binaries.append(path + u'/' + library);
} else {
+ if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
+ multipleDirs = true;
options->binaries.append(path);
}
}
- 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;
}
@@ -658,20 +755,37 @@ 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;
- QString moduleHelp =
+ QString moduleHelp;
+ moduleHelp +=
"\n\nQt libraries can be added by passing their name (-xml) or removed by passing\n"
"the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
- moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(0xFFFFFFFFFFFFFFFFull, true)));
- moduleHelp += u'\n';
+ ModuleBitset mask;
+ moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
+ 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;
}
@@ -695,7 +809,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;
@@ -703,7 +818,7 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin
// Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we
// are run the 2nd time (updating). We want to check against the Qt bin dir libraries
const int start = result->size();
- for (const QString &lib : qAsConst(dependentLibs)) {
+ for (const QString &lib : std::as_const(dependentLibs)) {
if (isQtModule(lib)) {
const QString path = normalizeFileName(qtBinDir + u'/' + QFileInfo(lib).fileName());
if (!result->contains(path))
@@ -752,7 +867,7 @@ static inline QStringList qmlCacheFileFilters()
}
// File entry filter function for updateFile() that returns a list of files for
-// QML import trees: DLLs (matching debgug) and .qml/,js, etc.
+// QML import trees: DLLs (matching debug) and .qml/,js, etc.
class QmlDirectoryFileEntryFunction {
public:
enum Flags {
@@ -760,13 +875,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) {
@@ -782,6 +903,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;
@@ -798,63 +930,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[] =
-{
- {"qml1tooling", QtDeclarativeModule},
-#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},
- {"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}
-};
-
-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'/');
@@ -869,104 +948,198 @@ 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;
}
-QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules,
- unsigned disabledPlugins,
- const QString &qtPluginsDirName, const QString &libraryLocation,
- const QString &infix,
- DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin)
+// Return the path if a plugin is to be deployed
+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 (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 (subDirName == u"designer")
+ return pluginPath;
+
+ QStringList dependentQtLibs;
QString errorMessage;
+ if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
+ &errorMessage, &dependentQtLibs)) {
+ 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 disabledNeededQtModules;
+ disabledNeededQtModules = *pluginNeededQtModules & disabledQtModules;
+ if (disabledNeededQtModules.any()) {
+ if (optVerboseLevel) {
+ std::wcout << "Skipping plugin " << plugin
+ << " due to disabled dependencies ("
+ << formatQtModules(disabledNeededQtModules).constData() << ").\n";
+ }
+ return {};
+ }
+
+ 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,
+ const PluginInformation &pluginInfo, const PluginSelections &pluginSelections,
+ const QString &qtPluginsDirName, const QString &libraryLocation,
+ const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform,
+ QString *platformPlugin, bool deployInsightTrackerPlugin,
+ bool deployOpenSslPlugin)
+{
if (qtPluginsDirName.isEmpty())
return QStringList();
QDir pluginsDir(qtPluginsDirName);
QStringList result;
- const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList("*"_L1), QDir::Dirs | QDir::NoDotAndDotDot);
+ 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 (module & *usedQtModules) {
- 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 & 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");
- break;
- case Unix:
- filter = QStringLiteral("libqxcb");
- break;
- case UnknownPlatform:
- break;
- }
- } else {
- filter = "*"_L1;
- }
- const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter);
+ const QStringList plugins =
+ findSharedLibraries(subDir, platform, debugMatchMode, QString());
for (const QString &plugin : plugins) {
- // Filter out disabled plugins
- if ((disabledPlugins & QtVirtualKeyboardPlugin)
- && plugin.startsWith("qtvirtualkeyboardplugin"_L1)) {
- continue;
- }
- const QString pluginPath = subDir.absoluteFilePath(plugin);
- if (isPlatformPlugin)
- *platformPlugin = pluginPath;
- QStringList dependentQtLibs;
- quint64 neededModules = 0;
- if (findDependentQtLibraries(libraryLocation, pluginPath, platform, &errorMessage, &dependentQtLibs)) {
- for (int d = 0; d < dependentQtLibs.size(); ++ d)
- neededModules |= qtModule(dependentQtLibs.at(d), infix);
- } else {
- std::wcerr << "Warning: Cannot determine dependencies of "
- << QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
- }
- if (const quint64 missingModules = neededModules & disabledQtModules) {
- if (optVerboseLevel) {
- std::wcout << "Skipping plugin " << plugin
- << " due to disabled dependencies ("
- << formatQtModules(missingModules).constData() << ").\n";
- }
- } else {
- if (const quint64 missingModules = (neededModules & ~*usedQtModules)) {
+ ModuleBitset pluginNeededQtModules;
+ const QString pluginPath =
+ deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
+ disabledQtModules, pluginSelections, libraryLocation, infix,
+ platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
+ if (!pluginPath.isEmpty()) {
+ if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
+ *platformPlugin = subDir.absoluteFilePath(plugin);
+ result.append(pluginPath);
+
+ const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
+ if (missingModules.any()) {
*usedQtModules |= missingModules;
- if (optVerboseLevel)
- std::wcout << "Adding " << formatQtModules(missingModules).constData() << " for " << plugin << '\n';
+ missingQtModulesAdded = true;
+ if (optVerboseLevel) {
+ std::wcout << "Adding " << formatQtModules(missingModules).constData()
+ << " for " << plugin << " from plugin type: " << subDirName << '\n';
+ }
}
- result.append(pluginPath);
}
} // 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;
}
-static QStringList translationNameFilters(quint64 modules, const QString &prefix)
+static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
{
QStringList result;
for (const auto &qtModule : qtModuleEntries) {
- if ((qtModule.module & modules) && qtModule.translation) {
- const QString name = QLatin1StringView(qtModule.translation) +
- u'_' + prefix + QStringLiteral(".qm");
+ 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);
}
@@ -974,7 +1147,7 @@ static QStringList translationNameFilters(quint64 modules, const QString &prefix
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,
QString *errorMessage)
{
@@ -998,7 +1171,7 @@ static bool deployTranslations(const QString &sourcePath, quint64 usedQtModules,
const QString absoluteTarget = QFileInfo(target).absoluteFilePath();
const QString binary = QStringLiteral("lconvert");
QStringList arguments;
- for (const QString &prefix : qAsConst(prefixes)) {
+ for (const QString &prefix : std::as_const(prefixes)) {
arguments.clear();
const QString targetFile = QStringLiteral("qt_") + prefix + QStringLiteral(".qm");
arguments.append(QStringLiteral("-o"));
@@ -1006,7 +1179,12 @@ static bool deployTranslations(const QString &sourcePath, quint64 usedQtModules,
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(),
@@ -1026,32 +1204,82 @@ static bool deployTranslations(const QString &sourcePath, quint64 usedQtModules,
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; }
bool success = false;
bool isDebug = false;
- quint64 directlyUsedQtLibraries = 0;
- quint64 usedQtLibraries = 0;
- quint64 deployedQtLibraries = 0;
+ ModuleBitset directlyUsedQtLibraries;
+ ModuleBitset usedQtLibraries;
+ ModuleBitset deployedQtLibraries;
};
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;
}
@@ -1092,27 +1320,48 @@ 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.
QString vcRedistDirName = vcRedistDir();
@@ -1136,11 +1385,11 @@ static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned
const QStringList countryCodes = vcRedistDir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Dirs);
if (!countryCodes.isEmpty()) // Pre MSVC2017
releaseRedistDir += u'/' + countryCodes.constFirst();
- QFileInfo fi(releaseRedistDir + u'/' + QStringLiteral("vc_redist.")
- + machineArchString + QStringLiteral(".exe"));
+ QFileInfo fi(releaseRedistDir + "/vc_redist."_L1
+ + machineArchString + ".exe"_L1);
if (!fi.isFile()) { // Pre MSVC2017/15.5
- fi.setFile(releaseRedistDir + u'/' + QStringLiteral("vcredist_")
- + machineArchString + QStringLiteral(".exe"));
+ fi.setFile(releaseRedistDir + "/vcredist_"_L1
+ + machineArchString + ".exe"_L1);
}
if (fi.isFile())
redistFiles.append(fi.absoluteFilePath());
@@ -1170,16 +1419,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)
@@ -1212,16 +1451,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);
@@ -1268,17 +1505,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 < directDependencyCount; ++m) {
- const quint64 module = qtModule(dependentQtLibs.at(m), infix);
- result.directlyUsedQtLibraries |= module;
- if (module == QtCoreModule)
- qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform);
+ for (int m = 0; m < dependentQtLibs.size(); ++m) {
+ const qint64 module = qtModule(dependentQtLibs.at(m), infix);
+ if (module >= 0)
+ result.directlyUsedQtLibraries[module] = 1;
}
- const bool usesQml2 = !(options.disabledLibraries & QtQmlModule)
- && ((result.directlyUsedQtLibraries & (QtQmlModule | QtQuickModule | Qt3DQuickModule))
- || (options.additionalLibraries & 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()) << ' '
@@ -1300,7 +1537,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.
@@ -1309,7 +1546,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) {
@@ -1321,7 +1558,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
}
icuLibs.push_back(icuLib);
}
- for (const QString &icuLib : qAsConst(icuLibs)) {
+ for (const QString &icuLib : std::as_const(icuLibs)) {
const QString icuPath = findInPath(icuLib);
if (icuPath.isEmpty()) {
*errorMessage = QStringLiteral("Unable to locate ICU library ") + icuLib;
@@ -1347,30 +1584,30 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
if (!qmlDirectory.isEmpty())
qmlDirectories.append(qmlDirectory);
}
- for (const QString &qmlDirectory : qAsConst(qmlDirectories)) {
+ for (const QString &qmlDirectory : std::as_const(qmlDirectories)) {
if (optVerboseLevel >= 1)
std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
const QmlImportScanResult scanResult =
runQmlImportScanner(qmlDirectory, qmlImportPaths,
- result.directlyUsedQtLibraries & QtWidgetsModule,
+ result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
options.platform, debugMatchMode, errorMessage);
if (!scanResult.ok)
return result;
qmlScanResult.append(scanResult);
// Additional dependencies of QML plugins.
- for (const QString &plugin : qAsConst(qmlScanResult.plugins)) {
+ for (const QString &plugin : std::as_const(qmlScanResult.plugins)) {
if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &detectedDebug, &machineArch))
return result;
}
if (optVerboseLevel >= 1) {
std::wcout << "QML imports:\n";
- for (const QmlImportScanResult::Module &mod : qAsConst(qmlScanResult.modules)) {
+ for (const QmlImportScanResult::Module &mod : std::as_const(qmlScanResult.modules)) {
std::wcout << " '" << mod.name << "' "
<< QDir::toNativeSeparators(mod.sourcePath) << '\n';
}
if (optVerboseLevel >= 2) {
std::wcout << "QML plugins:\n";
- for (const QString &p : qAsConst(qmlScanResult.plugins))
+ for (const QString &p : std::as_const(qmlScanResult.plugins))
std::wcout << " " << QDir::toNativeSeparators(p) << '\n';
}
}
@@ -1382,28 +1619,50 @@ 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;
+ 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.
}
result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
+ ModuleBitset disabled = options.disabledLibraries;
+ if (!usesQml2) {
+ 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.
- options.disabledLibraries | (usesQml2 ? 0 : (QtQmlModule | QtQuickModule)),
- 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 & 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;
}
}
@@ -1417,13 +1676,13 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
if (optVerboseLevel > 1)
std::wcout << "Plugins: " << plugins.join(u',') << '\n';
- if ((result.deployedQtLibraries & 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));
@@ -1438,30 +1697,43 @@ 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));
- for (const QString &qtLib : qAsConst(libraries)) {
+ 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;
}
+#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();
-#ifndef QT_RELOCATABLE
if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
std::wcerr << "Warning: " << *errorMessage << '\n';
errorMessage->clear();
}
-#endif
}
+#endif // QT_CONFIG(relocatable)
} // optLibraries
// Update plugins
@@ -1491,44 +1763,39 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
} // optPlugins
// Update Quick imports
- const bool usesQuick1 = result.deployedQtLibraries & QtDeclarativeModule;
// 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 && (usesQuick1 || usesQml2)) {
- if (usesQml2) {
- for (const QmlImportScanResult::Module &module : qAsConst(qmlScanResult.modules)) {
- const QString installPath = module.installPath(options.directory);
- if (optVerboseLevel > 1)
- std::wcout << "Installing: '" << module.name
- << "' from " << module.sourcePath << " to "
- << QDir::toNativeSeparators(installPath) << '\n';
- if (installPath != options.directory && !createDirectory(installPath, errorMessage))
- return result;
- unsigned updateFileFlags = options.updateFileFlags | SkipQmlDesignerSpecificsDirectories;
- unsigned qmlDirectoryFileFlags = 0;
- if (options.deployPdb)
- qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
- if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform, debugMatchMode, qmlDirectoryFileFlags),
- installPath, updateFileFlags, options.json, errorMessage)) {
- return result;
- }
- }
- } // Quick 2
- if (usesQuick1) {
- const QString quick1ImportPath =
- qtpathsVariables.value(QStringLiteral("QT_INSTALL_IMPORTS"));
- const QmlDirectoryFileEntryFunction qmlFileEntryFunction(options.platform, debugMatchMode, options.deployPdb ? QmlDirectoryFileEntryFunction::DeployPdb : 0);
- QStringList quick1Imports(QStringLiteral("Qt"));
- for (const QString &quick1Import : qAsConst(quick1Imports)) {
- const QString sourceFile = quick1ImportPath + slash + quick1Import;
- if (!updateFile(sourceFile, qmlFileEntryFunction, options.directory, options.updateFileFlags, options.json, errorMessage))
- return result;
+ 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(targetPath);
+ if (optVerboseLevel > 1)
+ std::wcout << "Installing: '" << module.name
+ << "' from " << module.sourcePath << " to "
+ << QDir::toNativeSeparators(installPath) << '\n';
+ 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(module.sourcePath,
+ options.platform,
+ debugMatchMode,
+ qmlDirectoryFileFlags),
+ installPath, updateFileFlags, options.json, errorMessage)) {
+ return result;
}
- } // Quick 1
+ }
} // 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,
@@ -1542,7 +1809,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);
@@ -1554,29 +1822,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),
@@ -1593,7 +1864,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);
}
@@ -1606,7 +1877,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);
@@ -1624,63 +1895,95 @@ int main(int argc, char **argv)
const QByteArray qtBinPath = QFile::encodeName(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
QByteArray path = qgetenv("PATH");
if (!path.contains(qtBinPath)) { // QTBUG-39177, ensure Qt is in the path so that qt.conf is taken into account.
- path += ';';
- path += qtBinPath;
+ path.prepend(QDir::listSeparator().toLatin1());
+ path.prepend(qtBinPath);
qputenv("PATH", path);
}
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);
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 & 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;
}