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.testFlags(WindowsDesktopMsvc)
596 || 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.testFlags(WindowsDesktopMsvc)) {
603 *errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
605 }
606
607 if (parser->isSet(skipPluginTypesOption))
608 options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
609
610 if (parser->isSet(addPluginTypesOption))
611 options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
612
613 if (parser->isSet(includePluginsOption))
614 options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
615
616 if (parser->isSet(excludePluginsOption))
617 options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
618
619 if (parser->isSet(releaseWithDebugInfoOption))
620 std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete.";
621
622 switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
623 case OptionAuto:
624 break;
625 case OptionEnabled:
627 break;
628 case OptionDisabled:
630 break;
631 }
632
633 if (parser->isSet(deployPdbOption)) {
634 if (options->platform.testFlag(WindowsBased) && !options->platform.testFlag(MinGW))
635 options->deployPdb = true;
636 else
637 std::wcerr << "Warning: --" << deployPdbOption.names().first() << " is not supported on this platform.\n";
638 }
639
640 if (parser->isSet(suppressSoftwareRasterizerOption))
641 options->softwareRasterizer = false;
642
643 if (parser->isSet(noFFmpegOption))
644 options->ffmpeg = false;
645
646 if (parser->isSet(forceOpenSslOption))
647 options->forceOpenSslPlugin = true;
648
649 if (parser->isSet(openSslRootOption))
650 options->openSslRootDirectory = parser->value(openSslRootOption);
651
652 if (options->forceOpenSslPlugin && !options->openSslRootDirectory.isEmpty()) {
653 *errorMessage = QStringLiteral("force-openssl and openssl-root are mutually exclusive");
655 }
656
657 if (parser->isSet(forceOption))
659 if (parser->isSet(dryRunOption)) {
660 options->dryRun = true;
662 }
663
664 options->patchQt = !parser->isSet(noPatchQtOption);
665 options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
666 if (insightTrackerModuleAvailable)
667 options->deployInsightTrackerPlugin = parser->isSet(deployInsightTrackerOption);
668
669 for (const QtModule &module : qtModuleEntries) {
670 if (parser->isSet(*enabledModuleOptions.at(module.id)))
671 options->additionalLibraries[module.id] = 1;
672 if (parser->isSet(*disabledModuleOptions.at(module.id)))
673 options->disabledLibraries[module.id] = 1;
674 }
675
676 // Add some dependencies
677 if (options->additionalLibraries.test(QtQuickModuleId))
678 options->additionalLibraries[QtQmlModuleId] = 1;
679 if (options->additionalLibraries.test(QtDesignerComponentsModuleId))
680 options->additionalLibraries[QtDesignerModuleId] = 1;
681
682 if (parser->isSet(listOption)) {
683 const QString value = parser->value(listOption);
684 if (value == QStringLiteral("source")) {
685 options->list = ListSource;
686 } else if (value == QStringLiteral("target")) {
687 options->list = ListTarget;
688 } else if (value == QStringLiteral("relative")) {
689 options->list = ListRelative;
690 } else if (value == QStringLiteral("mapping")) {
691 options->list = ListMapping;
692 } else {
693 *errorMessage = QStringLiteral("Please specify a valid option for -list (source, target, relative, mapping).");
695 }
696 }
697
698 if (parser->isSet(jsonOption) || options->list) {
699 optVerboseLevel = 0;
700 options->json = new JsonOutput;
701 }
702
703 const QStringList posArgs = parser->positionalArguments();
704 if (posArgs.isEmpty()) {
705 *errorMessage = QStringLiteral("Please specify the binary or folder.");
707 }
708
709 if (parser->isSet(dirOption))
710 options->directory = parser->value(dirOption);
711
712 if (parser->isSet(qmlDirOption))
713 options->qmlDirectories = parser->values(qmlDirOption);
714
715 if (parser->isSet(qmlImportOption))
716 options->qmlImportPaths = parser->values(qmlImportOption);
717
718 if (parser->isSet(qmlImportTimeoutOption)) {
719 const QString timeoutString = parser->value(qmlImportTimeoutOption);
720 bool ok;
721 int timeout = timeoutString.toInt(&ok);
722 if (!ok) {
723 *errorMessage = u'"' + timeoutString + QStringLiteral("\" is not an acceptable timeout "
724 "value.");
726 }
727 options->qmlImportTimeout = timeout;
728 }
729
730 const QString &file = posArgs.front();
731 const QFileInfo fi(QDir::cleanPath(file));
732 if (!fi.exists()) {
733 *errorMessage = msgFileDoesNotExist(file);
735 }
736
737 if (!options->directory.isEmpty() && !fi.isFile()) { // -dir was specified - expecting file.
738 *errorMessage = u'"' + file + QStringLiteral("\" is not an executable file.");
740 }
741
742 if (fi.isFile()) {
743 options->binaries.append(fi.absoluteFilePath());
744 if (options->directory.isEmpty())
745 options->directory = fi.absolutePath();
746 } else {
747 const QString binary = findBinary(fi.absoluteFilePath(), options->platform);
748 if (binary.isEmpty()) {
749 *errorMessage = QStringLiteral("Unable to find binary in \"") + file + u'"';
751 }
752 options->directory = fi.absoluteFilePath();
753 options->binaries.append(binary);
754 } // directory.
755
756 // Remaining files or plugin directories
757 bool multipleDirs = false;
758 for (int i = 1; i < posArgs.size(); ++i) {
759 const QFileInfo fi(QDir::cleanPath(posArgs.at(i)));
760 const QString path = fi.absoluteFilePath();
761 if (!fi.exists()) {
762 *errorMessage = msgFileDoesNotExist(path);
764 }
765 if (fi.isDir()) {
766 const QStringList libraries =
767 findSharedLibraries(QDir(path), options->platform, MatchDebugOrRelease, QString());
768 for (const QString &library : libraries)
769 options->binaries.append(path + u'/' + library);
770 } else {
771 if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
772 multipleDirs = true;
773 options->binaries.append(path);
774 }
775 }
776 if (multipleDirs) {
777 std::wcerr << "Warning: using binaries from different directories, deploying to following path: "
778 << options->directory << '\n' << "To disable this warning, use the --dir option\n";
779 }
780 if (options->translationsDirectory.isEmpty())
781 options->translationsDirectory = options->directory + "/translations"_L1;
782 return 0;
783}
784
785// Simple line wrapping at 80 character boundaries.
786static inline QString lineBreak(QString s)
787{
788 for (qsizetype i = 80; i < s.size(); i += 80) {
789 const qsizetype lastBlank = s.lastIndexOf(u' ', i);
790 if (lastBlank >= 0) {
791 s[lastBlank] = u'\n';
792 i = lastBlank + 1;
793 }
794 }
795 return s;
796}
797
798static inline QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
799{
800 QString result = p.helpText();
801 // Replace the default-generated text which is too long by a short summary
802 // explaining how to enable single libraries.
803 if (qtModuleEntries.size() == 0)
804 return result;
805 const QtModule &firstModule = qtModuleEntries.moduleById(0);
806 const QString firstModuleOption = moduleNameToOptionName(firstModule.name, firstModule.internal);
807 const qsizetype moduleStart = result.indexOf("\n --"_L1 + firstModuleOption);
808 const qsizetype argumentsStart = result.lastIndexOf("\nArguments:"_L1);
809 if (moduleStart >= argumentsStart)
810 return result;
811 QString moduleHelp;
812 moduleHelp +=
813 "\n\nQt libraries can be added by passing their name (-xml) or removed by passing\n"
814 "the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
815 ModuleBitset mask;
816 moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
817 moduleHelp += u"\n\n";
818 moduleHelp +=
819 u"Qt plugins can be included or excluded individually or by type.\n"
820 u"To deploy or block plugins individually, use the --include-plugins\n"
821 u"and --exclude-plugins options (--include-plugins qjpeg,qsvgicon)\n"
822 u"You can also use the --skip-plugin-types or --add-plugin-types to\n"
823 u"achieve similar results with entire plugin groups, like imageformats, e.g.\n"
824 u"(--add-plugin-types imageformats,iconengines). Exclusion always takes\n"
825 u"precedence over inclusion, and types take precedence over specific plugins.\n"
826 u"For example, including qjpeg, but skipping imageformats, will NOT deploy qjpeg.\n"
827 u"\nDetected available plugins:\n";
828 moduleHelp += formatQtPlugins(pluginInfo);
829 result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp);
830 return result;
831}
832
833static inline bool isQtModule(const QString &libName)
834{
835 // Match Standard modules named Qt6XX.dll
836 if (libName.size() < 3 || !libName.startsWith("Qt"_L1, Qt::CaseInsensitive))
837 return false;
838 const QChar version = libName.at(2);
839 return version.isDigit() && (version.toLatin1() - '0') == QT_VERSION_MAJOR;
840}
841
842// Helper for recursively finding all dependent Qt libraries.
843static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary,
844 Platform platform, QString *errorMessage,
845 QStringList *qtDependencies, QStringList *nonQtDependencies)
846{
847 QStringList dependentLibs;
848 if (!readPeExecutableDependencies(binary, errorMessage, &dependentLibs)) {
849 errorMessage->prepend("Unable to find dependent libraries of "_L1 +
850 QDir::toNativeSeparators(binary) + " :"_L1);
851 return false;
852 }
853 // Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we
854 // are run the 2nd time (updating). We want to check against the Qt bin dir libraries
855 const int start = qtDependencies->size();
856 for (const QString &lib : std::as_const(dependentLibs)) {
857 if (isQtModule(lib)) {
858 const QString path = normalizeFileName(qtBinDir + u'/' + QFileInfo(lib).fileName());
859 if (!qtDependencies->contains(path))
860 qtDependencies->append(path);
861 } else if (nonQtDependencies && !nonQtDependencies->contains(lib)) {
862 nonQtDependencies->append(lib);
863 }
864 }
865 const int end = qtDependencies->size();
866 // Recurse
867 for (int i = start; i < end; ++i) {
868 if (!findDependentQtLibraries(qtBinDir, qtDependencies->at(i), platform, errorMessage,
869 qtDependencies, nonQtDependencies)) {
870 return false;
871 }
872 }
873 return true;
874}
875
876// Base class to filter debug/release Windows DLLs for functions to be passed to updateFile().
877// Tries to pre-filter by namefilter and does check via PE.
879public:
880 explicit DllDirectoryFileEntryFunction(Platform platform,
881 DebugMatchMode debugMatchMode, const QString &prefix = QString()) :
882 m_platform(platform), m_debugMatchMode(debugMatchMode), m_prefix(prefix) {}
883
884 QStringList operator()(const QDir &dir) const
885 { return findSharedLibraries(dir, m_platform, m_debugMatchMode, m_prefix); }
886
887private:
888 const Platform m_platform;
889 const DebugMatchMode m_debugMatchMode;
890 const QString m_prefix;
891};
892
893static QString pdbFileName(QString libraryFileName)
894{
895 const qsizetype lastDot = libraryFileName.lastIndexOf(u'.') + 1;
896 if (lastDot <= 0)
897 return QString();
898 libraryFileName.replace(lastDot, libraryFileName.size() - lastDot, "pdb"_L1);
899 return libraryFileName;
900}
902{
903 return QStringList() << QStringLiteral("*.jsc") << QStringLiteral("*.qmlc");
904}
905
906// File entry filter function for updateFile() that returns a list of files for
907// QML import trees: DLLs (matching debug) and .qml/,js, etc.
909public:
910 enum Flags {
913 };
914
916 const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
919 {}
920
921 QStringList operator()(const QDir &dir) const
922 {
923 if (moduleSourceDir(dir).canonicalPath() != m_moduleSourcePath) {
924 // If we're in a different module, return nothing.
925 return {};
926 }
927
928 QStringList result;
929 const QStringList &libraries = m_dllFilter(dir);
930 for (const QString &library : libraries) {
931 result.append(library);
932 if (m_flags & DeployPdb) {
933 const QString pdb = pdbFileName(library);
934 if (QFileInfo(dir.absoluteFilePath(pdb)).isFile())
935 result.append(pdb);
936 }
937 }
938 result.append(m_qmlNameFilter(dir));
939 return result;
940 }
941
942private:
943 static QDir moduleSourceDir(const QDir &dir)
944 {
945 QDir moduleSourceDir = dir;
946 while (!moduleSourceDir.exists(QStringLiteral("qmldir"))) {
947 if (!moduleSourceDir.cdUp()) {
948 return {};
949 }
950 }
951 return moduleSourceDir;
952 }
953
954 static inline QStringList qmlNameFilters(unsigned flags)
955 {
956 QStringList result;
957 result << QStringLiteral("qmldir") << QStringLiteral("*.qmltypes")
958 << QStringLiteral("*.frag") << QStringLiteral("*.vert") // Shaders
959 << QStringLiteral("*.ttf");
960 if (!(flags & SkipSources)) {
961 result << QStringLiteral("*.js") << QStringLiteral("*.qml") << QStringLiteral("*.png");
962 result.append(qmlCacheFileFilters());
963 }
964 return result;
965 }
966
967 const unsigned m_flags;
968 NameFilterFileEntryFunction m_qmlNameFilter;
970 QString m_moduleSourcePath;
971};
972
973static qint64 qtModule(QString module, const QString &infix)
974{
975 // Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0'
976 const qsizetype lastSlashPos = module.lastIndexOf(u'/');
977 if (lastSlashPos > 0)
978 module.remove(0, lastSlashPos + 1);
979 if (module.startsWith("lib"_L1))
980 module.remove(0, 3);
981 int endPos = infix.isEmpty() ? -1 : module.lastIndexOf(infix);
982 if (endPos == -1)
983 endPos = module.indexOf(u'.'); // strip suffixes '.so.5.0'.
984 if (endPos > 0)
985 module.truncate(endPos);
986 // That should leave us with 'Qt6Core<d>'.
987 for (const auto &qtModule : qtModuleEntries) {
988 const QString &libraryName = qtModule.name;
989 if (module == libraryName
990 || (module.size() == libraryName.size() + 1 && module.startsWith(libraryName))) {
991 return qtModule.id;
992 }
993 }
994 std::wcerr << "Warning: module " << qPrintable(module) << " could not be found\n";
995 return -1;
996}
997
998// Return the path if a plugin is to be deployed
999static QString deployPlugin(const QString &plugin, const QDir &subDir, const bool dueToModule,
1000 const DebugMatchMode &debugMatchMode, ModuleBitset *pluginNeededQtModules,
1001 const ModuleBitset &disabledQtModules,
1002 const PluginSelections &pluginSelections, const QString &libraryLocation,
1003 const QString &infix, Platform platform,
1004 bool deployInsightTrackerPlugin, bool deployOpenSslPlugin)
1005{
1006 const QString subDirName = subDir.dirName();
1007 // Filter out disabled plugins
1008 if (optVerboseLevel && pluginSelections.disabledPluginTypes.contains(subDirName)) {
1009 std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n';
1010 return {};
1011 }
1012 if (optVerboseLevel && subDirName == u"generic" && plugin.contains(u"qinsighttracker")
1013 && !deployInsightTrackerPlugin) {
1014 std::wcout << "Skipping plugin " << plugin
1015 << ". Use -deploy-insighttracker if you want to use it.\n";
1016 return {};
1017 }
1018 if (optVerboseLevel && subDirName == u"tls" && plugin.contains(u"qopensslbackend")
1019 && !deployOpenSslPlugin) {
1020 std::wcout << "Skipping plugin " << plugin
1021 << ". Use -force-openssl or specify -openssl-root if you want to use it.\n";
1022 return {};
1023 }
1024
1025 const int dotIndex = plugin.lastIndexOf(u'.');
1026 // Strip the .dll from the name, and an additional 'd' if it's a debug library with the 'd'
1027 // suffix
1028 const int stripIndex = debugMatchMode == MatchDebug && platformHasDebugSuffix(platform)
1029 ? dotIndex - 1
1030 : dotIndex;
1031 const QString pluginName = plugin.first(stripIndex);
1032
1033 if (optVerboseLevel && pluginSelections.excludedPlugins.contains(pluginName)) {
1034 std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n';
1035 return {};
1036 }
1037
1038 // By default, only deploy qwindows.dll
1039 if (subDirName == u"platforms"
1040 && !(pluginSelections.includedPlugins.contains(pluginName)
1041 || (pluginSelections.enabledPluginTypes.contains(subDirName)))
1042 && !pluginName.startsWith(u"qwindows")) {
1043 return {};
1044 }
1045
1046 const QString pluginPath = subDir.absoluteFilePath(plugin);
1047
1048 // If dueToModule is false, check if the user included the plugin or the entire type. In the
1049 // former's case, only deploy said plugin and not all plugins of that type.
1050 const bool requiresPlugin = pluginSelections.includedPlugins.contains(pluginName)
1051 || pluginSelections.enabledPluginTypes.contains(subDirName);
1052 if (!dueToModule && !requiresPlugin)
1053 return {};
1054
1055 // Deploy QUiTools plugins as is without further dependency checking.
1056 // The user needs to ensure all required libraries are present (would
1057 // otherwise pull QtWebEngine for its plugin).
1058 if (subDirName == u"designer")
1059 return pluginPath;
1060
1061 QStringList dependentQtLibs;
1062 QString errorMessage;
1063 if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
1064 &errorMessage, &dependentQtLibs, nullptr)) {
1065 for (int d = 0; d < dependentQtLibs.size(); ++d) {
1066 const qint64 module = qtModule(dependentQtLibs.at(d), infix);
1067 if (module >= 0)
1068 (*pluginNeededQtModules)[module] = 1;
1069 }
1070 } else {
1071 std::wcerr << "Warning: Cannot determine dependencies of "
1072 << QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
1073 }
1074
1075 ModuleBitset disabledNeededQtModules;
1076 disabledNeededQtModules = *pluginNeededQtModules & disabledQtModules;
1077 if (disabledNeededQtModules.any()) {
1078 if (optVerboseLevel) {
1079 std::wcout << "Skipping plugin " << plugin
1080 << " due to disabled dependencies ("
1081 << formatQtModules(disabledNeededQtModules).constData() << ").\n";
1082 }
1083 return {};
1084 }
1085
1086 return pluginPath;
1087}
1088
1089static bool needsPluginType(const QString &subDirName, const PluginInformation &pluginInfo,
1090 const PluginSelections &pluginSelections)
1091{
1092 bool needsTypeForPlugin = false;
1093 for (const QString &plugin: pluginSelections.includedPlugins) {
1094 if (pluginInfo.isTypeForPlugin(subDirName, plugin))
1095 needsTypeForPlugin = true;
1096 }
1097 return (pluginSelections.enabledPluginTypes.contains(subDirName) || needsTypeForPlugin);
1098}
1099
1100QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
1101 const PluginInformation &pluginInfo, const PluginSelections &pluginSelections,
1102 const QString &qtPluginsDirName, const QString &libraryLocation,
1103 const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform,
1104 QString *platformPlugin, bool deployInsightTrackerPlugin,
1105 bool deployOpenSslPlugin)
1106{
1107 if (qtPluginsDirName.isEmpty())
1108 return QStringList();
1109 QDir pluginsDir(qtPluginsDirName);
1110 QStringList result;
1111 bool missingQtModulesAdded = false;
1112 const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
1113 for (const QFileInfo &subDirFi : pluginDirs) {
1114 const QString subDirName = subDirFi.fileName();
1115 const size_t module = qtModuleEntries.moduleIdForPluginType(subDirName);
1116 if (module == QtModule::InvalidId) {
1117 if (optVerboseLevel > 1) {
1118 std::wcerr << "No Qt module found for plugin type \"" << subDirName << "\".\n";
1119 }
1120 continue;
1121 }
1122 const bool dueToModule = usedQtModules->test(module);
1123 if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
1124 const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
1125 ? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all.
1126 : debugMatchModeIn;
1127 QDir subDir(subDirFi.absoluteFilePath());
1128 if (optVerboseLevel)
1129 std::wcout << "Adding in plugin type " << subDirFi.baseName() << " for module: " << qtModuleEntries.moduleById(module).name << '\n';
1130
1131 const bool isPlatformPlugin = subDirName == "platforms"_L1;
1132 const QStringList plugins =
1133 findSharedLibraries(subDir, platform, debugMatchMode, QString());
1134 for (const QString &plugin : plugins) {
1135 ModuleBitset pluginNeededQtModules;
1136 const QString pluginPath =
1137 deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
1138 disabledQtModules, pluginSelections, libraryLocation, infix,
1139 platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
1140 if (!pluginPath.isEmpty()) {
1141 if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
1142 *platformPlugin = subDir.absoluteFilePath(plugin);
1143 result.append(pluginPath);
1144
1145 const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
1146 if (missingModules.any()) {
1147 *usedQtModules |= missingModules;
1148 missingQtModulesAdded = true;
1149 if (optVerboseLevel) {
1150 std::wcout << "Adding " << formatQtModules(missingModules).constData()
1151 << " for " << plugin << " from plugin type: " << subDirName << '\n';
1152 }
1153 }
1154 }
1155 } // for filter
1156 } // type matches
1157 } // for plugin folder
1158
1159 // If missing Qt modules were added during plugin deployment make additional pass, because we may need
1160 // additional plugins.
1161 if (missingQtModulesAdded) {
1162 if (optVerboseLevel) {
1163 std::wcout << "Performing additional pass of finding Qt plugins due to updated Qt module list: "
1164 << formatQtModules(*usedQtModules).constData() << "\n";
1165 }
1166 return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
1167 libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
1168 deployInsightTrackerPlugin, deployOpenSslPlugin);
1169 }
1170
1171 return result;
1172}
1173
1174static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
1175{
1176 QStringList result;
1177 for (const auto &qtModule : qtModuleEntries) {
1178 if (modules.test(qtModule.id) && !qtModule.translationCatalog.isEmpty()) {
1179 const QString name = qtModule.translationCatalog + u'_' + prefix + ".qm"_L1;
1180 if (!result.contains(name))
1181 result.push_back(name);
1182 }
1183 }
1184 return result;
1185}
1186
1187static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules,
1188 const QString &target, const Options &options,
1189 QString *errorMessage)
1190{
1191 // Find available languages prefixes by checking on qtbase.
1192 QStringList prefixes;
1193 QDir sourceDir(sourcePath);
1194 const QStringList qmFilter = QStringList(QStringLiteral("qtbase_*.qm"));
1195 const QFileInfoList &qmFiles = sourceDir.entryInfoList(qmFilter);
1196 for (const QFileInfo &qmFi : qmFiles) {
1197 const QString prefix = qmFi.baseName().mid(7);
1198 if (options.languages.isEmpty() || options.languages.contains(prefix))
1199 prefixes.append(prefix);
1200 }
1201 if (prefixes.isEmpty()) {
1202 std::wcerr << "Warning: Could not find any translations in "
1203 << QDir::toNativeSeparators(sourcePath) << " (developer build?)\n.";
1204 return true;
1205 }
1206 // Run lconvert to concatenate all files into a single named "qt_<prefix>.qm" in the application folder
1207 // Use QT_INSTALL_TRANSLATIONS as working directory to keep the command line short.
1208 const QString absoluteTarget = QFileInfo(target).absoluteFilePath();
1209 const QString binary = QStringLiteral("lconvert");
1210 QStringList arguments;
1211 for (const QString &prefix : std::as_const(prefixes)) {
1212 arguments.clear();
1213 const QString targetFile = QStringLiteral("qt_") + prefix + QStringLiteral(".qm");
1214 arguments.append(QStringLiteral("-o"));
1215 const QString targetFilePath = absoluteTarget + u'/' + targetFile;
1216 if (options.json)
1217 options.json->addFile(sourcePath + u'/' + targetFile, absoluteTarget);
1218 arguments.append(QDir::toNativeSeparators(targetFilePath));
1219 const QStringList translationFilters = translationNameFilters(usedQtModules, prefix);
1220 if (translationFilters.isEmpty()){
1221 std::wcerr << "Warning: translation catalogs are all empty, skipping translation deployment\n";
1222 return true;
1223 }
1224 const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationFilters);
1225 for (const QFileInfo &langQmFileFi : langQmFiles) {
1226 if (options.json) {
1227 options.json->addFile(langQmFileFi.absoluteFilePath(),
1228 absoluteTarget);
1229 }
1230 arguments.append(langQmFileFi.fileName());
1231 }
1232 if (optVerboseLevel)
1233 std::wcout << "Creating " << targetFile << "...\n";
1234 unsigned long exitCode;
1235 if ((options.updateFileFlags & SkipUpdateFile) == 0
1236 && (!runProcess(binary, arguments, sourcePath, &exitCode, nullptr, nullptr, errorMessage)
1237 || exitCode)) {
1238 return false;
1239 }
1240 } // for prefixes.
1241 return true;
1242}
1243
1244static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
1245{
1246 const std::vector<QLatin1StringView> ffmpegHints = { "avcodec"_L1, "avformat"_L1, "avutil"_L1,
1247 "swresample"_L1, "swscale"_L1 };
1248 const QStringList bundledLibs =
1249 findSharedLibraries(qtBinDir, platform, MatchDebugOrRelease, {});
1250
1251 QStringList ffmpegLibs;
1252 for (const QLatin1StringView &libHint : ffmpegHints) {
1253 const QStringList ffmpegLib = bundledLibs.filter(libHint, Qt::CaseInsensitive);
1254
1255 if (ffmpegLib.empty()) {
1256 std::wcerr << "Warning: Cannot find FFmpeg libraries. Multimedia features will not work as expected.\n";
1257 return {};
1258 } else if (ffmpegLib.size() != 1u) {
1259 std::wcerr << "Warning: Multiple versions of FFmpeg libraries found. Multimedia features will not work as expected.\n";
1260 return {};
1261 }
1262
1263 const QChar slash(u'/');
1264 QFileInfo ffmpegLibPath{ qtBinDir + slash + ffmpegLib.front() };
1265 ffmpegLibs.append(ffmpegLibPath.absoluteFilePath());
1266 }
1267
1268 return ffmpegLibs;
1269}
1270
1271// Find the openssl libraries Qt executables depend on.
1272static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
1273{
1274 const std::vector<QLatin1StringView> libHints = { "libcrypto"_L1, "libssl"_L1 };
1275 const QChar slash(u'/');
1276 const QString openSslBinDir = openSslRootDir + slash + "bin"_L1;
1277 const QStringList openSslRootLibs =
1278 findSharedLibraries(openSslBinDir, platform, MatchDebugOrRelease, {});
1279
1280 QStringList result;
1281 for (const QLatin1StringView &libHint : libHints) {
1282 const QStringList lib = openSslRootLibs.filter(libHint, Qt::CaseInsensitive);
1283
1284 if (lib.empty()) {
1285 std::wcerr << "Warning: Cannot find openssl libraries.\n";
1286 return {};
1287 } else if (lib.size() != 1u) {
1288 std::wcerr << "Warning: Multiple versions of openssl libraries found.\n";
1289 return {};
1290 }
1291
1292 QFileInfo libPath{ openSslBinDir + slash + lib.front() };
1293 result.append(libPath.absoluteFilePath());
1294 }
1295
1296 return result;
1297}
1298
1299
1310
1311static QString libraryPath(const QString &libraryLocation, const char *name,
1312 const QString &infix, Platform platform, bool debug)
1313{
1314 QString result = libraryLocation + u'/';
1315 result += QLatin1StringView(name);
1316 result += infix;
1317 if (debug && platformHasDebugSuffix(platform))
1318 result += u'd';
1319 result += sharedLibrarySuffix();
1320 return result;
1321}
1322
1323static QString vcDebugRedistDir() { return QStringLiteral("Debug_NonRedist"); }
1324
1326{
1327 const char vcDirVar[] = "VCINSTALLDIR";
1328 const QChar slash(u'/');
1329 QString vcRedistDirName = QDir::cleanPath(QFile::decodeName(qgetenv(vcDirVar)));
1330 if (vcRedistDirName.isEmpty()) {
1331 std::wcerr << "Warning: Cannot find Visual Studio installation directory, " << vcDirVar
1332 << " is not set.\n";
1333 return QString();
1334 }
1335 if (!vcRedistDirName.endsWith(slash))
1336 vcRedistDirName.append(slash);
1337 vcRedistDirName.append(QStringLiteral("redist/MSVC"));
1338 if (!QFileInfo(vcRedistDirName).isDir()) {
1339 std::wcerr << "Warning: Cannot find Visual Studio redist directory, "
1340 << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1341 return QString();
1342 }
1343 // Look in reverse order for folder containing the debug redist folder
1344 const QFileInfoList subDirs =
1345 QDir(vcRedistDirName)
1346 .entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
1347 for (const QFileInfo &f : subDirs) {
1348 QString path = f.absoluteFilePath();
1349 if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
1350 return path;
1351 path += QStringLiteral("/onecore");
1352 if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
1353 return path;
1354 }
1355 std::wcerr << "Warning: Cannot find Visual Studio redist directory under "
1356 << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1357 return QString();
1358}
1359
1360static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
1361{
1362 //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found.
1363 QStringList result;
1364 const bool isClang = platform == WindowsDesktopClangMinGW;
1365 QStringList filters;
1366 const QString suffix = u'*' + sharedLibrarySuffix();
1367 for (const auto &minGWRuntime : runtimeFilters)
1368 filters.append(minGWRuntime + suffix);
1369
1370 QFileInfoList dlls = QDir(qtBinDir).entryInfoList(filters, QDir::Files);
1371 if (dlls.isEmpty()) {
1372 std::wcerr << "Warning: Runtime libraries not found in Qt binary folder, defaulting to looking in path\n";
1373 const QString binaryPath = isClang ? findInPath("clang++.exe"_L1) : findInPath("g++.exe"_L1);
1374 if (binaryPath.isEmpty()) {
1375 std::wcerr << "Warning: Cannot find " << (isClang ? "Clang" : "GCC") << " installation directory, " << (isClang ? "clang++" : "g++") << ".exe must be in the path\n";
1376 return {};
1377 }
1378 const QString binaryFolder = QFileInfo(binaryPath).absolutePath();
1379 dlls = QDir(binaryFolder).entryInfoList(filters, QDir::Files);
1380 }
1381
1382 for (const QFileInfo &dllFi : dlls)
1383 result.append(dllFi.absoluteFilePath());
1384
1385 return result;
1386}
1387
1388static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
1389{
1390 QStringList result;
1391 switch (platform) {
1392 case WindowsDesktopMinGW: {
1393 const QStringList minGWRuntimes = { "*gcc_"_L1, "*stdc++"_L1, "*winpthread"_L1 };
1394 result.append(findMinGWRuntimePaths(qtBinDir, platform, minGWRuntimes));
1395 break;
1396 }
1398 const QStringList clangMinGWRuntimes = { "*unwind"_L1, "*c++"_L1 };
1399 result.append(findMinGWRuntimePaths(qtBinDir, platform, clangMinGWRuntimes));
1400 break;
1401 }
1402#ifdef Q_OS_WIN
1403 case WindowsDesktopMsvcIntel:
1404 case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages.
1405 QString vcRedistDirName = vcRedistDir();
1406 if (vcRedistDirName.isEmpty())
1407 break;
1408 QStringList redistFiles;
1409 QDir vcRedistDir(vcRedistDirName);
1410 const QString machineArchString = getArchString(machineArch);
1411 if (isDebug) {
1412 // Append DLLs from Debug_NonRedist\x??\Microsoft.VC<version>.DebugCRT.
1413 if (vcRedistDir.cd(vcDebugRedistDir()) && vcRedistDir.cd(machineArchString)) {
1414 const QStringList names = vcRedistDir.entryList(QStringList(QStringLiteral("Microsoft.VC*.DebugCRT")), QDir::Dirs);
1415 if (!names.isEmpty() && vcRedistDir.cd(names.first())) {
1416 const QFileInfoList &dlls = vcRedistDir.entryInfoList(QStringList("*.dll"_L1));
1417 for (const QFileInfo &dll : dlls)
1418 redistFiles.append(dll.absoluteFilePath());
1419 }
1420 }
1421 } else { // release: Bundle vcredist<>.exe
1422 QString releaseRedistDir = vcRedistDirName;
1423 const QStringList countryCodes = vcRedistDir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Dirs);
1424 if (!countryCodes.isEmpty()) // Pre MSVC2017
1425 releaseRedistDir += u'/' + countryCodes.constFirst();
1426 QFileInfo fi(releaseRedistDir + "/vc_redist."_L1
1427 + machineArchString + ".exe"_L1);
1428 if (!fi.isFile()) { // Pre MSVC2017/15.5
1429 fi.setFile(releaseRedistDir + "/vcredist_"_L1
1430 + machineArchString + ".exe"_L1);
1431 }
1432 if (fi.isFile())
1433 redistFiles.append(fi.absoluteFilePath());
1434 }
1435 if (redistFiles.isEmpty()) {
1436 std::wcerr << "Warning: Cannot find Visual Studio " << (isDebug ? "debug" : "release")
1437 << " redistributable files in " << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1438 break;
1439 }
1440 result.append(redistFiles);
1441 }
1442 break;
1443#endif // Q_OS_WIN
1444 default:
1445 break;
1446 }
1447 return result;
1448}
1449
1450static inline int qtVersion(const QMap<QString, QString> &qtpathsVariables)
1451{
1452 const QString versionString = qtpathsVariables.value(QStringLiteral("QT_VERSION"));
1453 const QChar dot = u'.';
1454 const int majorVersion = versionString.section(dot, 0, 0).toInt();
1455 const int minorVersion = versionString.section(dot, 1, 1).toInt();
1456 const int patchVersion = versionString.section(dot, 2, 2).toInt();
1457 return (majorVersion << 16) | (minorVersion << 8) | patchVersion;
1458}
1459
1460// Deploy a library along with its .pdb debug info file (MSVC) should it exist.
1461static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory,
1462 const Options &options, QString *errorMessage)
1463{
1464 if (!updateFile(sourceFileName, targetDirectory, options.updateFileFlags, options.json, errorMessage)) {
1465 if (options.ignoreLibraryErrors) {
1466 std::wcerr << "Warning: Could not update " << sourceFileName << " :" << *errorMessage << '\n';
1467 errorMessage->clear();
1468 return true;
1469 }
1470 return false;
1471 }
1472
1473 if (options.deployPdb) {
1474 const QFileInfo pdb(pdbFileName(sourceFileName));
1475 if (pdb.isFile())
1476 return updateFile(pdb.absoluteFilePath(), targetDirectory, options.updateFileFlags, nullptr, errorMessage);
1477 }
1478 return true;
1479}
1480
1481// Find out the ICU version to add the data library icudtXX.dll, which does not
1482// show as a dependency.
1483static QString getIcuVersion(const QString &libName)
1484{
1485 QString version;
1486 std::copy_if(libName.cbegin(), libName.cend(), std::back_inserter(version),
1487 [](QChar c) { return c.isDigit(); });
1488 return version;
1489}
1490
1491static DeployResult deploy(const Options &options, const QMap<QString, QString> &qtpathsVariables,
1492 const PluginInformation &pluginInfo, QString *errorMessage)
1493{
1494 DeployResult result;
1495
1496 const QChar slash = u'/';
1497
1498 const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
1499 const QString libraryLocation = qtBinDir;
1500 const QString infix = qtpathsVariables.value(QLatin1StringView(qmakeInfixKey));
1501 const int version = qtVersion(qtpathsVariables);
1502 Q_UNUSED(version);
1503
1504 if (optVerboseLevel > 1)
1505 std::wcout << "Qt binaries in " << QDir::toNativeSeparators(qtBinDir) << '\n';
1506
1507 QStringList dependentQtLibs;
1508 QStringList dependentNonQtLibs;
1509 PeHeaderInfoStruct peHeaderInfo;
1510
1511 if (!readPeExecutableInfo(options.binaries.first(), errorMessage, &peHeaderInfo))
1512 return result;
1513 if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform,
1514 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1515 return result;
1516 }
1517 for (int b = 1; b < options.binaries.size(); ++b) {
1518 if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform,
1519 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1520 return result;
1521 }
1522 }
1523
1524 const QFileInfo fi(options.binaries.first());
1525 const QString canonicalBinPath = fi.canonicalPath();
1526 // Also check Qt dependencies of "local non Qt dependencies" (dlls located in the same folder)
1527 // Index based loop as container might be changed which invalidates iterators
1528 for (qsizetype i = 0; i < dependentNonQtLibs.size(); ++i) {
1529 const QString nonQtLib = dependentNonQtLibs.at(i);
1530 const QString path = canonicalBinPath + u'/' + nonQtLib;
1531 if (!QFileInfo::exists(path))
1532 continue;
1533
1534 if (optVerboseLevel)
1535 std::wcout << "Adding local dependency" << path << '\n';
1536
1537 if (!findDependentQtLibraries(libraryLocation, path, options.platform,
1538 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1539 return result;
1540 }
1541 }
1542
1543 DebugMatchMode debugMatchMode = MatchDebugOrRelease;
1544 result.isDebug = false;
1545 switch (options.debugDetection) {
1547 // Debug detection is only relevant for Msvc/ClangMsvc which have distinct
1548 // runtimes and binaries. For anything else, use MatchDebugOrRelease
1549 // since also debug cannot be reliably detect for MinGW.
1550 if (options.platform.testFlag(Msvc) || options.platform.testFlag(ClangMsvc)) {
1551 result.isDebug = peHeaderInfo.isDebug;
1552 debugMatchMode = result.isDebug ? MatchDebug : MatchRelease;
1553 }
1554 break;
1556 result.isDebug = true;
1557 debugMatchMode = MatchDebug;
1558 break;
1560 debugMatchMode = MatchRelease;
1561 break;
1562 }
1563
1564 // Determine application type, check Quick2 is used by looking at the
1565 // direct dependencies (do not be fooled by QtWebKit depending on it).
1566 for (int m = 0; m < dependentQtLibs.size(); ++m) {
1567 const qint64 module = qtModule(dependentQtLibs.at(m), infix);
1568 if (module >= 0)
1569 result.directlyUsedQtLibraries[module] = 1;
1570 }
1571
1572 const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
1573 const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModuleId);
1574 const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModuleId);
1575 const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModuleId))
1576 && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModuleId)));
1577
1578 if (optVerboseLevel) {
1579 std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' '
1580 << peHeaderInfo.wordSize << " bit, " << (result.isDebug ? "debug" : "release")
1581 << " executable";
1582 if (usesQml2)
1583 std::wcout << " [QML]";
1584 std::wcout << '\n';
1585 }
1586
1587 if (dependentQtLibs.isEmpty()) {
1588 *errorMessage = QDir::toNativeSeparators(options.binaries.first()) + QStringLiteral(" does not seem to be a Qt executable.");
1589 return result;
1590 }
1591
1592 // Scan Quick2 imports
1593 QmlImportScanResult qmlScanResult;
1594 if (options.quickImports && usesQml2) {
1595 // Custom list of import paths provided by user
1596 QStringList qmlImportPaths = options.qmlImportPaths;
1597 // Qt's own QML modules
1598 qmlImportPaths << qtpathsVariables.value(QStringLiteral("QT_INSTALL_QML"));
1599 QStringList qmlDirectories = options.qmlDirectories;
1600 if (qmlDirectories.isEmpty()) {
1601 const QString qmlDirectory = findQmlDirectory(options.platform, options.directory);
1602 if (!qmlDirectory.isEmpty())
1603 qmlDirectories.append(qmlDirectory);
1604 }
1605 for (const QString &qmlDirectory : std::as_const(qmlDirectories)) {
1606 if (optVerboseLevel >= 1)
1607 std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
1608 const QmlImportScanResult scanResult =
1609 runQmlImportScanner(qmlDirectory, qmlImportPaths,
1610 result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
1611 options.platform, debugMatchMode, errorMessage,
1612 options.qmlImportTimeout);
1613 if (!scanResult.ok)
1614 return result;
1615 qmlScanResult.append(scanResult);
1616 // Additional dependencies of QML plugins.
1617 for (const QString &plugin : std::as_const(qmlScanResult.plugins)) {
1618 if (!findDependentQtLibraries(libraryLocation, plugin, options.platform,
1619 errorMessage, &dependentQtLibs, nullptr)) {
1620 return result;
1621 }
1622 }
1623 if (optVerboseLevel >= 1) {
1624 std::wcout << "QML imports:\n";
1625 for (const QmlImportScanResult::Module &mod : std::as_const(qmlScanResult.modules)) {
1626 std::wcout << " '" << mod.name << "' "
1627 << QDir::toNativeSeparators(mod.sourcePath) << '\n';
1628 }
1629 if (optVerboseLevel >= 2) {
1630 std::wcout << "QML plugins:\n";
1631 for (const QString &p : std::as_const(qmlScanResult.plugins))
1632 std::wcout << " " << QDir::toNativeSeparators(p) << '\n';
1633 }
1634 }
1635 }
1636 }
1637
1638 QString platformPlugin;
1639 // Sort apart Qt 5 libraries in the ones that are represented by the
1640 // QtModule enumeration (and thus controlled by flags) and others.
1641 QStringList deployedQtLibraries;
1642 for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
1643 const qint64 module = qtModule(dependentQtLibs.at(i), infix);
1644 if (module >= 0)
1645 result.usedQtLibraries[module] = 1;
1646 else
1647 deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
1648 }
1649 result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
1650
1651 ModuleBitset disabled = options.disabledLibraries;
1652 if (!usesQml2) {
1653 disabled[QtQmlModuleId] = 1;
1654 disabled[QtQuickModuleId] = 1;
1655 }
1656
1657 // Some Windows-specific checks: Qt5Core depends on ICU when configured with "-icu". Other than
1658 // that, Qt5WebKit has a hard dependency on ICU.
1659 if (options.platform.testFlag(WindowsBased)) {
1660 const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral("Qt6Core"), Qt::CaseInsensitive)
1661 + dependentQtLibs.filter(QStringLiteral("Qt5WebKit"), Qt::CaseInsensitive);
1662 for (const QString &qtLib : qtLibs) {
1663 QStringList icuLibs = findDependentLibraries(qtLib, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive);
1664 if (!icuLibs.isEmpty()) {
1665 // Find out the ICU version to add the data library icudtXX.dll, which does not show
1666 // as a dependency.
1667 const QString icuVersion = getIcuVersion(icuLibs.constFirst());
1668 if (!icuVersion.isEmpty()) {
1669 if (optVerboseLevel > 1)
1670 std::wcout << "Adding ICU version " << icuVersion << '\n';
1671 QString icuLib = QStringLiteral("icudt") + icuVersion
1672 + QLatin1StringView(windowsSharedLibrarySuffix);
1673 // Some packages contain debug dlls of ICU libraries even though it's a C
1674 // library and the official packages do not differentiate (QTBUG-87677)
1675 if (result.isDebug) {
1676 const QString icuLibCandidate = QStringLiteral("icudtd") + icuVersion
1677 + QLatin1StringView(windowsSharedLibrarySuffix);
1678 if (!findInPath(icuLibCandidate).isEmpty()) {
1679 icuLib = icuLibCandidate;
1680 }
1681 }
1682 icuLibs.push_back(icuLib);
1683 }
1684 for (const QString &icuLib : std::as_const(icuLibs)) {
1685 const QString icuPath = findInPath(icuLib);
1686 if (icuPath.isEmpty()) {
1687 *errorMessage = QStringLiteral("Unable to locate ICU library ") + icuLib;
1688 return result;
1689 }
1690 deployedQtLibraries.push_back(icuPath);
1691 } // for each icuLib
1692 break;
1693 } // !icuLibs.isEmpty()
1694 } // Qt6Core/Qt6WebKit
1695 } // Windows
1696
1697 QStringList openSslLibs;
1698 if (!options.openSslRootDirectory.isEmpty()) {
1699 openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
1700 if (openSslLibs.isEmpty()) {
1701 *errorMessage = QStringLiteral("Unable to find openSSL libraries in ")
1702 + options.openSslRootDirectory;
1703 return result;
1704 }
1705
1706 deployedQtLibraries.append(openSslLibs);
1707 }
1708 const bool deployOpenSslPlugin = options.forceOpenSslPlugin || !openSslLibs.isEmpty();
1709
1710 const QStringList plugins = findQtPlugins(
1711 &result.deployedQtLibraries,
1712 // For non-QML applications, disable QML to prevent it from being pulled in by the
1713 // qtaccessiblequick plugin.
1714 disabled, pluginInfo,
1715 options.pluginSelections, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
1716 libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
1717 options.deployInsightTrackerPlugin, deployOpenSslPlugin);
1718
1719 // Apply options flags and re-add library names.
1720 QString qtGuiLibrary;
1721 for (const auto &qtModule : qtModuleEntries) {
1722 if (result.deployedQtLibraries.test(qtModule.id)) {
1723 const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
1724 options.platform, result.isDebug);
1725 deployedQtLibraries.append(library);
1726 if (qtModule.id == QtGuiModuleId)
1727 qtGuiLibrary = library;
1728 }
1729 }
1730
1731 if (optVerboseLevel >= 1) {
1732 std::wcout << "Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData()
1733 << "\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData()
1734 << "\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() << '\n';
1735 }
1736
1737 if (optVerboseLevel > 1)
1738 std::wcout << "Plugins: " << plugins.join(u',') << '\n';
1739
1740 if (result.deployedQtLibraries.test(QtGuiModuleId) && platformPlugin.isEmpty()) {
1741 *errorMessage =QStringLiteral("Unable to find the platform plugin.");
1742 return result;
1743 }
1744
1745 if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) {
1746 const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
1747 const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty();
1748 if (options.softwareRasterizer && !dependsOnOpenGl) {
1749 const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1StringView(windowsSharedLibrarySuffix));
1750 if (softwareRasterizer.isFile())
1751 deployedQtLibraries.append(softwareRasterizer.absoluteFilePath());
1752 }
1753 if (options.systemD3dCompiler && peHeaderInfo.machineArch != IMAGE_FILE_MACHINE_ARM64) {
1754 const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir,
1755 peHeaderInfo.wordSize);
1756 if (d3dCompiler.isEmpty()) {
1757 std::wcerr << "Warning: Cannot find any version of the d3dcompiler DLL.\n";
1758 } else {
1759 deployedQtLibraries.push_back(d3dCompiler);
1760 }
1761 }
1762 if (options.systemDxc) {
1763 const QStringList dxcLibs = findDxc(options.platform, qtBinDir,
1764 peHeaderInfo.wordSize);
1765 if (!dxcLibs.isEmpty())
1766 deployedQtLibraries.append(dxcLibs);
1767 else
1768 std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
1769 }
1770 } // Windows
1771
1772 // Add FFmpeg if we deploy the FFmpeg backend
1773 if (options.ffmpeg
1774 && !plugins.filter(QStringLiteral("ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
1775 deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
1776 }
1777
1778 // Update libraries
1779 if (options.libraries) {
1780 const QString targetPath = options.libraryDirectory.isEmpty() ?
1781 options.directory : options.libraryDirectory;
1782 QStringList libraries = deployedQtLibraries;
1783 if (options.compilerRunTime) {
1784 libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug,
1785 peHeaderInfo.machineArch));
1786 }
1787 for (const QString &qtLib : std::as_const(libraries)) {
1788 if (!updateLibrary(qtLib, targetPath, options, errorMessage))
1789 return result;
1790 }
1791
1792#if !QT_CONFIG(relocatable)
1793 if (options.patchQt && !options.dryRun) {
1794 const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", infix,
1795 options.platform, result.isDebug)).fileName();
1796 if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
1797 std::wcerr << "Warning: " << *errorMessage << '\n';
1798 errorMessage->clear();
1799 }
1800 }
1801#endif // QT_CONFIG(relocatable)
1802 } // optLibraries
1803
1804 // Update plugins
1805 if (options.plugins) {
1806 const QString targetPath = options.pluginDirectory.isEmpty() ?
1807 options.directory : options.pluginDirectory;
1808 QDir dir(targetPath);
1809 if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
1810 *errorMessage = "Cannot create "_L1 +
1811 QDir::toNativeSeparators(dir.absolutePath()) + u'.';
1812 return result;
1813 }
1814 for (const QString &plugin : plugins) {
1815 const QString targetDirName = plugin.section(slash, -2, -2);
1816 const QString targetPath = dir.absoluteFilePath(targetDirName);
1817 if (!dir.exists(targetDirName)) {
1818 if (optVerboseLevel)
1819 std::wcout << "Creating directory " << targetPath << ".\n";
1820 if (!(options.updateFileFlags & SkipUpdateFile) && !dir.mkdir(targetDirName)) {
1821 *errorMessage = QStringLiteral("Cannot create ") + targetDirName + u'.';
1822 return result;
1823 }
1824 }
1825 if (!updateLibrary(plugin, targetPath, options, errorMessage))
1826 return result;
1827 }
1828 } // optPlugins
1829
1830 // Update Quick imports
1831 // Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
1832 // for WebKit1-applications. Check direct dependency only.
1833 if (options.quickImports && usesQml2) {
1834 const QString targetPath = options.qmlDirectory.isEmpty()
1835 ? options.directory + QStringLiteral("/qml")
1836 : options.qmlDirectory;
1837 if (!createDirectory(targetPath, errorMessage, options.dryRun))
1838 return result;
1839 for (const QmlImportScanResult::Module &module : std::as_const(qmlScanResult.modules)) {
1840 const QString installPath = module.installPath(targetPath);
1841 if (optVerboseLevel > 1)
1842 std::wcout << "Installing: '" << module.name
1843 << "' from " << module.sourcePath << " to "
1844 << QDir::toNativeSeparators(installPath) << '\n';
1845 if (installPath != targetPath && !createDirectory(installPath, errorMessage, options.dryRun))
1846 return result;
1847 unsigned updateFileFlags = options.updateFileFlags
1848 | SkipQmlDesignerSpecificsDirectories;
1849 unsigned qmlDirectoryFileFlags = 0;
1850 if (options.deployPdb)
1851 qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
1852 if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
1853 options.platform,
1854 debugMatchMode,
1855 qmlDirectoryFileFlags),
1856 installPath, updateFileFlags, options.json, errorMessage)) {
1857 return result;
1858 }
1859 }
1860 } // optQuickImports
1861
1862 if (options.translations) {
1863 if (!createDirectory(options.translationsDirectory, errorMessage, options.dryRun))
1864 return result;
1865 if (!deployTranslations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS")),
1866 result.deployedQtLibraries, options.translationsDirectory, options,
1867 errorMessage)) {
1868 return result;
1869 }
1870 }
1871
1872 result.success = true;
1873 return result;
1874}
1875
1876static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, const char *binaryName,
1877 const PluginInformation &pluginInfo, const Options &sourceOptions,
1878 QString *errorMessage)
1879{
1880 // Copy the web process and its dependencies
1881 const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform);
1882 const QString webProcessSource = qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBEXECS"))
1883 + u'/' + webProcess;
1884 const QString webProcessTargetDir = sourceOptions.platform & WindowsBased
1885 && !sourceOptions.libraryDirectory.isEmpty() ?
1886 sourceOptions.libraryDirectory :
1887 sourceOptions.directory;
1888 if (!updateFile(webProcessSource, webProcessTargetDir, sourceOptions.updateFileFlags, sourceOptions.json, errorMessage))
1889 return false;
1890 Options options(sourceOptions);
1891 options.binaries.append(webProcessTargetDir + u'/' + webProcess);
1892 options.quickImports = false;
1893 options.translations = false;
1894 return deploy(options, qtpathsVariables, pluginInfo, errorMessage);
1895}
1896
1897static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
1898 const PluginInformation &pluginInfo, const Options &options,
1899 bool isDebug, QString *errorMessage)
1900{
1901 static const char *installDataFilesRelease[] = {
1902 "icudtl.dat", "qtwebengine_devtools_resources.pak", "qtwebengine_resources.pak",
1903 "qtwebengine_resources_100p.pak", "qtwebengine_resources_200p.pak"
1904 };
1905 static const char *installDataFilesDebug[] = {
1906 "icudtl.dat", "qtwebengine_devtools_resources.debug.pak", "qtwebengine_resources.debug.pak",
1907 "qtwebengine_resources_100p.debug.pak", "qtwebengine_resources_200p.debug.pak"
1908 };
1909 static const auto &installDataFiles = isDebug ? installDataFilesDebug : installDataFilesRelease;
1910 static const auto installV8SnapshotFile =
1911 isDebug ? "v8_context_snapshot.debug.bin" : "v8_context_snapshot.bin";
1912
1913 QByteArray webEngineProcessName(webEngineProcessC);
1914 if (isDebug && platformHasDebugSuffix(options.platform))
1915 webEngineProcessName.append('d');
1916 if (optVerboseLevel)
1917 std::wcout << "Deploying: " << webEngineProcessName.constData() << "...\n";
1918 if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
1919 return false;
1920 const QString resourcesSubDir = QStringLiteral("/resources");
1921 const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_DATA"))
1922 + resourcesSubDir + u'/';
1923 const QString resourcesTargetDir(options.directory + resourcesSubDir);
1924 if (!createDirectory(resourcesTargetDir, errorMessage, options.dryRun))
1925 return false;
1926 for (auto installDataFile : installDataFiles) {
1927 if (!updateFile(resourcesSourceDir + QLatin1StringView(installDataFile),
1928 resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) {
1929 return false;
1930 }
1931 }
1932 // snapshot file is optional feature in qtwebengine, so it might be missing
1933 updateFile(resourcesSourceDir + QLatin1StringView(installV8SnapshotFile), resourcesTargetDir,
1934 options.updateFileFlags, options.json, errorMessage);
1935 errorMessage->clear();
1936 const QFileInfo translations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS"))
1937 + QStringLiteral("/qtwebengine_locales"));
1938 if (!translations.isDir()) {
1939 std::wcerr << "Warning: Cannot find the translation files of the QtWebEngine module at "
1940 << QDir::toNativeSeparators(translations.absoluteFilePath()) << ".\n";
1941 return true;
1942 }
1943 if (options.translations) {
1944 // Copy the whole translations directory.
1945 return createDirectory(options.translationsDirectory, errorMessage, options.dryRun)
1946 && updateFile(translations.absoluteFilePath(), options.translationsDirectory,
1947 options.updateFileFlags, options.json, errorMessage);
1948 }
1949 // Translations have been turned off, but QtWebEngine needs at least one.
1950 const QFileInfo enUSpak(translations.filePath() + QStringLiteral("/en-US.pak"));
1951 if (!enUSpak.exists()) {
1952 std::wcerr << "Warning: Cannot find "
1953 << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) << ".\n";
1954 return true;
1955 }
1956 const QString webEngineTranslationsDir = options.translationsDirectory + u'/'
1957 + translations.fileName();
1958 if (!createDirectory(webEngineTranslationsDir, errorMessage, options.dryRun))
1959 return false;
1960 return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir,
1961 options.updateFileFlags, options.json, errorMessage);
1962}
1963
1964QT_END_NAMESPACE
1965
1966QT_USE_NAMESPACE
1967
1968int main(int argc, char **argv)
1969{
1970 QCoreApplication a(argc, argv);
1971 QCoreApplication::setApplicationVersion(QT_VERSION_STR ""_L1);
1972
1973 const QByteArray qtBinPath = QFile::encodeName(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
1974 QByteArray path = qgetenv("PATH");
1975 if (!path.contains(qtBinPath)) { // QTBUG-39177, ensure Qt is in the path so that qt.conf is taken into account.
1976 path.prepend(QDir::listSeparator().toLatin1());
1977 path.prepend(qtBinPath);
1978 qputenv("PATH", path);
1979 }
1980
1981 Options options;
1982 QString errorMessage;
1983
1984 // Early parse the --qmake and --qtpaths options, because they are needed to determine the
1985 // options that select/deselect Qt modules.
1986 {
1987 int result = parseEarlyArguments(QCoreApplication::arguments(), &options, &errorMessage);
1988 if (result & CommandLineParseError) {
1989 std::wcerr << "Error: " << errorMessage << "\n";
1990 return 1;
1991 }
1992 }
1993
1994 const QMap<QString, QString> qtpathsVariables =
1995 queryQtPaths(options.qtpathsBinary, &errorMessage);
1996 const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
1997 if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
1998 || !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
1999 std::wcerr << "Unable to query qtpaths: " << errorMessage << '\n';
2000 return 1;
2001 }
2002
2003 options.platform = platformFromMkSpec(xSpec);
2004 // We are on MSVC and not crosscompiling. We need the host arch
2005 if (options.platform == WindowsDesktopMsvc) {
2006 SYSTEM_INFO si;
2007 GetSystemInfo(&si);
2008 switch (si.wProcessorArchitecture) {
2009 case PROCESSOR_ARCHITECTURE_INTEL:
2010 case PROCESSOR_ARCHITECTURE_IA64:
2011 case PROCESSOR_ARCHITECTURE_AMD64:
2012 options.platform |= IntelBased;
2013 break;
2014 case PROCESSOR_ARCHITECTURE_ARM:
2015 case PROCESSOR_ARCHITECTURE_ARM64:
2016 options.platform |= ArmBased;
2017 break;
2018 default:
2019 options.platform = UnknownPlatform;
2020 }
2021 }
2022 if (options.platform == UnknownPlatform) {
2023 std::wcerr << "Unsupported platform " << xSpec << '\n';
2024 return 1;
2025 }
2026
2027 // Read the Qt module information from the Qt installation directory.
2028 const QString modulesDir
2029 = qtpathsVariables.value(QLatin1String("QT_INSTALL_ARCHDATA"))
2030 + QLatin1String("/modules");
2031 const QString translationsDir
2032 = qtpathsVariables.value(QLatin1String("QT_INSTALL_TRANSLATIONS"));
2033 if (!qtModuleEntries.populate(modulesDir, translationsDir, optVerboseLevel > 1,
2034 &errorMessage)) {
2035 std::wcerr << "Error: " << errorMessage << "\n";
2036 return 1;
2037 }
2039
2040 // Read the Qt plugin types information from the Qt installation directory.
2041 PluginInformation pluginInfo{};
2042 pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
2043
2044 // Parse the full command line.
2045 {
2046 QCommandLineParser parser;
2047 QString errorMessage;
2048 const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
2049 if (result & CommandLineParseError)
2050 std::wcerr << errorMessage << "\n\n";
2051 if (result & CommandLineVersionRequested) {
2052 std::fputs(QT_VERSION_STR "\n", stdout);
2053 return 0;
2054 }
2055 if (result & CommandLineParseHelpRequested)
2056 std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
2057 if (result & CommandLineParseError)
2058 return 1;
2059 if (result & CommandLineParseHelpRequested)
2060 return 0;
2061 }
2062
2063 // Create directories
2064 if (!createDirectory(options.directory, &errorMessage, options.dryRun)) {
2065 std::wcerr << errorMessage << '\n';
2066 return 1;
2067 }
2068 if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory
2069 && !createDirectory(options.libraryDirectory, &errorMessage, options.dryRun)) {
2070 std::wcerr << errorMessage << '\n';
2071 return 1;
2072 }
2073
2074 const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
2075 if (!result) {
2076 std::wcerr << errorMessage << '\n';
2077 return 1;
2078 }
2079
2080 if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
2081 if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
2082 &errorMessage)) {
2083 std::wcerr << errorMessage << '\n';
2084 return 1;
2085 }
2086 }
2087
2088 if (options.createAppx && !options.appxCertificatePath.isEmpty()) {
2089 const QFileInfo storeLogo(options.directory + QStringLiteral("/Assets/StoreLogo.png"));
2090 if (!storeLogo.exists()) {
2091 std::wcerr << "Error: Could not open application logo file " << storeLogo.absoluteFilePath() << '\n';
2092 return 1;
2093 }
2094
2095 QFile certFile(options.appxCertificatePath);
2096 if (!certFile.open(QIODevice::ReadOnly)) {
2097 std::wcerr << "Could not open certificate file" << '\n';
2098 return 1;
2099 }
2100
2101 QSslCertificate cert(&certFile, QSsl::Der);
2102 QString publisher = cert.subjectDisplayName();
2103
2104 const QString applicationName = QFileInfo(options.binaries.first()).baseName();
2105 const QString platform = options.platform.testFlag(PlatformFlag::IntelBased) ? QStringLiteral("x64") : QStringLiteral("arm64");
2106 const QString appxFilePath(options.directory + QStringLiteral("/") + QStringLiteral("AppxManifest.xml"));
2107 QFile f(appxFilePath);
2108 if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
2109 std::wcerr << "Could not create AppxManifest.xml" << '\n';
2110 return 1;
2111 }
2112
2113 QXmlStreamWriter manifestWriter(&f);
2114 manifestWriter.setAutoFormatting(true);
2115 manifestWriter.writeStartDocument();
2116 manifestWriter.writeStartElement(QStringLiteral("Package"));
2117 manifestWriter.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.microsoft.com/appx/manifest/foundation/windows10"));
2118 manifestWriter.writeAttribute(QStringLiteral("xmlns:uap"), QStringLiteral("http://schemas.microsoft.com/appx/manifest/uap/windows10"));
2119 manifestWriter.writeAttribute(QStringLiteral("xmlns:rescap"), QStringLiteral("http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"));
2120
2121 manifestWriter.writeStartElement(QStringLiteral("Identity"));
2122 manifestWriter.writeAttribute("Name", QUuid::createUuid().toString(QUuid::WithoutBraces));
2123 manifestWriter.writeAttribute("Publisher", QStringLiteral("CN=") + publisher);
2124 manifestWriter.writeAttribute("Version", "1.0.0.0");
2125 manifestWriter.writeAttribute("ProcessorArchitecture", platform);
2126 manifestWriter.writeEndElement();
2127
2128 manifestWriter.writeStartElement("Properties");
2129 manifestWriter.writeStartElement("DisplayName");
2130 manifestWriter.writeCharacters(applicationName);
2131 manifestWriter.writeEndElement();
2132 manifestWriter.writeStartElement("PublisherDisplayName");
2133 manifestWriter.writeCharacters(publisher);
2134 manifestWriter.writeEndElement();
2135 manifestWriter.writeStartElement("Logo");
2136 manifestWriter.writeCharacters("Assets/StoreLogo.png");
2137 manifestWriter.writeEndElement();
2138 manifestWriter.writeEndElement();
2139
2140 manifestWriter.writeStartElement("Dependencies");
2141 manifestWriter.writeStartElement("TargetDeviceFamily");
2142 manifestWriter.writeAttribute("Name", "Windows.Desktop");
2143 manifestWriter.writeAttribute("MinVersion", "10.0.14316.0");
2144 manifestWriter.writeAttribute("MaxVersionTested", "10.0.14316.0");
2145 manifestWriter.writeEndElement();
2146 manifestWriter.writeEndElement();
2147
2148 manifestWriter.writeStartElement("Capabilities");
2149 manifestWriter.writeStartElement("rescap:Capability");
2150 manifestWriter.writeAttribute("Name", "runFullTrust");
2151 manifestWriter.writeEndElement();
2152 manifestWriter.writeEndElement();
2153
2154 manifestWriter.writeStartElement("Resources");
2155 manifestWriter.writeStartElement("Resource");
2156 if (options.languages.isEmpty()) {
2157 QLocale locale = QLocale::system();
2158 manifestWriter.writeAttribute("Language", locale.bcp47Name());
2159 } else {
2160 for (const auto& language : options.languages) {
2161 manifestWriter.writeAttribute("Language", language);
2162 }
2163 }
2164 manifestWriter.writeEndElement();
2165 manifestWriter.writeEndElement();
2166
2167 manifestWriter.writeStartElement("Applications");
2168 for (const auto& binary : options.binaries) {
2169 const QString binaryRelative = binary.split(QStringLiteral("/")).last();
2170 const QString displayName = binaryRelative.split(QStringLiteral(".")).first();
2171 QFile descriptionFile(options.directory + QStringLiteral("/") + QStringLiteral("Assets/Description_") + displayName + QStringLiteral(".txt"));
2172 QString description;
2173 if (!descriptionFile.exists())
2174 std::wcerr << "Warning: No package description was provided " << descriptionFile.fileName() << '\n';
2175 if (descriptionFile.open(QIODevice::ReadOnly | QIODevice::Text))
2176 description = QString::fromUtf8(descriptionFile.readAll());
2177
2178 manifestWriter.writeStartElement("Application");
2179 manifestWriter.writeAttribute("Id", displayName);
2180 manifestWriter.writeAttribute("Executable", binaryRelative);
2181 manifestWriter.writeAttribute("EntryPoint", "Windows.FullTrustApplication");
2182 manifestWriter.writeStartElement("uap:VisualElements");
2183 manifestWriter.writeAttribute("DisplayName", displayName);
2184 manifestWriter.writeAttribute("Description", description);
2185 manifestWriter.writeAttribute("BackgroundColor", "transparent");
2186 manifestWriter.writeAttribute("Square150x150Logo", "Assets/Logo.png");
2187 manifestWriter.writeAttribute("Square44x44Logo", "Assets/SmallLogo.png");
2188 manifestWriter.writeStartElement("uap:DefaultTile");
2189 manifestWriter.writeEndElement();
2190 manifestWriter.writeEndElement();
2191 manifestWriter.writeEndElement();
2192 }
2193 manifestWriter.writeEndElement();
2194 manifestWriter.writeEndElement();
2195 manifestWriter.writeEndDocument();
2196 }
2197
2198 if (options.json) {
2199 if (options.list)
2200 std::fputs(options.json->toList(options.list, options.directory).constData(), stdout);
2201 else
2202 std::fputs(options.json->toJson().constData(), stdout);
2203 delete options.json;
2204 options.json = nullptr;
2205 }
2206
2207 return 0;
2208}
QStringList operator()(const QDir &dir) const
Definition main.cpp:884
DllDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, const QString &prefix=QString())
Definition main.cpp:880
QStringList operator()(const QDir &dir) const
Definition main.cpp:921
QmlDirectoryFileEntryFunction(const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
Definition main.cpp:915
static Platform platformFromMkSpec(const QString &xSpec)
Definition main.cpp:135
static bool isQtModule(const QString &libName)
Definition main.cpp:833
static QString libraryPath(const QString &libraryLocation, const char *name, const QString &infix, Platform platform, bool debug)
Definition main.cpp:1311
static QString lineBreak(QString s)
Definition main.cpp:786
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:1388
static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory, const Options &options, QString *errorMessage)
Definition main.cpp:1461
static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary, Platform platform, QString *errorMessage, QStringList *qtDependencies, QStringList *nonQtDependencies)
Definition main.cpp:843
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:1450
static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
Definition main.cpp:1174
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:1491
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:1897
static QStringList qmlCacheFileFilters()
Definition main.cpp:901
static QString pdbFileName(QString libraryFileName)
Definition main.cpp:893
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:1089
static qint64 qtModule(QString module, const QString &infix)
Definition main.cpp:973
static QString vcRedistDir()
Definition main.cpp:1325
static QString webProcessBinary(const char *binaryName, Platform p)
Definition main.cpp:87
static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
Definition main.cpp:1244
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:999
static QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
Definition main.cpp:798
static bool deployWebProcess(const QMap< QString, QString > &qtpathsVariables, const char *binaryName, const PluginInformation &pluginInfo, const Options &sourceOptions, QString *errorMessage)
Definition main.cpp:1876
static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
Definition main.cpp:1360
#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:1483
static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules, const QString &target, const Options &options, QString *errorMessage)
Definition main.cpp:1187
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:1100
static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
Definition main.cpp:1272
static QString vcDebugRedistDir()
Definition main.cpp:1323
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:1307
ModuleBitset directlyUsedQtLibraries
Definition main.cpp:1306
operator bool() const
Definition main.cpp:1302
bool isDebug
Definition main.cpp:1305
ModuleBitset deployedQtLibraries
Definition main.cpp:1308
bool success
Definition main.cpp:1304
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