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