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