Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "utils.h"
5#include "qmlutils.h"
6#include "qtmoduleinfo.h"
7#include "qtplugininfo.h"
8
9#include <QtCore/QCommandLineOption>
10#include <QtCore/QCommandLineParser>
11#include <QtCore/QDir>
12#include <QtCore/QFileInfo>
13#include <QtCore/QCoreApplication>
14#include <QtCore/QJsonDocument>
15#include <QtCore/QJsonObject>
16#include <QtCore/QJsonArray>
17#include <QtCore/QList>
18#include <QtCore/QOperatingSystemVersion>
19#include <QtCore/QSharedPointer>
20#include <QtCore/QXmlStreamWriter>
21#include <QtNetwork/QSslCertificate>
22
23#ifdef Q_OS_WIN
24#include <QtCore/qt_windows.h>
25#else
26#define IMAGE_FILE_MACHINE_ARM64 0xaa64
27#endif
28
29#include <QtCore/private/qconfig_p.h>
30
31#include <algorithm>
32#include <cstdio>
33#include <iostream>
34#include <iterator>
35#include <unordered_map>
36
37QT_BEGIN_NAMESPACE
38
39using namespace Qt::StringLiterals;
40
42
43#define DECLARE_KNOWN_MODULE(name)
44 static size_t Qt##name ## ModuleId = QtModule::InvalidId
45
49DECLARE_KNOWN_MODULE(DesignerComponents);
54DECLARE_KNOWN_MODULE(WebEngineCore);
56
57#define DEFINE_KNOWN_MODULE(name)
58 m[QLatin1String("Qt6" #name)] = &Qt##name ## ModuleId
59
61{
62 std::unordered_map<QString, size_t *> m;
63 DEFINE_KNOWN_MODULE(3DQuick);
65 DEFINE_KNOWN_MODULE(Designer);
66 DEFINE_KNOWN_MODULE(DesignerComponents);
69 DEFINE_KNOWN_MODULE(QmlTooling);
71 DEFINE_KNOWN_MODULE(WebEngineCore);
72 DEFINE_KNOWN_MODULE(Widgets);
73 for (size_t i = 0; i < qtModuleEntries.size(); ++i) {
74 const QtModule &module = qtModuleEntries.moduleById(i);
75 auto it = m.find(module.name);
76 if (it == m.end())
77 continue;
78 *(it->second) = i;
79 }
80}
81
82#undef DECLARE_KNOWN_MODULE
83#undef DEFINE_KNOWN_MODULE
84
85static const char webEngineProcessC[] = "QtWebEngineProcess";
86
87static inline QString webProcessBinary(const char *binaryName, Platform p)
88{
89 const QString webProcess = QLatin1StringView(binaryName);
90 return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess;
91}
92
93static QString moduleNameToOptionName(const QString &moduleName, bool internal)
94{
95 QString result = moduleName
96 .mid(3) // strip the "Qt6" prefix
97 .toLower();
98 if (result == u"help"_s)
99 result.prepend("qt"_L1);
100 if (internal)
101 result.append("Internal"_L1);
102 return result;
103}
104
105static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
106{
107 QByteArray result;
108 for (const auto &qtModule : qtModuleEntries) {
109 if (mask.test(qtModule.id)) {
110 if (!result.isEmpty())
111 result.append(' ');
112 result.append(option
113 ? moduleNameToOptionName(qtModule.name, qtModule.internal).toUtf8()
114 : qtModule.name.toUtf8());
115 }
116 }
117 return result;
118}
119
121{
122 QString result(u'\n');
123 for (const auto &pair : pluginInfo.typeMap()) {
124 result += pair.first;
125 result += u": \n";
126 for (const QString &plugin : pair.second) {
127 result += u" ";
128 result += plugin;
129 result += u'\n';
130 }
131 }
132 return result;
133}
134
135static Platform platformFromMkSpec(const QString &xSpec)
136{
137 if (xSpec.startsWith("win32-"_L1)) {
138 if (xSpec.contains("clang-g++"_L1))
140 if (xSpec.contains("clang-msvc++"_L1))
142 if (xSpec.contains("arm"_L1))
144 if (xSpec.contains("g++"_L1))
145 return WindowsDesktopMinGW;
146
147 return WindowsDesktopMsvc;
148 }
149 return UnknownPlatform;
150}
151
152// Helpers for exclusive options, "-foo", "--no-foo"
158
159static ExlusiveOptionValue parseExclusiveOptions(const QCommandLineParser *parser,
160 const QCommandLineOption &enableOption,
161 const QCommandLineOption &disableOption)
162{
163 const bool enabled = parser->isSet(enableOption);
164 const bool disabled = parser->isSet(disableOption);
165 if (enabled) {
166 if (disabled) {
167 std::wcerr << "Warning: both -" << enableOption.names().first()
168 << " and -" << disableOption.names().first() << " were specified, defaulting to -"
169 << enableOption.names().first() << ".\n";
170 }
171 return OptionEnabled;
172 }
173 return disabled ? OptionDisabled : OptionAuto;
174}
175
176struct Options {
182
183 bool plugins = true;
184 bool libraries = true;
185 bool quickImports = true;
186 bool translations = true;
187 bool systemD3dCompiler = true;
188 bool systemDxc = true;
189 bool compilerRunTime = false;
191 bool ffmpeg = true;
196 unsigned updateFileFlags = 0;
197 QStringList qmlDirectories; // Project's QML files.
198 QStringList qmlImportPaths; // Custom QML module locations.
199 int qmlImportTimeout = 30000;
202 QString translationsDirectory; // Translations target directory
209 JsonOutput *json = nullptr;
212 bool deployPdb = false;
213 bool dryRun = false;
214 bool patchQt = true;
217 bool forceOpenSslPlugin = false;
218 bool createAppx = false;
220};
221
222// Return binary to be deployed from folder, ignore pre-existing web engine process.
223static inline QString findBinary(const QString &directory, Platform platform)
224{
225 const QStringList nameFilters = (platform & WindowsBased) ?
226 QStringList(QStringLiteral("*.exe")) : QStringList();
227 const QFileInfoList &binaries =
228 QDir(QDir::cleanPath(directory)).entryInfoList(nameFilters, QDir::Files | QDir::Executable);
229 for (const QFileInfo &binaryFi : binaries) {
230 const QString binary = binaryFi.fileName();
231 if (!binary.contains(QLatin1StringView(webEngineProcessC), Qt::CaseInsensitive)) {
232 return binaryFi.absoluteFilePath();
233 }
234 }
235 return QString();
236}
237
238static QString msgFileDoesNotExist(const QString & file)
239{
240 return u'"' + QDir::toNativeSeparators(file) + "\" does not exist."_L1;
241}
242
248
250{
251 return {
252 u"qmake"_s,
253 u"Use specified qmake instead of qmake from PATH. Deprecated, use qtpaths instead."_s,
254 u"path"_s
255 };
256}
257
259{
260 return {
261 u"qtpaths"_s,
262 u"Use specified qtpaths.exe instead of qtpaths.exe from PATH."_s,
263 u"path"_s
264 };
265}
266
268{
269 return {
270 u"verbose"_s,
271 u"Verbose level (0-2)."_s,
272 u"level"_s
273 };
274}
275
276static int parseEarlyArguments(const QStringList &arguments, Options *options,
277 QString *errorMessage)
278{
279 QCommandLineParser parser;
280 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
281
282 QCommandLineOption qmakeOption = createQMakeOption();
283 parser.addOption(qmakeOption);
284
285 QCommandLineOption qtpathsOption = createQtPathsOption();
286 parser.addOption(qtpathsOption);
287
288 QCommandLineOption verboseOption = createVerboseOption();
289 parser.addOption(verboseOption);
290
291 // Deliberately don't check for errors. We want to ignore options we don't know about.
292 parser.parse(arguments);
293
294 if (parser.isSet(qmakeOption) && parser.isSet(qtpathsOption)) {
295 *errorMessage = QStringLiteral("-qmake and -qtpaths are mutually exclusive.");
297 }
298
299 if (parser.isSet(qmakeOption) && optVerboseLevel >= 1)
300 std::wcerr << "Warning: -qmake option is deprecated. Use -qtpaths instead.\n";
301
302 if (parser.isSet(qtpathsOption) || parser.isSet(qmakeOption)) {
303 const QString qtpathsArg = parser.isSet(qtpathsOption) ? parser.value(qtpathsOption)
304 : parser.value(qmakeOption);
305
306 const QString qtpathsBinary = QDir::cleanPath(qtpathsArg);
307 const QFileInfo fi(qtpathsBinary);
308 if (!fi.exists()) {
309 *errorMessage = msgFileDoesNotExist(qtpathsBinary);
311 }
312
313 if (!fi.isExecutable()) {
314 *errorMessage = u'"' + QDir::toNativeSeparators(qtpathsBinary)
315 + QStringLiteral("\" is not an executable.");
317 }
318 options->qtpathsBinary = qtpathsBinary;
319 }
320
321 if (parser.isSet(verboseOption)) {
322 bool ok;
323 const QString value = parser.value(verboseOption);
324 optVerboseLevel = value.toInt(&ok);
325 if (!ok || optVerboseLevel < 0) {
326 *errorMessage = QStringLiteral("Invalid value \"%1\" passed for verbose level.")
327 .arg(value);
329 }
330 }
331
332 return 0;
333}
334
335static inline int parseArguments(const QStringList &arguments, QCommandLineParser *parser,
336 Options *options, QString *errorMessage)
337{
338 using CommandLineOptionPtr = QSharedPointer<QCommandLineOption>;
339 using OptionPtrVector = QList<CommandLineOptionPtr>;
340
341 parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
342 parser->setApplicationDescription(u"Qt Deploy Tool " QT_VERSION_STR
343 "\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n"
344 "installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n\n"
345 "If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>"_s);
346 const QCommandLineOption helpOption = parser->addHelpOption();
347 const QCommandLineOption versionOption = parser->addVersionOption();
348
349 QCommandLineOption dirOption(QStringLiteral("dir"),
350 QStringLiteral("Use directory instead of binary directory."),
351 QStringLiteral("directory"));
352 parser->addOption(dirOption);
353
354 // Add early options to have them available in the help text.
355 parser->addOption(createQMakeOption());
356 parser->addOption(createQtPathsOption());
357
358 QCommandLineOption libDirOption(QStringLiteral("libdir"),
359 QStringLiteral("Copy libraries to path."),
360 QStringLiteral("path"));
361 parser->addOption(libDirOption);
362
363 QCommandLineOption pluginDirOption(QStringLiteral("plugindir"),
364 QStringLiteral("Copy plugins to path."),
365 QStringLiteral("path"));
366 parser->addOption(pluginDirOption);
367
368 const QCommandLineOption translationDirOption(
369 u"translationdir"_s,
370 u"Copy translations to path."_s,
371 u"path"_s);
372 parser->addOption(translationDirOption);
373
374 QCommandLineOption qmlDeployDirOption(QStringLiteral("qml-deploy-dir"),
375 QStringLiteral("Copy qml files to path."),
376 QStringLiteral("path"));
377 parser->addOption(qmlDeployDirOption);
378
379 QCommandLineOption debugOption(QStringLiteral("debug"),
380 QStringLiteral("Assume debug binaries."));
381 parser->addOption(debugOption);
382 QCommandLineOption releaseOption(QStringLiteral("release"),
383 QStringLiteral("Assume release binaries."));
384 parser->addOption(releaseOption);
385 QCommandLineOption releaseWithDebugInfoOption(QStringLiteral("release-with-debug-info"),
386 QStringLiteral("Assume release binaries with debug information."));
387 releaseWithDebugInfoOption.setFlags(QCommandLineOption::HiddenFromHelp); // Deprecated by improved debug detection.
388 parser->addOption(releaseWithDebugInfoOption);
389
390 QCommandLineOption deployPdbOption(QStringLiteral("pdb"),
391 QStringLiteral("Deploy .pdb files (MSVC)."));
392 parser->addOption(deployPdbOption);
393
394 QCommandLineOption forceOption(QStringLiteral("force"),
395 QStringLiteral("Force updating files."));
396 parser->addOption(forceOption);
397
398 QCommandLineOption dryRunOption(QStringLiteral("dry-run"),
399 QStringLiteral("Simulation mode. Behave normally, but do not copy/update any files."));
400 parser->addOption(dryRunOption);
401
402 QCommandLineOption noPatchQtOption(QStringLiteral("no-patchqt"),
403 QStringLiteral("Do not patch the Qt6Core library."));
404 parser->addOption(noPatchQtOption);
405
406 QCommandLineOption ignoreErrorOption(QStringLiteral("ignore-library-errors"),
407 QStringLiteral("Ignore errors when libraries cannot be found."));
408 parser->addOption(ignoreErrorOption);
409
410 QCommandLineOption noPluginsOption(QStringLiteral("no-plugins"),
411 QStringLiteral("Skip plugin deployment."));
412 parser->addOption(noPluginsOption);
413
414 QCommandLineOption skipPluginTypesOption(QStringLiteral("skip-plugin-types"),
415 QStringLiteral("A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
416 QStringLiteral("plugin types"));
417 parser->addOption(skipPluginTypesOption);
418
419 QCommandLineOption addPluginTypesOption(QStringLiteral("add-plugin-types"),
420 QStringLiteral("A comma-separated list of plugin types that will be added to deployment (imageformats,iconengines)"),
421 QStringLiteral("plugin types"));
422 parser->addOption(addPluginTypesOption);
423
424 QCommandLineOption includePluginsOption(QStringLiteral("include-plugins"),
425 QStringLiteral("A comma-separated list of individual plugins that will be added to deployment (scene2d,qjpeg)"),
426 QStringLiteral("plugins"));
427 parser->addOption(includePluginsOption);
428
429 QCommandLineOption excludePluginsOption(QStringLiteral("exclude-plugins"),
430 QStringLiteral("A comma-separated list of individual plugins that will not be deployed (qsvg,qpdf)"),
431 QStringLiteral("plugins"));
432 parser->addOption(excludePluginsOption);
433
434 QCommandLineOption noLibraryOption(QStringLiteral("no-libraries"),
435 QStringLiteral("Skip library deployment."));
436 parser->addOption(noLibraryOption);
437
438 QCommandLineOption qmlDirOption(QStringLiteral("qmldir"),
439 QStringLiteral("Scan for QML-imports starting from directory."),
440 QStringLiteral("directory"));
441 parser->addOption(qmlDirOption);
442
443 QCommandLineOption qmlImportOption(QStringLiteral("qmlimport"),
444 QStringLiteral("Add the given path to the QML module search locations."),
445 QStringLiteral("directory"));
446 parser->addOption(qmlImportOption);
447
448 QCommandLineOption qmlImportTimeoutOption(QStringLiteral("qmlimporttimeout"),
449 QStringLiteral("Set timeout (in ms for) execution of "
450 "qmlimportscanner."),
451 QStringLiteral("timeout"));
452 parser->addOption(qmlImportTimeoutOption);
453
454 QCommandLineOption noQuickImportOption(QStringLiteral("no-quick-import"),
455 QStringLiteral("Skip deployment of Qt Quick imports."));
456 parser->addOption(noQuickImportOption);
457
458
459 QCommandLineOption translationOption(QStringLiteral("translations"),
460 QStringLiteral("A comma-separated list of languages to deploy (de,fi)."),
461 QStringLiteral("languages"));
462 parser->addOption(translationOption);
463
464 QCommandLineOption noTranslationOption(QStringLiteral("no-translations"),
465 QStringLiteral("Skip deployment of translations."));
466 parser->addOption(noTranslationOption);
467
468 QCommandLineOption noSystemD3DCompilerOption(QStringLiteral("no-system-d3d-compiler"),
469 QStringLiteral("Skip deployment of the system D3D compiler."));
470 parser->addOption(noSystemD3DCompilerOption);
471
472 QCommandLineOption noSystemDxcOption(QStringLiteral("no-system-dxc-compiler"),
473 QStringLiteral("Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
474 parser->addOption(noSystemDxcOption);
475
476
477 QCommandLineOption compilerRunTimeOption(QStringLiteral("compiler-runtime"),
478 QStringLiteral("Deploy compiler runtime (Desktop only)."));
479 parser->addOption(compilerRunTimeOption);
480
481 QCommandLineOption noCompilerRunTimeOption(QStringLiteral("no-compiler-runtime"),
482 QStringLiteral("Do not deploy compiler runtime (Desktop only)."));
483 parser->addOption(noCompilerRunTimeOption);
484
485 QCommandLineOption jsonOption(QStringLiteral("json"),
486 QStringLiteral("Print to stdout in JSON format."));
487 parser->addOption(jsonOption);
488
489 QCommandLineOption suppressSoftwareRasterizerOption(QStringLiteral("no-opengl-sw"),
490 QStringLiteral("Do not deploy the software rasterizer library."));
491 parser->addOption(suppressSoftwareRasterizerOption);
492
493 QCommandLineOption noFFmpegOption(QStringLiteral("no-ffmpeg"),
494 QStringLiteral("Do not deploy the FFmpeg libraries."));
495 parser->addOption(noFFmpegOption);
496
497 QCommandLineOption forceOpenSslOption(QStringLiteral("force-openssl"),
498 QStringLiteral("Deploy openssl plugin but ignore openssl library dependency"));
499 parser->addOption(forceOpenSslOption);
500
501 QCommandLineOption openSslRootOption(QStringLiteral("openssl-root"),
502 QStringLiteral("Directory containing openSSL libraries."),
503 QStringLiteral("directory"));
504 parser->addOption(openSslRootOption);
505
506
507 QCommandLineOption listOption(QStringLiteral("list"),
508 "Print only the names of the files copied.\n"
509 "Available options:\n"
510 " source: absolute path of the source files\n"
511 " target: absolute path of the target files\n"
512 " relative: paths of the target files, relative\n"
513 " to the target directory\n"
514 " mapping: outputs the source and the relative\n"
515 " target, suitable for use within an\n"
516 " Appx mapping file"_L1,
517 QStringLiteral("option"));
518 parser->addOption(listOption);
519
520 QCommandLineOption appxOption(QStringLiteral("appx"),
521 QStringLiteral("Create an appx package for the Windows Store"));
522 parser->addOption(appxOption);
523
524 QCommandLineOption appxCertificatePath(QStringLiteral("appx-certificate"),
525 QStringLiteral("Path to appx certificate to sign appx package"),
526 QStringLiteral(".cer file"));
527 parser->addOption(appxCertificatePath);
528
529 // Add early option to have it available in the help text.
530 parser->addOption(createVerboseOption());
531
532 parser->addPositionalArgument(QStringLiteral("[files]"),
533 QStringLiteral("Binaries or directory containing the binary."));
534
535 QCommandLineOption deployInsightTrackerOption(QStringLiteral("deploy-insighttracker"),
536 QStringLiteral("Deploy insight tracker plugin."));
537 // The option will be added to the parser if the module is available (see block below)
538 bool insightTrackerModuleAvailable = false;
539
540 OptionPtrVector enabledModuleOptions;
541 OptionPtrVector disabledModuleOptions;
542 const size_t qtModulesCount = qtModuleEntries.size();
543 enabledModuleOptions.reserve(qtModulesCount);
544 disabledModuleOptions.reserve(qtModulesCount);
545 for (const QtModule &module : qtModuleEntries) {
546 const QString option = moduleNameToOptionName(module.name, module.internal);
547 const QString name = module.name;
548 if (name == u"InsightTracker") {
549 parser->addOption(deployInsightTrackerOption);
550 insightTrackerModuleAvailable = true;
551 }
552 const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module.");
553 CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription));
554 parser->addOption(*enabledOption.data());
555 enabledModuleOptions.append(enabledOption);
556 const QString disabledDescription = QStringLiteral("Remove ") + name + QStringLiteral(" module.");
557 CommandLineOptionPtr disabledOption(new QCommandLineOption(QStringLiteral("no-") + option,
558 disabledDescription));
559 disabledModuleOptions.append(disabledOption);
560 parser->addOption(*disabledOption.data());
561 }
562
563 const bool success = parser->parse(arguments);
564 if (parser->isSet(helpOption))
566 if (parser->isSet(versionOption))
568 if (!success) {
569 *errorMessage = parser->errorText();
571 }
572
573 options->libraryDirectory = parser->value(libDirOption);
574 options->pluginDirectory = parser->value(pluginDirOption);
575 options->translationsDirectory = parser->value(translationDirOption);
576 options->qmlDirectory = parser->value(qmlDeployDirOption);
577 options->plugins = !parser->isSet(noPluginsOption);
578 options->libraries = !parser->isSet(noLibraryOption);
579 options->translations = !parser->isSet(noTranslationOption);
580 if (parser->isSet(translationOption))
581 options->languages = parser->value(translationOption).split(u',');
582 options->systemD3dCompiler = !parser->isSet(noSystemD3DCompilerOption);
583 options->systemDxc = !parser->isSet(noSystemDxcOption);
584 options->quickImports = !parser->isSet(noQuickImportOption);
585 options->createAppx = parser->isSet(appxOption);
586 if (options->createAppx) {
587 if (!parser->isSet(appxCertificatePath)) {
588 *errorMessage = QStringLiteral("--appx requires --appx-certificate with a valid certificate");
590 }
591 options->appxCertificatePath = parser->value(appxCertificatePath);
592 }
593
594 // default to deployment of compiler runtime for windows desktop configurations
595 if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopClangMinGW
596 || options->platform.testFlags(WindowsDesktopMsvc) || parser->isSet(compilerRunTimeOption))
597 options->compilerRunTime = true;
598 if (parser->isSet(noCompilerRunTimeOption))
599 options->compilerRunTime = false;
600
601 if (options->compilerRunTime && options->platform != WindowsDesktopMinGW
602 && options->platform != WindowsDesktopClangMinGW
603 && !options->platform.testFlags(WindowsDesktopMsvc)) {
604 *errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for "
605 "Desktop MSVC and MinGW (g++ and Clang) only.");
607 }
608
609 if (parser->isSet(skipPluginTypesOption))
610 options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
611
612 if (parser->isSet(addPluginTypesOption))
613 options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
614
615 if (parser->isSet(includePluginsOption))
616 options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
617
618 if (parser->isSet(excludePluginsOption))
619 options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
620
621 if (parser->isSet(releaseWithDebugInfoOption))
622 std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete.";
623
624 switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
625 case OptionAuto:
626 break;
627 case OptionEnabled:
629 break;
630 case OptionDisabled:
632 break;
633 }
634
635 if (parser->isSet(deployPdbOption)) {
636 if (options->platform.testFlag(WindowsBased) && !options->platform.testFlag(MinGW))
637 options->deployPdb = true;
638 else
639 std::wcerr << "Warning: --" << deployPdbOption.names().first() << " is not supported on this platform.\n";
640 }
641
642 if (parser->isSet(suppressSoftwareRasterizerOption))
643 options->softwareRasterizer = false;
644
645 if (parser->isSet(noFFmpegOption))
646 options->ffmpeg = false;
647
648 if (parser->isSet(forceOpenSslOption))
649 options->forceOpenSslPlugin = true;
650
651 if (parser->isSet(openSslRootOption))
652 options->openSslRootDirectory = parser->value(openSslRootOption);
653
654 if (options->forceOpenSslPlugin && !options->openSslRootDirectory.isEmpty()) {
655 *errorMessage = QStringLiteral("force-openssl and openssl-root are mutually exclusive");
657 }
658
659 if (parser->isSet(forceOption))
661 if (parser->isSet(dryRunOption)) {
662 options->dryRun = true;
664 }
665
666 options->patchQt = !parser->isSet(noPatchQtOption);
667 options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
668 if (insightTrackerModuleAvailable)
669 options->deployInsightTrackerPlugin = parser->isSet(deployInsightTrackerOption);
670
671 for (const QtModule &module : qtModuleEntries) {
672 if (parser->isSet(*enabledModuleOptions.at(module.id)))
673 options->additionalLibraries[module.id] = 1;
674 if (parser->isSet(*disabledModuleOptions.at(module.id)))
675 options->disabledLibraries[module.id] = 1;
676 }
677
678 // Add some dependencies
679 if (options->additionalLibraries.test(QtQuickModuleId))
680 options->additionalLibraries[QtQmlModuleId] = 1;
681 if (options->additionalLibraries.test(QtDesignerComponentsModuleId))
682 options->additionalLibraries[QtDesignerModuleId] = 1;
683
684 if (parser->isSet(listOption)) {
685 const QString value = parser->value(listOption);
686 if (value == QStringLiteral("source")) {
687 options->list = ListSource;
688 } else if (value == QStringLiteral("target")) {
689 options->list = ListTarget;
690 } else if (value == QStringLiteral("relative")) {
691 options->list = ListRelative;
692 } else if (value == QStringLiteral("mapping")) {
693 options->list = ListMapping;
694 } else {
695 *errorMessage = QStringLiteral("Please specify a valid option for -list (source, target, relative, mapping).");
697 }
698 }
699
700 if (parser->isSet(jsonOption) || options->list) {
701 optVerboseLevel = 0;
702 options->json = new JsonOutput;
703 }
704
705 const QStringList posArgs = parser->positionalArguments();
706 if (posArgs.isEmpty()) {
707 *errorMessage = QStringLiteral("Please specify the binary or folder.");
709 }
710
711 if (parser->isSet(dirOption))
712 options->directory = parser->value(dirOption);
713
714 if (parser->isSet(qmlDirOption))
715 options->qmlDirectories = parser->values(qmlDirOption);
716
717 if (parser->isSet(qmlImportOption))
718 options->qmlImportPaths = parser->values(qmlImportOption);
719
720 if (parser->isSet(qmlImportTimeoutOption)) {
721 const QString timeoutString = parser->value(qmlImportTimeoutOption);
722 bool ok;
723 int timeout = timeoutString.toInt(&ok);
724 if (!ok) {
725 *errorMessage = u'"' + timeoutString + QStringLiteral("\" is not an acceptable timeout "
726 "value.");
728 }
729 options->qmlImportTimeout = timeout;
730 }
731
732 const QString &file = posArgs.front();
733 const QFileInfo fi(QDir::cleanPath(file));
734 if (!fi.exists()) {
735 *errorMessage = msgFileDoesNotExist(file);
737 }
738
739 if (!options->directory.isEmpty() && !fi.isFile()) { // -dir was specified - expecting file.
740 *errorMessage = u'"' + file + QStringLiteral("\" is not an executable file.");
742 }
743
744 if (fi.isFile()) {
745 options->binaries.append(fi.absoluteFilePath());
746 if (options->directory.isEmpty())
747 options->directory = fi.absolutePath();
748 } else {
749 const QString binary = findBinary(fi.absoluteFilePath(), options->platform);
750 if (binary.isEmpty()) {
751 *errorMessage = QStringLiteral("Unable to find binary in \"") + file + u'"';
753 }
754 options->directory = fi.absoluteFilePath();
755 options->binaries.append(binary);
756 } // directory.
757
758 // Remaining files or plugin directories
759 bool multipleDirs = false;
760 for (int i = 1; i < posArgs.size(); ++i) {
761 const QFileInfo fi(QDir::cleanPath(posArgs.at(i)));
762 const QString path = fi.absoluteFilePath();
763 if (!fi.exists()) {
764 *errorMessage = msgFileDoesNotExist(path);
766 }
767 if (fi.isDir()) {
768 const QStringList libraries =
769 findSharedLibraries(QDir(path), options->platform, MatchDebugOrRelease, QString());
770 for (const QString &library : libraries)
771 options->binaries.append(path + u'/' + library);
772 } else {
773 if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
774 multipleDirs = true;
775 options->binaries.append(path);
776 }
777 }
778 if (multipleDirs) {
779 std::wcerr << "Warning: using binaries from different directories, deploying to following path: "
780 << options->directory << '\n' << "To disable this warning, use the --dir option\n";
781 }
782 if (options->translationsDirectory.isEmpty())
783 options->translationsDirectory = options->directory + "/translations"_L1;
784 return 0;
785}
786
787// Simple line wrapping at 80 character boundaries.
788static inline QString lineBreak(QString s)
789{
790 for (qsizetype i = 80; i < s.size(); i += 80) {
791 const qsizetype lastBlank = s.lastIndexOf(u' ', i);
792 if (lastBlank >= 0) {
793 s[lastBlank] = u'\n';
794 i = lastBlank + 1;
795 }
796 }
797 return s;
798}
799
800static inline QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
801{
802 QString result = p.helpText();
803 // Replace the default-generated text which is too long by a short summary
804 // explaining how to enable single libraries.
805 if (qtModuleEntries.size() == 0)
806 return result;
807 const QtModule &firstModule = qtModuleEntries.moduleById(0);
808 const QString firstModuleOption = moduleNameToOptionName(firstModule.name, firstModule.internal);
809 const qsizetype moduleStart = result.indexOf("\n --"_L1 + firstModuleOption);
810 const qsizetype argumentsStart = result.lastIndexOf("\nArguments:"_L1);
811 if (moduleStart >= argumentsStart)
812 return result;
813 QString moduleHelp;
814 moduleHelp +=
815 "\n\nQt libraries can be added by passing their name (-xml) or removed by passing\n"
816 "the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
817 ModuleBitset mask;
818 moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
819 moduleHelp += u"\n\n";
820 moduleHelp +=
821 u"Qt plugins can be included or excluded individually or by type.\n"
822 u"To deploy or block plugins individually, use the --include-plugins\n"
823 u"and --exclude-plugins options (--include-plugins qjpeg,qsvgicon)\n"
824 u"You can also use the --skip-plugin-types or --add-plugin-types to\n"
825 u"achieve similar results with entire plugin groups, like imageformats, e.g.\n"
826 u"(--add-plugin-types imageformats,iconengines). Exclusion always takes\n"
827 u"precedence over inclusion, and types take precedence over specific plugins.\n"
828 u"For example, including qjpeg, but skipping imageformats, will NOT deploy qjpeg.\n"
829 u"\nDetected available plugins:\n";
830 moduleHelp += formatQtPlugins(pluginInfo);
831 result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp);
832 return result;
833}
834
835static inline bool isQtModule(const QString &libName)
836{
837 // Match Standard modules named Qt6XX.dll
838 if (libName.size() < 3 || !libName.startsWith("Qt"_L1, Qt::CaseInsensitive))
839 return false;
840 const QChar version = libName.at(2);
841 return version.isDigit() && (version.toLatin1() - '0') == QT_VERSION_MAJOR;
842}
843
844// Helper for recursively finding all dependent Qt libraries.
845static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary,
846 Platform platform, QString *errorMessage,
847 QStringList *qtDependencies, QStringList *nonQtDependencies)
848{
849 QStringList dependentLibs;
850 if (!readPeExecutableDependencies(binary, errorMessage, &dependentLibs)) {
851 errorMessage->prepend("Unable to find dependent libraries of "_L1 +
852 QDir::toNativeSeparators(binary) + " :"_L1);
853 return false;
854 }
855 // Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we
856 // are run the 2nd time (updating). We want to check against the Qt bin dir libraries
857 const int start = qtDependencies->size();
858 for (const QString &lib : std::as_const(dependentLibs)) {
859 if (isQtModule(lib)) {
860 const QString path = normalizeFileName(qtBinDir + u'/' + QFileInfo(lib).fileName());
861 if (!qtDependencies->contains(path))
862 qtDependencies->append(path);
863 } else if (nonQtDependencies && !nonQtDependencies->contains(lib)) {
864 nonQtDependencies->append(lib);
865 }
866 }
867 const int end = qtDependencies->size();
868 // Recurse
869 for (int i = start; i < end; ++i) {
870 if (!findDependentQtLibraries(qtBinDir, qtDependencies->at(i), platform, errorMessage,
871 qtDependencies, nonQtDependencies)) {
872 return false;
873 }
874 }
875 return true;
876}
877
878// Base class to filter debug/release Windows DLLs for functions to be passed to updateFile().
879// Tries to pre-filter by namefilter and does check via PE.
881public:
882 explicit DllDirectoryFileEntryFunction(Platform platform,
883 DebugMatchMode debugMatchMode, const QString &prefix = QString()) :
884 m_platform(platform), m_debugMatchMode(debugMatchMode), m_prefix(prefix) {}
885
886 QStringList operator()(const QDir &dir) const
887 { return findSharedLibraries(dir, m_platform, m_debugMatchMode, m_prefix); }
888
889private:
890 const Platform m_platform;
891 const DebugMatchMode m_debugMatchMode;
892 const QString m_prefix;
893};
894
895static QString pdbFileName(QString libraryFileName)
896{
897 const qsizetype lastDot = libraryFileName.lastIndexOf(u'.') + 1;
898 if (lastDot <= 0)
899 return QString();
900 libraryFileName.replace(lastDot, libraryFileName.size() - lastDot, "pdb"_L1);
901 return libraryFileName;
902}
904{
905 return QStringList() << QStringLiteral("*.jsc") << QStringLiteral("*.qmlc");
906}
907
908// File entry filter function for updateFile() that returns a list of files for
909// QML import trees: DLLs (matching debug) and .qml/,js, etc.
911public:
912 enum Flags {
915 };
916
918 const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
921 {}
922
923 QStringList operator()(const QDir &dir) const
924 {
925 if (moduleSourceDir(dir).canonicalPath() != m_moduleSourcePath) {
926 // If we're in a different module, return nothing.
927 return {};
928 }
929
930 QStringList result;
931 const QStringList &libraries = m_dllFilter(dir);
932 for (const QString &library : libraries) {
933 result.append(library);
934 if (m_flags & DeployPdb) {
935 const QString pdb = pdbFileName(library);
936 if (QFileInfo(dir.absoluteFilePath(pdb)).isFile())
937 result.append(pdb);
938 }
939 }
940 result.append(m_qmlNameFilter(dir));
941 return result;
942 }
943
944private:
945 static QDir moduleSourceDir(const QDir &dir)
946 {
947 QDir moduleSourceDir = dir;
948 while (!moduleSourceDir.exists(QStringLiteral("qmldir"))) {
949 if (!moduleSourceDir.cdUp()) {
950 return {};
951 }
952 }
953 return moduleSourceDir;
954 }
955
956 static inline QStringList qmlNameFilters(unsigned flags)
957 {
958 QStringList result;
959 result << QStringLiteral("qmldir") << QStringLiteral("*.qmltypes")
960 << QStringLiteral("*.frag") << QStringLiteral("*.vert") // Shaders
961 << QStringLiteral("*.ttf");
962 if (!(flags & SkipSources)) {
963 result << QStringLiteral("*.js") << QStringLiteral("*.qml") << QStringLiteral("*.png");
964 result.append(qmlCacheFileFilters());
965 }
966 return result;
967 }
968
969 const unsigned m_flags;
970 NameFilterFileEntryFunction m_qmlNameFilter;
972 QString m_moduleSourcePath;
973};
974
975static qint64 qtModule(QString module, const QString &infix)
976{
977 // Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0'
978 const qsizetype lastSlashPos = module.lastIndexOf(u'/');
979 if (lastSlashPos > 0)
980 module.remove(0, lastSlashPos + 1);
981 if (module.startsWith("lib"_L1))
982 module.remove(0, 3);
983 int endPos = infix.isEmpty() ? -1 : module.lastIndexOf(infix);
984 if (endPos == -1)
985 endPos = module.indexOf(u'.'); // strip suffixes '.so.5.0'.
986 if (endPos > 0)
987 module.truncate(endPos);
988 // That should leave us with 'Qt6Core<d>'.
989 for (const auto &qtModule : qtModuleEntries) {
990 const QString &libraryName = qtModule.name;
991 if (module == libraryName
992 || (module.size() == libraryName.size() + 1 && module.startsWith(libraryName))) {
993 return qtModule.id;
994 }
995 }
996 std::wcerr << "Warning: module " << qPrintable(module) << " could not be found\n";
997 return -1;
998}
999
1000// Return the path if a plugin is to be deployed
1001static QString deployPlugin(const QString &plugin, const QDir &subDir, const bool dueToModule,
1002 const DebugMatchMode &debugMatchMode, ModuleBitset *pluginNeededQtModules,
1003 const ModuleBitset &disabledQtModules,
1004 const PluginSelections &pluginSelections, const QString &libraryLocation,
1005 const QString &infix, Platform platform,
1006 bool deployInsightTrackerPlugin, bool deployOpenSslPlugin)
1007{
1008 const QString subDirName = subDir.dirName();
1009 // Filter out disabled plugins
1010 if (optVerboseLevel && pluginSelections.disabledPluginTypes.contains(subDirName)) {
1011 std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n';
1012 return {};
1013 }
1014 if (optVerboseLevel && subDirName == u"generic" && plugin.contains(u"qinsighttracker")
1015 && !deployInsightTrackerPlugin) {
1016 std::wcout << "Skipping plugin " << plugin
1017 << ". Use -deploy-insighttracker if you want to use it.\n";
1018 return {};
1019 }
1020 if (optVerboseLevel && subDirName == u"tls" && plugin.contains(u"qopensslbackend")
1021 && !deployOpenSslPlugin) {
1022 std::wcout << "Skipping plugin " << plugin
1023 << ". Use -force-openssl or specify -openssl-root if you want to use it.\n";
1024 return {};
1025 }
1026
1027 const int dotIndex = plugin.lastIndexOf(u'.');
1028 // Strip the .dll from the name, and an additional 'd' if it's a debug library with the 'd'
1029 // suffix
1030 const int stripIndex = debugMatchMode == MatchDebug && platformHasDebugSuffix(platform)
1031 ? dotIndex - 1
1032 : dotIndex;
1033 const QString pluginName = plugin.first(stripIndex);
1034
1035 if (optVerboseLevel && pluginSelections.excludedPlugins.contains(pluginName)) {
1036 std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n';
1037 return {};
1038 }
1039
1040 // By default, only deploy qwindows.dll
1041 if (subDirName == u"platforms"
1042 && !(pluginSelections.includedPlugins.contains(pluginName)
1043 || (pluginSelections.enabledPluginTypes.contains(subDirName)))
1044 && !pluginName.startsWith(u"qwindows")) {
1045 return {};
1046 }
1047
1048 const QString pluginPath = subDir.absoluteFilePath(plugin);
1049
1050 // If dueToModule is false, check if the user included the plugin or the entire type. In the
1051 // former's case, only deploy said plugin and not all plugins of that type.
1052 const bool requiresPlugin = pluginSelections.includedPlugins.contains(pluginName)
1053 || pluginSelections.enabledPluginTypes.contains(subDirName);
1054 if (!dueToModule && !requiresPlugin)
1055 return {};
1056
1057 // Deploy QUiTools plugins as is without further dependency checking.
1058 // The user needs to ensure all required libraries are present (would
1059 // otherwise pull QtWebEngine for its plugin).
1060 if (subDirName == u"designer")
1061 return pluginPath;
1062
1063 QStringList dependentQtLibs;
1064 QString errorMessage;
1065 if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
1066 &errorMessage, &dependentQtLibs, nullptr)) {
1067 for (int d = 0; d < dependentQtLibs.size(); ++d) {
1068 const qint64 module = qtModule(dependentQtLibs.at(d), infix);
1069 if (module >= 0)
1070 (*pluginNeededQtModules)[module] = 1;
1071 }
1072 } else {
1073 std::wcerr << "Warning: Cannot determine dependencies of "
1074 << QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
1075 }
1076
1077 ModuleBitset disabledNeededQtModules;
1078 disabledNeededQtModules = *pluginNeededQtModules & disabledQtModules;
1079 if (disabledNeededQtModules.any()) {
1080 if (optVerboseLevel) {
1081 std::wcout << "Skipping plugin " << plugin
1082 << " due to disabled dependencies ("
1083 << formatQtModules(disabledNeededQtModules).constData() << ").\n";
1084 }
1085 return {};
1086 }
1087
1088 return pluginPath;
1089}
1090
1091static bool needsPluginType(const QString &subDirName, const PluginInformation &pluginInfo,
1092 const PluginSelections &pluginSelections)
1093{
1094 bool needsTypeForPlugin = false;
1095 for (const QString &plugin: pluginSelections.includedPlugins) {
1096 if (pluginInfo.isTypeForPlugin(subDirName, plugin))
1097 needsTypeForPlugin = true;
1098 }
1099 return (pluginSelections.enabledPluginTypes.contains(subDirName) || needsTypeForPlugin);
1100}
1101
1102QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
1103 const PluginInformation &pluginInfo, const PluginSelections &pluginSelections,
1104 const QString &qtPluginsDirName, const QString &libraryLocation,
1105 const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform,
1106 QString *platformPlugin, bool deployInsightTrackerPlugin,
1107 bool deployOpenSslPlugin)
1108{
1109 if (qtPluginsDirName.isEmpty())
1110 return QStringList();
1111 QDir pluginsDir(qtPluginsDirName);
1112 QStringList result;
1113 bool missingQtModulesAdded = false;
1114 const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
1115 for (const QFileInfo &subDirFi : pluginDirs) {
1116 const QString subDirName = subDirFi.fileName();
1117 const size_t module = qtModuleEntries.moduleIdForPluginType(subDirName);
1118 if (module == QtModule::InvalidId) {
1119 if (optVerboseLevel > 1) {
1120 std::wcerr << "No Qt module found for plugin type \"" << subDirName << "\".\n";
1121 }
1122 continue;
1123 }
1124 const bool dueToModule = usedQtModules->test(module);
1125 if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
1126 const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
1127 ? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all.
1128 : debugMatchModeIn;
1129 QDir subDir(subDirFi.absoluteFilePath());
1130 if (optVerboseLevel)
1131 std::wcout << "Adding in plugin type " << subDirFi.baseName() << " for module: " << qtModuleEntries.moduleById(module).name << '\n';
1132
1133 const bool isPlatformPlugin = subDirName == "platforms"_L1;
1134 const QStringList plugins =
1135 findSharedLibraries(subDir, platform, debugMatchMode, QString());
1136 for (const QString &plugin : plugins) {
1137 ModuleBitset pluginNeededQtModules;
1138 const QString pluginPath =
1139 deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
1140 disabledQtModules, pluginSelections, libraryLocation, infix,
1141 platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
1142 if (!pluginPath.isEmpty()) {
1143 if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
1144 *platformPlugin = subDir.absoluteFilePath(plugin);
1145 result.append(pluginPath);
1146
1147 const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
1148 if (missingModules.any()) {
1149 *usedQtModules |= missingModules;
1150 missingQtModulesAdded = true;
1151 if (optVerboseLevel) {
1152 std::wcout << "Adding " << formatQtModules(missingModules).constData()
1153 << " for " << plugin << " from plugin type: " << subDirName << '\n';
1154 }
1155 }
1156 }
1157 } // for filter
1158 } // type matches
1159 } // for plugin folder
1160
1161 // If missing Qt modules were added during plugin deployment make additional pass, because we may need
1162 // additional plugins.
1163 if (missingQtModulesAdded) {
1164 if (optVerboseLevel) {
1165 std::wcout << "Performing additional pass of finding Qt plugins due to updated Qt module list: "
1166 << formatQtModules(*usedQtModules).constData() << "\n";
1167 }
1168 return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
1169 libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
1170 deployInsightTrackerPlugin, deployOpenSslPlugin);
1171 }
1172
1173 return result;
1174}
1175
1176static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
1177{
1178 QStringList result;
1179 for (const auto &qtModule : qtModuleEntries) {
1180 if (modules.test(qtModule.id) && !qtModule.translationCatalog.isEmpty()) {
1181 const QString name = qtModule.translationCatalog + u'_' + prefix + ".qm"_L1;
1182 if (!result.contains(name))
1183 result.push_back(name);
1184 }
1185 }
1186 return result;
1187}
1188
1189static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules,
1190 const QString &target, const Options &options,
1191 QString *errorMessage)
1192{
1193 // Find available languages prefixes by checking on qtbase.
1194 QStringList prefixes;
1195 QDir sourceDir(sourcePath);
1196 const QStringList qmFilter = QStringList(QStringLiteral("qtbase_*.qm"));
1197 const QFileInfoList &qmFiles = sourceDir.entryInfoList(qmFilter);
1198 for (const QFileInfo &qmFi : qmFiles) {
1199 const QString prefix = qmFi.baseName().mid(7);
1200 if (options.languages.isEmpty() || options.languages.contains(prefix))
1201 prefixes.append(prefix);
1202 }
1203 if (prefixes.isEmpty()) {
1204 std::wcerr << "Warning: Could not find any translations in "
1205 << QDir::toNativeSeparators(sourcePath) << " (developer build?)\n.";
1206 return true;
1207 }
1208 // Run lconvert to concatenate all files into a single named "qt_<prefix>.qm" in the application folder
1209 // Use QT_INSTALL_TRANSLATIONS as working directory to keep the command line short.
1210 const QString absoluteTarget = QFileInfo(target).absoluteFilePath();
1211 const QString binary = QStringLiteral("lconvert");
1212 QStringList arguments;
1213 for (const QString &prefix : std::as_const(prefixes)) {
1214 arguments.clear();
1215 const QString targetFile = QStringLiteral("qt_") + prefix + QStringLiteral(".qm");
1216 arguments.append(QStringLiteral("-o"));
1217 const QString targetFilePath = absoluteTarget + u'/' + targetFile;
1218 if (options.json)
1219 options.json->addFile(sourcePath + u'/' + targetFile, absoluteTarget);
1220 arguments.append(QDir::toNativeSeparators(targetFilePath));
1221 const QStringList translationFilters = translationNameFilters(usedQtModules, prefix);
1222 if (translationFilters.isEmpty()){
1223 std::wcerr << "Warning: translation catalogs are all empty, skipping translation deployment\n";
1224 return true;
1225 }
1226 const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationFilters);
1227 for (const QFileInfo &langQmFileFi : langQmFiles) {
1228 if (options.json) {
1229 options.json->addFile(langQmFileFi.absoluteFilePath(),
1230 absoluteTarget);
1231 }
1232 arguments.append(langQmFileFi.fileName());
1233 }
1234 if (optVerboseLevel)
1235 std::wcout << "Creating " << targetFile << "...\n";
1236 unsigned long exitCode;
1237 if ((options.updateFileFlags & SkipUpdateFile) == 0
1238 && (!runProcess(binary, arguments, sourcePath, &exitCode, nullptr, nullptr, errorMessage)
1239 || exitCode)) {
1240 return false;
1241 }
1242 } // for prefixes.
1243 return true;
1244}
1245
1246static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
1247{
1248 const std::vector<QLatin1StringView> ffmpegHints = { "avcodec"_L1, "avformat"_L1, "avutil"_L1,
1249 "swresample"_L1, "swscale"_L1 };
1250 const QStringList bundledLibs =
1251 findSharedLibraries(qtBinDir, platform, MatchDebugOrRelease, {});
1252
1253 QStringList ffmpegLibs;
1254 for (const QLatin1StringView &libHint : ffmpegHints) {
1255 const QStringList ffmpegLib = bundledLibs.filter(libHint, Qt::CaseInsensitive);
1256
1257 if (ffmpegLib.empty()) {
1258 std::wcerr << "Warning: Cannot find FFmpeg libraries. Multimedia features will not work as expected.\n";
1259 return {};
1260 } else if (ffmpegLib.size() != 1u) {
1261 std::wcerr << "Warning: Multiple versions of FFmpeg libraries found. Multimedia features will not work as expected.\n";
1262 return {};
1263 }
1264
1265 const QChar slash(u'/');
1266 QFileInfo ffmpegLibPath{ qtBinDir + slash + ffmpegLib.front() };
1267 ffmpegLibs.append(ffmpegLibPath.absoluteFilePath());
1268 }
1269
1270 return ffmpegLibs;
1271}
1272
1273// Find the openssl libraries Qt executables depend on.
1274static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
1275{
1276 const std::vector<QLatin1StringView> libHints = { "libcrypto"_L1, "libssl"_L1 };
1277 const QChar slash(u'/');
1278 const QString openSslBinDir = openSslRootDir + slash + "bin"_L1;
1279 const QStringList openSslRootLibs =
1280 findSharedLibraries(openSslBinDir, platform, MatchDebugOrRelease, {});
1281
1282 QStringList result;
1283 for (const QLatin1StringView &libHint : libHints) {
1284 const QStringList lib = openSslRootLibs.filter(libHint, Qt::CaseInsensitive);
1285
1286 if (lib.empty()) {
1287 std::wcerr << "Warning: Cannot find openssl libraries.\n";
1288 return {};
1289 } else if (lib.size() != 1u) {
1290 std::wcerr << "Warning: Multiple versions of openssl libraries found.\n";
1291 return {};
1292 }
1293
1294 QFileInfo libPath{ openSslBinDir + slash + lib.front() };
1295 result.append(libPath.absoluteFilePath());
1296 }
1297
1298 return result;
1299}
1300
1301
1312
1313static QString libraryPath(const QString &libraryLocation, const char *name,
1314 const QString &infix, Platform platform, bool debug)
1315{
1316 QString result = libraryLocation + u'/';
1317 result += QLatin1StringView(name);
1318 result += infix;
1319 if (debug && platformHasDebugSuffix(platform))
1320 result += u'd';
1321 result += sharedLibrarySuffix();
1322 return result;
1323}
1324
1325static QString vcDebugRedistDir() { return QStringLiteral("Debug_NonRedist"); }
1326
1328{
1329 const char vcDirVar[] = "VCINSTALLDIR";
1330 const QChar slash(u'/');
1331 QString vcRedistDirName = QDir::cleanPath(QFile::decodeName(qgetenv(vcDirVar)));
1332 if (vcRedistDirName.isEmpty()) {
1333 std::wcerr << "Warning: Cannot find Visual Studio installation directory, " << vcDirVar
1334 << " is not set.\n";
1335 return QString();
1336 }
1337 if (!vcRedistDirName.endsWith(slash))
1338 vcRedistDirName.append(slash);
1339 vcRedistDirName.append(QStringLiteral("redist/MSVC"));
1340 if (!QFileInfo(vcRedistDirName).isDir()) {
1341 std::wcerr << "Warning: Cannot find Visual Studio redist directory, "
1342 << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1343 return QString();
1344 }
1345 // Look in reverse order for folder containing the debug redist folder
1346 const QFileInfoList subDirs =
1347 QDir(vcRedistDirName)
1348 .entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
1349 for (const QFileInfo &f : subDirs) {
1350 QString path = f.absoluteFilePath();
1351 if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
1352 return path;
1353 path += QStringLiteral("/onecore");
1354 if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
1355 return path;
1356 }
1357 std::wcerr << "Warning: Cannot find Visual Studio redist directory under "
1358 << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1359 return QString();
1360}
1361
1362static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
1363{
1364 //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found.
1365 QStringList result;
1366 const bool isClang = platform == WindowsDesktopClangMinGW;
1367 QStringList filters;
1368 const QString suffix = u'*' + sharedLibrarySuffix();
1369 for (const auto &minGWRuntime : runtimeFilters)
1370 filters.append(minGWRuntime + suffix);
1371
1372 QFileInfoList dlls = QDir(qtBinDir).entryInfoList(filters, QDir::Files);
1373 if (dlls.isEmpty()) {
1374 std::wcerr << "Warning: Runtime libraries not found in Qt binary folder, defaulting to looking in path\n";
1375 const QString binaryPath = isClang ? findInPath("clang++.exe"_L1) : findInPath("g++.exe"_L1);
1376 if (binaryPath.isEmpty()) {
1377 std::wcerr << "Warning: Cannot find " << (isClang ? "Clang" : "GCC") << " installation directory, " << (isClang ? "clang++" : "g++") << ".exe must be in the path\n";
1378 return {};
1379 }
1380 const QString binaryFolder = QFileInfo(binaryPath).absolutePath();
1381 dlls = QDir(binaryFolder).entryInfoList(filters, QDir::Files);
1382 }
1383
1384 for (const QFileInfo &dllFi : dlls)
1385 result.append(dllFi.absoluteFilePath());
1386
1387 return result;
1388}
1389
1390static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
1391{
1392 QStringList result;
1393 switch (platform) {
1394 case WindowsDesktopMinGW: {
1395 const QStringList minGWRuntimes = { "*gcc_"_L1, "*stdc++"_L1, "*winpthread"_L1 };
1396 result.append(findMinGWRuntimePaths(qtBinDir, platform, minGWRuntimes));
1397 break;
1398 }
1400 const QStringList clangMinGWRuntimes = { "*unwind"_L1, "*c++"_L1 };
1401 result.append(findMinGWRuntimePaths(qtBinDir, platform, clangMinGWRuntimes));
1402 break;
1403 }
1404#ifdef Q_OS_WIN
1405 case WindowsDesktopMsvcIntel:
1406 case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages.
1407 QString vcRedistDirName = vcRedistDir();
1408 if (vcRedistDirName.isEmpty())
1409 break;
1410 QStringList redistFiles;
1411 QDir vcRedistDir(vcRedistDirName);
1412 const QString machineArchString = getArchString(machineArch);
1413 if (isDebug) {
1414 // Append DLLs from Debug_NonRedist\x??\Microsoft.VC<version>.DebugCRT.
1415 if (vcRedistDir.cd(vcDebugRedistDir()) && vcRedistDir.cd(machineArchString)) {
1416 const QStringList names = vcRedistDir.entryList(QStringList(QStringLiteral("Microsoft.VC*.DebugCRT")), QDir::Dirs);
1417 if (!names.isEmpty() && vcRedistDir.cd(names.first())) {
1418 const QFileInfoList &dlls = vcRedistDir.entryInfoList(QStringList("*.dll"_L1));
1419 for (const QFileInfo &dll : dlls)
1420 redistFiles.append(dll.absoluteFilePath());
1421 }
1422 }
1423 } else { // release: Bundle vcredist<>.exe
1424 QString releaseRedistDir = vcRedistDirName;
1425 const QStringList countryCodes = vcRedistDir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Dirs);
1426 if (!countryCodes.isEmpty()) // Pre MSVC2017
1427 releaseRedistDir += u'/' + countryCodes.constFirst();
1428 QFileInfo fi(releaseRedistDir + "/vc_redist."_L1
1429 + machineArchString + ".exe"_L1);
1430 if (!fi.isFile()) { // Pre MSVC2017/15.5
1431 fi.setFile(releaseRedistDir + "/vcredist_"_L1
1432 + machineArchString + ".exe"_L1);
1433 }
1434 if (fi.isFile())
1435 redistFiles.append(fi.absoluteFilePath());
1436 }
1437 if (redistFiles.isEmpty()) {
1438 std::wcerr << "Warning: Cannot find Visual Studio " << (isDebug ? "debug" : "release")
1439 << " redistributable files in " << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1440 break;
1441 }
1442 result.append(redistFiles);
1443 }
1444 break;
1445#endif // Q_OS_WIN
1446 default:
1447 break;
1448 }
1449 return result;
1450}
1451
1452static inline int qtVersion(const QMap<QString, QString> &qtpathsVariables)
1453{
1454 const QString versionString = qtpathsVariables.value(QStringLiteral("QT_VERSION"));
1455 const QChar dot = u'.';
1456 const int majorVersion = versionString.section(dot, 0, 0).toInt();
1457 const int minorVersion = versionString.section(dot, 1, 1).toInt();
1458 const int patchVersion = versionString.section(dot, 2, 2).toInt();
1459 return (majorVersion << 16) | (minorVersion << 8) | patchVersion;
1460}
1461
1462// Deploy a library along with its .pdb debug info file (MSVC) should it exist.
1463static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory,
1464 const Options &options, QString *errorMessage)
1465{
1466 if (!updateFile(sourceFileName, targetDirectory, options.updateFileFlags, options.json, errorMessage)) {
1467 if (options.ignoreLibraryErrors) {
1468 std::wcerr << "Warning: Could not update " << sourceFileName << " :" << *errorMessage << '\n';
1469 errorMessage->clear();
1470 return true;
1471 }
1472 return false;
1473 }
1474
1475 if (options.deployPdb) {
1476 const QFileInfo pdb(pdbFileName(sourceFileName));
1477 if (pdb.isFile())
1478 return updateFile(pdb.absoluteFilePath(), targetDirectory, options.updateFileFlags, nullptr, errorMessage);
1479 }
1480 return true;
1481}
1482
1483// Find out the ICU version to add the data library icudtXX.dll, which does not
1484// show as a dependency.
1485static QString getIcuVersion(const QString &libName)
1486{
1487 QString version;
1488 std::copy_if(libName.cbegin(), libName.cend(), std::back_inserter(version),
1489 [](QChar c) { return c.isDigit(); });
1490 return version;
1491}
1492
1493static DeployResult deploy(const Options &options, const QMap<QString, QString> &qtpathsVariables,
1494 const PluginInformation &pluginInfo, QString *errorMessage)
1495{
1496 DeployResult result;
1497
1498 const QChar slash = u'/';
1499
1500 const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
1501 const QString libraryLocation = qtBinDir;
1502 const QString infix = qtpathsVariables.value(QLatin1StringView(qmakeInfixKey));
1503 const int version = qtVersion(qtpathsVariables);
1504 Q_UNUSED(version);
1505
1506 if (optVerboseLevel > 1)
1507 std::wcout << "Qt binaries in " << QDir::toNativeSeparators(qtBinDir) << '\n';
1508
1509 QStringList dependentQtLibs;
1510 QStringList dependentNonQtLibs;
1511 PeHeaderInfoStruct peHeaderInfo;
1512
1513 if (!readPeExecutableInfo(options.binaries.first(), errorMessage, &peHeaderInfo))
1514 return result;
1515 if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform,
1516 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1517 return result;
1518 }
1519 for (int b = 1; b < options.binaries.size(); ++b) {
1520 if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform,
1521 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1522 return result;
1523 }
1524 }
1525
1526 const QFileInfo fi(options.binaries.first());
1527 const QString canonicalBinPath = fi.canonicalPath();
1528 // Also check Qt dependencies of "local non Qt dependencies" (dlls located in the same folder)
1529 // Index based loop as container might be changed which invalidates iterators
1530 for (qsizetype i = 0; i < dependentNonQtLibs.size(); ++i) {
1531 const QString nonQtLib = dependentNonQtLibs.at(i);
1532 const QString path = canonicalBinPath + u'/' + nonQtLib;
1533 if (!QFileInfo::exists(path))
1534 continue;
1535
1536 if (optVerboseLevel)
1537 std::wcout << "Adding local dependency" << path << '\n';
1538
1539 if (!findDependentQtLibraries(libraryLocation, path, options.platform,
1540 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1541 return result;
1542 }
1543 }
1544
1545 DebugMatchMode debugMatchMode = MatchDebugOrRelease;
1546 result.isDebug = false;
1547 switch (options.debugDetection) {
1549 // Debug detection is only relevant for Msvc/ClangMsvc which have distinct
1550 // runtimes and binaries. For anything else, use MatchDebugOrRelease
1551 // since also debug cannot be reliably detect for MinGW.
1552 if (options.platform.testFlag(Msvc) || options.platform.testFlag(ClangMsvc)) {
1553 result.isDebug = peHeaderInfo.isDebug;
1554 debugMatchMode = result.isDebug ? MatchDebug : MatchRelease;
1555 }
1556 break;
1558 result.isDebug = true;
1559 debugMatchMode = MatchDebug;
1560 break;
1562 debugMatchMode = MatchRelease;
1563 break;
1564 }
1565
1566 // Determine application type, check Quick2 is used by looking at the
1567 // direct dependencies (do not be fooled by QtWebKit depending on it).
1568 for (int m = 0; m < dependentQtLibs.size(); ++m) {
1569 const qint64 module = qtModule(dependentQtLibs.at(m), infix);
1570 if (module >= 0)
1571 result.directlyUsedQtLibraries[module] = 1;
1572 }
1573
1574 const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
1575 const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModuleId);
1576 const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModuleId);
1577 const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModuleId))
1578 && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModuleId)));
1579
1580 if (optVerboseLevel) {
1581 std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' '
1582 << peHeaderInfo.wordSize << " bit, " << (result.isDebug ? "debug" : "release")
1583 << " executable";
1584 if (usesQml2)
1585 std::wcout << " [QML]";
1586 std::wcout << '\n';
1587 }
1588
1589 if (dependentQtLibs.isEmpty()) {
1590 *errorMessage = QDir::toNativeSeparators(options.binaries.first()) + QStringLiteral(" does not seem to be a Qt executable.");
1591 return result;
1592 }
1593
1594 // Scan Quick2 imports
1595 QmlImportScanResult qmlScanResult;
1596 if (options.quickImports && usesQml2) {
1597 // Custom list of import paths provided by user
1598 QStringList qmlImportPaths = options.qmlImportPaths;
1599 // Qt's own QML modules
1600 qmlImportPaths << qtpathsVariables.value(QStringLiteral("QT_INSTALL_QML"));
1601 QStringList qmlDirectories = options.qmlDirectories;
1602 if (qmlDirectories.isEmpty()) {
1603 const QString qmlDirectory = findQmlDirectory(options.platform, options.directory);
1604 if (!qmlDirectory.isEmpty())
1605 qmlDirectories.append(qmlDirectory);
1606 }
1607 for (const QString &qmlDirectory : std::as_const(qmlDirectories)) {
1608 if (optVerboseLevel >= 1)
1609 std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
1610 const QmlImportScanResult scanResult =
1611 runQmlImportScanner(qmlDirectory, qmlImportPaths,
1612 result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
1613 options.platform, debugMatchMode, errorMessage,
1614 options.qmlImportTimeout);
1615 if (!scanResult.ok)
1616 return result;
1617 qmlScanResult.append(scanResult);
1618 // Additional dependencies of QML plugins.
1619 for (const QString &plugin : std::as_const(qmlScanResult.plugins)) {
1620 if (!findDependentQtLibraries(libraryLocation, plugin, options.platform,
1621 errorMessage, &dependentQtLibs, nullptr)) {
1622 return result;
1623 }
1624 }
1625 if (optVerboseLevel >= 1) {
1626 std::wcout << "QML imports:\n";
1627 for (const QmlImportScanResult::Module &mod : std::as_const(qmlScanResult.modules)) {
1628 std::wcout << " '" << mod.name << "' "
1629 << QDir::toNativeSeparators(mod.sourcePath) << '\n';
1630 }
1631 if (optVerboseLevel >= 2) {
1632 std::wcout << "QML plugins:\n";
1633 for (const QString &p : std::as_const(qmlScanResult.plugins))
1634 std::wcout << " " << QDir::toNativeSeparators(p) << '\n';
1635 }
1636 }
1637 }
1638 }
1639
1640 QString platformPlugin;
1641 // Sort apart Qt 5 libraries in the ones that are represented by the
1642 // QtModule enumeration (and thus controlled by flags) and others.
1643 QStringList deployedQtLibraries;
1644 for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
1645 const qint64 module = qtModule(dependentQtLibs.at(i), infix);
1646 if (module >= 0)
1647 result.usedQtLibraries[module] = 1;
1648 else
1649 deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
1650 }
1651 result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
1652
1653 ModuleBitset disabled = options.disabledLibraries;
1654 if (!usesQml2) {
1655 disabled[QtQmlModuleId] = 1;
1656 disabled[QtQuickModuleId] = 1;
1657 }
1658
1659 // Some Windows-specific checks: Qt5Core depends on ICU when configured with "-icu". Other than
1660 // that, Qt5WebKit has a hard dependency on ICU.
1661 if (options.platform.testFlag(WindowsBased)) {
1662 const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral("Qt6Core"), Qt::CaseInsensitive)
1663 + dependentQtLibs.filter(QStringLiteral("Qt5WebKit"), Qt::CaseInsensitive);
1664 for (const QString &qtLib : qtLibs) {
1665 QStringList icuLibs = findDependentLibraries(qtLib, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive);
1666 if (!icuLibs.isEmpty()) {
1667 // Find out the ICU version to add the data library icudtXX.dll, which does not show
1668 // as a dependency.
1669 const QString icuVersion = getIcuVersion(icuLibs.constFirst());
1670 if (!icuVersion.isEmpty()) {
1671 if (optVerboseLevel > 1)
1672 std::wcout << "Adding ICU version " << icuVersion << '\n';
1673 QString icuLib = QStringLiteral("icudt") + icuVersion
1674 + QLatin1StringView(windowsSharedLibrarySuffix);
1675 // Some packages contain debug dlls of ICU libraries even though it's a C
1676 // library and the official packages do not differentiate (QTBUG-87677)
1677 if (result.isDebug) {
1678 const QString icuLibCandidate = QStringLiteral("icudtd") + icuVersion
1679 + QLatin1StringView(windowsSharedLibrarySuffix);
1680 if (!findInPath(icuLibCandidate).isEmpty()) {
1681 icuLib = icuLibCandidate;
1682 }
1683 }
1684 icuLibs.push_back(icuLib);
1685 }
1686 for (const QString &icuLib : std::as_const(icuLibs)) {
1687 const QString icuPath = findInPath(icuLib);
1688 if (icuPath.isEmpty()) {
1689 *errorMessage = QStringLiteral("Unable to locate ICU library ") + icuLib;
1690 return result;
1691 }
1692 deployedQtLibraries.push_back(icuPath);
1693 } // for each icuLib
1694 break;
1695 } // !icuLibs.isEmpty()
1696 } // Qt6Core/Qt6WebKit
1697 } // Windows
1698
1699 QStringList openSslLibs;
1700 if (!options.openSslRootDirectory.isEmpty()) {
1701 openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
1702 if (openSslLibs.isEmpty()) {
1703 *errorMessage = QStringLiteral("Unable to find openSSL libraries in ")
1704 + options.openSslRootDirectory;
1705 return result;
1706 }
1707
1708 deployedQtLibraries.append(openSslLibs);
1709 }
1710 const bool deployOpenSslPlugin = options.forceOpenSslPlugin || !openSslLibs.isEmpty();
1711
1712 const QStringList plugins = findQtPlugins(
1713 &result.deployedQtLibraries,
1714 // For non-QML applications, disable QML to prevent it from being pulled in by the
1715 // qtaccessiblequick plugin.
1716 disabled, pluginInfo,
1717 options.pluginSelections, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
1718 libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
1719 options.deployInsightTrackerPlugin, deployOpenSslPlugin);
1720
1721 // Apply options flags and re-add library names.
1722 QString qtGuiLibrary;
1723 for (const auto &qtModule : qtModuleEntries) {
1724 if (result.deployedQtLibraries.test(qtModule.id)) {
1725 const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
1726 options.platform, result.isDebug);
1727 deployedQtLibraries.append(library);
1728 if (qtModule.id == QtGuiModuleId)
1729 qtGuiLibrary = library;
1730 }
1731 }
1732
1733 if (optVerboseLevel >= 1) {
1734 std::wcout << "Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData()
1735 << "\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData()
1736 << "\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() << '\n';
1737 }
1738
1739 if (optVerboseLevel > 1)
1740 std::wcout << "Plugins: " << plugins.join(u',') << '\n';
1741
1742 if (result.deployedQtLibraries.test(QtGuiModuleId) && platformPlugin.isEmpty()) {
1743 *errorMessage =QStringLiteral("Unable to find the platform plugin.");
1744 return result;
1745 }
1746
1747 if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) {
1748 const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
1749 const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty();
1750 if (options.softwareRasterizer && !dependsOnOpenGl) {
1751 const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1StringView(windowsSharedLibrarySuffix));
1752 if (softwareRasterizer.isFile())
1753 deployedQtLibraries.append(softwareRasterizer.absoluteFilePath());
1754 }
1755 if (options.systemD3dCompiler && peHeaderInfo.machineArch != IMAGE_FILE_MACHINE_ARM64) {
1756 const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir,
1757 peHeaderInfo.wordSize);
1758 if (d3dCompiler.isEmpty()) {
1759 std::wcerr << "Warning: Cannot find any version of the d3dcompiler DLL.\n";
1760 } else {
1761 deployedQtLibraries.push_back(d3dCompiler);
1762 }
1763 }
1764 if (options.systemDxc) {
1765 const QStringList dxcLibs = findDxc(options.platform, qtBinDir,
1766 peHeaderInfo.wordSize);
1767 if (!dxcLibs.isEmpty())
1768 deployedQtLibraries.append(dxcLibs);
1769 else
1770 std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
1771 }
1772 } // Windows
1773
1774 // Add FFmpeg if we deploy the FFmpeg backend
1775 if (options.ffmpeg
1776 && !plugins.filter(QStringLiteral("ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
1777 deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
1778 }
1779
1780 // Update libraries
1781 if (options.libraries) {
1782 const QString targetPath = options.libraryDirectory.isEmpty() ?
1783 options.directory : options.libraryDirectory;
1784 QStringList libraries = deployedQtLibraries;
1785 if (options.compilerRunTime) {
1786 libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug,
1787 peHeaderInfo.machineArch));
1788 }
1789 for (const QString &qtLib : std::as_const(libraries)) {
1790 if (!updateLibrary(qtLib, targetPath, options, errorMessage))
1791 return result;
1792 }
1793
1794#if !QT_CONFIG(relocatable)
1795 if (options.patchQt && !options.dryRun) {
1796 const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", infix,
1797 options.platform, result.isDebug)).fileName();
1798 if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
1799 std::wcerr << "Warning: " << *errorMessage << '\n';
1800 errorMessage->clear();
1801 }
1802 }
1803#endif // QT_CONFIG(relocatable)
1804 } // optLibraries
1805
1806 // Update plugins
1807 if (options.plugins) {
1808 const QString targetPath = options.pluginDirectory.isEmpty() ?
1809 options.directory : options.pluginDirectory;
1810 QDir dir(targetPath);
1811 if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
1812 *errorMessage = "Cannot create "_L1 +
1813 QDir::toNativeSeparators(dir.absolutePath()) + u'.';
1814 return result;
1815 }
1816 for (const QString &plugin : plugins) {
1817 const QString targetDirName = plugin.section(slash, -2, -2);
1818 const QString targetPath = dir.absoluteFilePath(targetDirName);
1819 if (!dir.exists(targetDirName)) {
1820 if (optVerboseLevel)
1821 std::wcout << "Creating directory " << targetPath << ".\n";
1822 if (!(options.updateFileFlags & SkipUpdateFile) && !dir.mkdir(targetDirName)) {
1823 *errorMessage = QStringLiteral("Cannot create ") + targetDirName + u'.';
1824 return result;
1825 }
1826 }
1827 if (!updateLibrary(plugin, targetPath, options, errorMessage))
1828 return result;
1829 }
1830 } // optPlugins
1831
1832 // Update Quick imports
1833 // Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
1834 // for WebKit1-applications. Check direct dependency only.
1835 if (options.quickImports && usesQml2) {
1836 const QString targetPath = options.qmlDirectory.isEmpty()
1837 ? options.directory + QStringLiteral("/qml")
1838 : options.qmlDirectory;
1839 if (!createDirectory(targetPath, errorMessage, options.dryRun))
1840 return result;
1841 for (const QmlImportScanResult::Module &module : std::as_const(qmlScanResult.modules)) {
1842 const QString installPath = module.installPath(targetPath);
1843 if (optVerboseLevel > 1)
1844 std::wcout << "Installing: '" << module.name
1845 << "' from " << module.sourcePath << " to "
1846 << QDir::toNativeSeparators(installPath) << '\n';
1847 if (installPath != targetPath && !createDirectory(installPath, errorMessage, options.dryRun))
1848 return result;
1849 unsigned updateFileFlags = options.updateFileFlags
1850 | SkipQmlDesignerSpecificsDirectories;
1851 unsigned qmlDirectoryFileFlags = 0;
1852 if (options.deployPdb)
1853 qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
1854 if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
1855 options.platform,
1856 debugMatchMode,
1857 qmlDirectoryFileFlags),
1858 installPath, updateFileFlags, options.json, errorMessage)) {
1859 return result;
1860 }
1861 }
1862 } // optQuickImports
1863
1864 if (options.translations) {
1865 if (!createDirectory(options.translationsDirectory, errorMessage, options.dryRun))
1866 return result;
1867 if (!deployTranslations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS")),
1868 result.deployedQtLibraries, options.translationsDirectory, options,
1869 errorMessage)) {
1870 return result;
1871 }
1872 }
1873
1874 result.success = true;
1875 return result;
1876}
1877
1878static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, const char *binaryName,
1879 const PluginInformation &pluginInfo, const Options &sourceOptions,
1880 QString *errorMessage)
1881{
1882 // Copy the web process and its dependencies
1883 const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform);
1884 const QString webProcessSource = qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBEXECS"))
1885 + u'/' + webProcess;
1886 const QString webProcessTargetDir = sourceOptions.platform & WindowsBased
1887 && !sourceOptions.libraryDirectory.isEmpty() ?
1888 sourceOptions.libraryDirectory :
1889 sourceOptions.directory;
1890 if (!updateFile(webProcessSource, webProcessTargetDir, sourceOptions.updateFileFlags, sourceOptions.json, errorMessage))
1891 return false;
1892 Options options(sourceOptions);
1893 options.binaries.append(webProcessTargetDir + u'/' + webProcess);
1894 options.quickImports = false;
1895 options.translations = false;
1896 return deploy(options, qtpathsVariables, pluginInfo, errorMessage);
1897}
1898
1899static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
1900 const PluginInformation &pluginInfo, const Options &options,
1901 bool isDebug, QString *errorMessage)
1902{
1903 static const char *installDataFilesRelease[] = {
1904 "icudtl.dat", "qtwebengine_devtools_resources.pak", "qtwebengine_resources.pak",
1905 "qtwebengine_resources_100p.pak", "qtwebengine_resources_200p.pak"
1906 };
1907 static const char *installDataFilesDebug[] = {
1908 "icudtl.dat", "qtwebengine_devtools_resources.debug.pak", "qtwebengine_resources.debug.pak",
1909 "qtwebengine_resources_100p.debug.pak", "qtwebengine_resources_200p.debug.pak"
1910 };
1911 static const auto &installDataFiles = isDebug ? installDataFilesDebug : installDataFilesRelease;
1912 static const auto installV8SnapshotFile =
1913 isDebug ? "v8_context_snapshot.debug.bin" : "v8_context_snapshot.bin";
1914
1915 QByteArray webEngineProcessName(webEngineProcessC);
1916 if (isDebug && platformHasDebugSuffix(options.platform))
1917 webEngineProcessName.append('d');
1918 if (optVerboseLevel)
1919 std::wcout << "Deploying: " << webEngineProcessName.constData() << "...\n";
1920 if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
1921 return false;
1922 const QString resourcesSubDir = QStringLiteral("/resources");
1923 const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_DATA"))
1924 + resourcesSubDir + u'/';
1925 const QString resourcesTargetDir(options.directory + resourcesSubDir);
1926 if (!createDirectory(resourcesTargetDir, errorMessage, options.dryRun))
1927 return false;
1928 for (auto installDataFile : installDataFiles) {
1929 if (!updateFile(resourcesSourceDir + QLatin1StringView(installDataFile),
1930 resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) {
1931 return false;
1932 }
1933 }
1934 // snapshot file is optional feature in qtwebengine, so it might be missing
1935 updateFile(resourcesSourceDir + QLatin1StringView(installV8SnapshotFile), resourcesTargetDir,
1936 options.updateFileFlags, options.json, errorMessage);
1937 errorMessage->clear();
1938 const QFileInfo translations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS"))
1939 + QStringLiteral("/qtwebengine_locales"));
1940 if (!translations.isDir()) {
1941 std::wcerr << "Warning: Cannot find the translation files of the QtWebEngine module at "
1942 << QDir::toNativeSeparators(translations.absoluteFilePath()) << ".\n";
1943 return true;
1944 }
1945 if (options.translations) {
1946 // Copy the whole translations directory.
1947 return createDirectory(options.translationsDirectory, errorMessage, options.dryRun)
1948 && updateFile(translations.absoluteFilePath(), options.translationsDirectory,
1949 options.updateFileFlags, options.json, errorMessage);
1950 }
1951 // Translations have been turned off, but QtWebEngine needs at least one.
1952 const QFileInfo enUSpak(translations.filePath() + QStringLiteral("/en-US.pak"));
1953 if (!enUSpak.exists()) {
1954 std::wcerr << "Warning: Cannot find "
1955 << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) << ".\n";
1956 return true;
1957 }
1958 const QString webEngineTranslationsDir = options.translationsDirectory + u'/'
1959 + translations.fileName();
1960 if (!createDirectory(webEngineTranslationsDir, errorMessage, options.dryRun))
1961 return false;
1962 return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir,
1963 options.updateFileFlags, options.json, errorMessage);
1964}
1965
1966QT_END_NAMESPACE
1967
1968QT_USE_NAMESPACE
1969
1970int main(int argc, char **argv)
1971{
1972 QCoreApplication a(argc, argv);
1973 QCoreApplication::setApplicationVersion(QT_VERSION_STR ""_L1);
1974
1975 const QByteArray qtBinPath = QFile::encodeName(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
1976 QByteArray path = qgetenv("PATH");
1977 if (!path.contains(qtBinPath)) { // QTBUG-39177, ensure Qt is in the path so that qt.conf is taken into account.
1978 path.prepend(QDir::listSeparator().toLatin1());
1979 path.prepend(qtBinPath);
1980 qputenv("PATH", path);
1981 }
1982
1983 Options options;
1984 QString errorMessage;
1985
1986 // Early parse the --qmake and --qtpaths options, because they are needed to determine the
1987 // options that select/deselect Qt modules.
1988 {
1989 int result = parseEarlyArguments(QCoreApplication::arguments(), &options, &errorMessage);
1990 if (result & CommandLineParseError) {
1991 std::wcerr << "Error: " << errorMessage << "\n";
1992 return 1;
1993 }
1994 }
1995
1996 const QMap<QString, QString> qtpathsVariables =
1997 queryQtPaths(options.qtpathsBinary, &errorMessage);
1998 const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
1999 if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
2000 || !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
2001 std::wcerr << "Unable to query qtpaths: " << errorMessage << '\n';
2002 return 1;
2003 }
2004
2005 options.platform = platformFromMkSpec(xSpec);
2006 // We are on MSVC and not crosscompiling. We need the host arch
2007 if (options.platform == WindowsDesktopMsvc) {
2008 SYSTEM_INFO si;
2009 GetSystemInfo(&si);
2010 switch (si.wProcessorArchitecture) {
2011 case PROCESSOR_ARCHITECTURE_INTEL:
2012 case PROCESSOR_ARCHITECTURE_IA64:
2013 case PROCESSOR_ARCHITECTURE_AMD64:
2014 options.platform |= IntelBased;
2015 break;
2016 case PROCESSOR_ARCHITECTURE_ARM:
2017 case PROCESSOR_ARCHITECTURE_ARM64:
2018 options.platform |= ArmBased;
2019 break;
2020 default:
2021 options.platform = UnknownPlatform;
2022 }
2023 }
2024 if (options.platform == UnknownPlatform) {
2025 std::wcerr << "Unsupported platform " << xSpec << '\n';
2026 return 1;
2027 }
2028
2029 // Read the Qt module information from the Qt installation directory.
2030 const QString modulesDir
2031 = qtpathsVariables.value(QLatin1String("QT_INSTALL_ARCHDATA"))
2032 + QLatin1String("/modules");
2033 const QString translationsDir
2034 = qtpathsVariables.value(QLatin1String("QT_INSTALL_TRANSLATIONS"));
2035 if (!qtModuleEntries.populate(modulesDir, translationsDir, optVerboseLevel > 1,
2036 &errorMessage)) {
2037 std::wcerr << "Error: " << errorMessage << "\n";
2038 return 1;
2039 }
2041
2042 // Read the Qt plugin types information from the Qt installation directory.
2043 PluginInformation pluginInfo{};
2044 pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
2045
2046 // Parse the full command line.
2047 {
2048 QCommandLineParser parser;
2049 QString errorMessage;
2050 const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
2051 if (result & CommandLineParseError)
2052 std::wcerr << errorMessage << "\n\n";
2053 if (result & CommandLineVersionRequested) {
2054 std::fputs(QT_VERSION_STR "\n", stdout);
2055 return 0;
2056 }
2057 if (result & CommandLineParseHelpRequested)
2058 std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
2059 if (result & CommandLineParseError)
2060 return 1;
2061 if (result & CommandLineParseHelpRequested)
2062 return 0;
2063 }
2064
2065 // Create directories
2066 if (!createDirectory(options.directory, &errorMessage, options.dryRun)) {
2067 std::wcerr << errorMessage << '\n';
2068 return 1;
2069 }
2070 if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory
2071 && !createDirectory(options.libraryDirectory, &errorMessage, options.dryRun)) {
2072 std::wcerr << errorMessage << '\n';
2073 return 1;
2074 }
2075
2076 const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
2077 if (!result) {
2078 std::wcerr << errorMessage << '\n';
2079 return 1;
2080 }
2081
2082 if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
2083 if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
2084 &errorMessage)) {
2085 std::wcerr << errorMessage << '\n';
2086 return 1;
2087 }
2088 }
2089
2090 if (options.createAppx && !options.appxCertificatePath.isEmpty()) {
2091 const QFileInfo storeLogo(options.directory + QStringLiteral("/Assets/StoreLogo.png"));
2092 if (!storeLogo.exists()) {
2093 std::wcerr << "Error: Could not open application logo file " << storeLogo.absoluteFilePath() << '\n';
2094 return 1;
2095 }
2096
2097 QFile certFile(options.appxCertificatePath);
2098 if (!certFile.open(QIODevice::ReadOnly)) {
2099 std::wcerr << "Could not open certificate file" << '\n';
2100 return 1;
2101 }
2102
2103 QSslCertificate cert(&certFile, QSsl::Der);
2104 QString publisher = cert.subjectDisplayName();
2105
2106 const QString applicationName = QFileInfo(options.binaries.first()).baseName();
2107 const QString platform = options.platform.testFlag(PlatformFlag::IntelBased) ? QStringLiteral("x64") : QStringLiteral("arm64");
2108 const QString appxFilePath(options.directory + QStringLiteral("/") + QStringLiteral("AppxManifest.xml"));
2109 QFile f(appxFilePath);
2110 if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
2111 std::wcerr << "Could not create AppxManifest.xml" << '\n';
2112 return 1;
2113 }
2114
2115 QXmlStreamWriter manifestWriter(&f);
2116 manifestWriter.setAutoFormatting(true);
2117 manifestWriter.writeStartDocument();
2118 manifestWriter.writeStartElement(QStringLiteral("Package"));
2119 manifestWriter.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.microsoft.com/appx/manifest/foundation/windows10"));
2120 manifestWriter.writeAttribute(QStringLiteral("xmlns:uap"), QStringLiteral("http://schemas.microsoft.com/appx/manifest/uap/windows10"));
2121 manifestWriter.writeAttribute(QStringLiteral("xmlns:rescap"), QStringLiteral("http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"));
2122
2123 manifestWriter.writeStartElement(QStringLiteral("Identity"));
2124 manifestWriter.writeAttribute("Name", QUuid::createUuid().toString(QUuid::WithoutBraces));
2125 manifestWriter.writeAttribute("Publisher", QStringLiteral("CN=") + publisher);
2126 manifestWriter.writeAttribute("Version", "1.0.0.0");
2127 manifestWriter.writeAttribute("ProcessorArchitecture", platform);
2128 manifestWriter.writeEndElement();
2129
2130 manifestWriter.writeStartElement("Properties");
2131 manifestWriter.writeStartElement("DisplayName");
2132 manifestWriter.writeCharacters(applicationName);
2133 manifestWriter.writeEndElement();
2134 manifestWriter.writeStartElement("PublisherDisplayName");
2135 manifestWriter.writeCharacters(publisher);
2136 manifestWriter.writeEndElement();
2137 manifestWriter.writeStartElement("Logo");
2138 manifestWriter.writeCharacters("Assets/StoreLogo.png");
2139 manifestWriter.writeEndElement();
2140 manifestWriter.writeEndElement();
2141
2142 manifestWriter.writeStartElement("Dependencies");
2143 manifestWriter.writeStartElement("TargetDeviceFamily");
2144 manifestWriter.writeAttribute("Name", "Windows.Desktop");
2145 manifestWriter.writeAttribute("MinVersion", "10.0.14316.0");
2146 manifestWriter.writeAttribute("MaxVersionTested", "10.0.14316.0");
2147 manifestWriter.writeEndElement();
2148 manifestWriter.writeEndElement();
2149
2150 manifestWriter.writeStartElement("Capabilities");
2151 manifestWriter.writeStartElement("rescap:Capability");
2152 manifestWriter.writeAttribute("Name", "runFullTrust");
2153 manifestWriter.writeEndElement();
2154 manifestWriter.writeEndElement();
2155
2156 manifestWriter.writeStartElement("Resources");
2157 manifestWriter.writeStartElement("Resource");
2158 if (options.languages.isEmpty()) {
2159 QLocale locale = QLocale::system();
2160 manifestWriter.writeAttribute("Language", locale.bcp47Name());
2161 } else {
2162 for (const auto& language : options.languages) {
2163 manifestWriter.writeAttribute("Language", language);
2164 }
2165 }
2166 manifestWriter.writeEndElement();
2167 manifestWriter.writeEndElement();
2168
2169 manifestWriter.writeStartElement("Applications");
2170 for (const auto& binary : options.binaries) {
2171 const QString binaryRelative = binary.split(QStringLiteral("/")).last();
2172 const QString displayName = binaryRelative.split(QStringLiteral(".")).first();
2173 QFile descriptionFile(options.directory + QStringLiteral("/") + QStringLiteral("Assets/Description_") + displayName + QStringLiteral(".txt"));
2174 QString description;
2175 if (!descriptionFile.exists())
2176 std::wcerr << "Warning: No package description was provided " << descriptionFile.fileName() << '\n';
2177 if (descriptionFile.open(QIODevice::ReadOnly | QIODevice::Text))
2178 description = QString::fromUtf8(descriptionFile.readAll());
2179
2180 manifestWriter.writeStartElement("Application");
2181 manifestWriter.writeAttribute("Id", displayName);
2182 manifestWriter.writeAttribute("Executable", binaryRelative);
2183 manifestWriter.writeAttribute("EntryPoint", "Windows.FullTrustApplication");
2184 manifestWriter.writeStartElement("uap:VisualElements");
2185 manifestWriter.writeAttribute("DisplayName", displayName);
2186 manifestWriter.writeAttribute("Description", description);
2187 manifestWriter.writeAttribute("BackgroundColor", "transparent");
2188 manifestWriter.writeAttribute("Square150x150Logo", "Assets/Logo.png");
2189 manifestWriter.writeAttribute("Square44x44Logo", "Assets/SmallLogo.png");
2190 manifestWriter.writeStartElement("uap:DefaultTile");
2191 manifestWriter.writeEndElement();
2192 manifestWriter.writeEndElement();
2193 manifestWriter.writeEndElement();
2194 }
2195 manifestWriter.writeEndElement();
2196 manifestWriter.writeEndElement();
2197 manifestWriter.writeEndDocument();
2198 }
2199
2200 if (options.json) {
2201 if (options.list)
2202 std::fputs(options.json->toList(options.list, options.directory).constData(), stdout);
2203 else
2204 std::fputs(options.json->toJson().constData(), stdout);
2205 delete options.json;
2206 options.json = nullptr;
2207 }
2208
2209 return 0;
2210}
QStringList operator()(const QDir &dir) const
Definition main.cpp:886
DllDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, const QString &prefix=QString())
Definition main.cpp:882
QStringList operator()(const QDir &dir) const
Definition main.cpp:923
QmlDirectoryFileEntryFunction(const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
Definition main.cpp:917
static Platform platformFromMkSpec(const QString &xSpec)
Definition main.cpp:135
static bool isQtModule(const QString &libName)
Definition main.cpp:835
static QString libraryPath(const QString &libraryLocation, const char *name, const QString &infix, Platform platform, bool debug)
Definition main.cpp:1313
static QString lineBreak(QString s)
Definition main.cpp:788
static QString msgFileDoesNotExist(const QString &file)
Definition main.cpp:238
static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
Definition main.cpp:1390
static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory, const Options &options, QString *errorMessage)
Definition main.cpp:1463
static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary, Platform platform, QString *errorMessage, QStringList *qtDependencies, QStringList *nonQtDependencies)
Definition main.cpp:845
static void assignKnownModuleIds()
Definition main.cpp:60
static QCommandLineOption createVerboseOption()
Definition main.cpp:267
ExlusiveOptionValue
Definition main.cpp:153
@ OptionEnabled
Definition main.cpp:155
@ OptionAuto
Definition main.cpp:154
@ OptionDisabled
Definition main.cpp:156
static int parseArguments(const QStringList &arguments, QCommandLineParser *parser, Options *options, QString *errorMessage)
Definition main.cpp:335
static ExlusiveOptionValue parseExclusiveOptions(const QCommandLineParser *parser, const QCommandLineOption &enableOption, const QCommandLineOption &disableOption)
Definition main.cpp:159
static int qtVersion(const QMap< QString, QString > &qtpathsVariables)
Definition main.cpp:1452
static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
Definition main.cpp:1176
static QString findBinary(const QString &directory, Platform platform)
Definition main.cpp:223
static DeployResult deploy(const Options &options, const QMap< QString, QString > &qtpathsVariables, const PluginInformation &pluginInfo, QString *errorMessage)
Definition main.cpp:1493
static int parseEarlyArguments(const QStringList &arguments, Options *options, QString *errorMessage)
Definition main.cpp:276
static QCommandLineOption createQMakeOption()
Definition main.cpp:249
static bool deployWebEngineCore(const QMap< QString, QString > &qtpathsVariables, const PluginInformation &pluginInfo, const Options &options, bool isDebug, QString *errorMessage)
Definition main.cpp:1899
static QStringList qmlCacheFileFilters()
Definition main.cpp:903
static QString pdbFileName(QString libraryFileName)
Definition main.cpp:895
CommandLineParseFlag
Definition main.cpp:243
@ CommandLineParseError
Definition main.cpp:244
@ CommandLineVersionRequested
Definition main.cpp:246
@ CommandLineParseHelpRequested
Definition main.cpp:245
static QString moduleNameToOptionName(const QString &moduleName, bool internal)
Definition main.cpp:93
static QString formatQtPlugins(const PluginInformation &pluginInfo)
Definition main.cpp:120
#define DECLARE_KNOWN_MODULE(name)
Definition main.cpp:43
static QCommandLineOption createQtPathsOption()
Definition main.cpp:258
static bool needsPluginType(const QString &subDirName, const PluginInformation &pluginInfo, const PluginSelections &pluginSelections)
Definition main.cpp:1091
static qint64 qtModule(QString module, const QString &infix)
Definition main.cpp:975
static QString vcRedistDir()
Definition main.cpp:1327
static QString webProcessBinary(const char *binaryName, Platform p)
Definition main.cpp:87
static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
Definition main.cpp:1246
static const char webEngineProcessC[]
Definition main.cpp:85
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)
Definition main.cpp:1001
static QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
Definition main.cpp:800
static bool deployWebProcess(const QMap< QString, QString > &qtpathsVariables, const char *binaryName, const PluginInformation &pluginInfo, const Options &sourceOptions, QString *errorMessage)
Definition main.cpp:1878
static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
Definition main.cpp:1362
#define DEFINE_KNOWN_MODULE(name)
Definition main.cpp:57
#define IMAGE_FILE_MACHINE_ARM64
Definition main.cpp:26
static QString getIcuVersion(const QString &libName)
Definition main.cpp:1485
static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules, const QString &target, const Options &options, QString *errorMessage)
Definition main.cpp:1189
static QtModuleInfoStore qtModuleEntries
Definition main.cpp:41
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)
Definition main.cpp:1102
static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
Definition main.cpp:1274
static QString vcDebugRedistDir()
Definition main.cpp:1325
static QByteArray formatQtModules(const ModuleBitset &mask, bool option=false)
Definition main.cpp:105
int main(int argc, char *argv[])
[ctor_close]
ModuleBitset usedQtLibraries
Definition main.cpp:1309
ModuleBitset directlyUsedQtLibraries
Definition main.cpp:1308
operator bool() const
Definition main.cpp:1304
bool isDebug
Definition main.cpp:1307
ModuleBitset deployedQtLibraries
Definition main.cpp:1310
bool success
Definition main.cpp:1306
QString libraryDirectory
Definition main.cpp:204
bool translations
Definition main.cpp:186
JsonOutput * json
Definition main.cpp:209
DebugDetection debugDetection
Definition main.cpp:211
QStringList binaries
Definition main.cpp:208
bool quickImports
Definition main.cpp:185
bool systemDxc
Definition main.cpp:188
bool ffmpeg
Definition main.cpp:191
bool forceOpenSslPlugin
Definition main.cpp:217
unsigned updateFileFlags
Definition main.cpp:196
int qmlImportTimeout
Definition main.cpp:199
ListOption list
Definition main.cpp:210
QStringList qmlImportPaths
Definition main.cpp:169
QString qtpathsBinary
Definition main.cpp:201
bool deployPdb
Definition main.cpp:212
PluginSelections pluginSelections
Definition main.cpp:192
QStringList qmlDirectories
Definition main.cpp:197
QString translationsDirectory
Definition main.cpp:202
QStringList languages
Definition main.cpp:203
ModuleBitset additionalLibraries
Definition main.cpp:194
QString directory
Definition main.cpp:200
bool patchQt
Definition main.cpp:214
bool systemD3dCompiler
Definition main.cpp:187
Platform platform
Definition main.cpp:193
bool createAppx
Definition main.cpp:218
bool ignoreLibraryErrors
Definition main.cpp:215
QString pluginDirectory
Definition main.cpp:205
QString qmlDirectory
Definition main.cpp:207
bool softwareRasterizer
Definition main.cpp:190
QString openSslRootDirectory
Definition main.cpp:206
ModuleBitset disabledLibraries
Definition main.cpp:195
bool dryRun
Definition main.cpp:213
bool deployInsightTrackerPlugin
Definition main.cpp:216
QString appxCertificatePath
Definition main.cpp:219
bool plugins
Definition main.cpp:183
DebugDetection
Definition main.cpp:177
@ DebugDetectionForceRelease
Definition main.cpp:180
@ DebugDetectionForceDebug
Definition main.cpp:179
@ DebugDetectionAuto
Definition main.cpp:178
bool libraries
Definition main.cpp:184
bool compilerRunTime
Definition main.cpp:189
PlatformFlag
Definition utils.h:26
@ MinGW
Definition utils.h:34
@ WindowsDesktopMsvcArm
Definition utils.h:40
@ ClangMsvc
Definition utils.h:35
@ WindowsBased
Definition utils.h:28
@ WindowsDesktopMsvc
Definition utils.h:38
@ Msvc
Definition utils.h:33
@ WindowsDesktopMinGW
Definition utils.h:41
@ UnknownPlatform
Definition utils.h:44
@ ArmBased
Definition utils.h:31
@ WindowsDesktopClangMinGW
Definition utils.h:43
@ WindowsDesktopClangMsvc
Definition utils.h:42
@ IntelBased
Definition utils.h:30
int optVerboseLevel
Definition utils.cpp:28
const char * qmakeInfixKey
Definition utils.cpp:192
@ SkipUpdateFile
Definition utils.h:208
@ ForceUpdateFile
Definition utils.h:207
static const char windowsSharedLibrarySuffix[]
Definition utils.h:145
DebugMatchMode
Definition utils.h:158
@ MatchRelease
Definition utils.h:160
@ MatchDebug
Definition utils.h:159
@ MatchDebugOrRelease
Definition utils.h:161