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