Qt 6.x
The Qt SDK
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
8#include <QtCore/QCommandLineOption>
9#include <QtCore/QCommandLineParser>
10#include <QtCore/QDir>
11#include <QtCore/QFileInfo>
12#include <QtCore/QCoreApplication>
13#include <QtCore/QJsonDocument>
14#include <QtCore/QJsonObject>
15#include <QtCore/QJsonArray>
16#include <QtCore/QList>
17#include <QtCore/QOperatingSystemVersion>
18#include <QtCore/QSharedPointer>
19
20#ifdef Q_OS_WIN
21#include <QtCore/qt_windows.h>
22#else
23#define IMAGE_FILE_MACHINE_ARM64 0xaa64
24#endif
25
26#include <QtCore/private/qconfig_p.h>
27
28#include <algorithm>
29#include <cstdio>
30#include <iostream>
31#include <iterator>
32#include <unordered_map>
33
35
36using namespace Qt::StringLiterals;
37
39
40#define DECLARE_KNOWN_MODULE(name) \
41 static size_t Qt##name ## ModuleId = QtModule::InvalidId
42
46DECLARE_KNOWN_MODULE(DesignerComponents);
51DECLARE_KNOWN_MODULE(WebEngineCore);
53
54#define DEFINE_KNOWN_MODULE(name) \
55 m[QLatin1String("Qt6" #name)] = &Qt##name ## ModuleId
56
58{
59 std::unordered_map<QString, size_t *> m;
60 DEFINE_KNOWN_MODULE(3DQuick);
62 DEFINE_KNOWN_MODULE(Designer);
63 DEFINE_KNOWN_MODULE(DesignerComponents);
66 DEFINE_KNOWN_MODULE(QmlTooling);
68 DEFINE_KNOWN_MODULE(WebEngineCore);
69 DEFINE_KNOWN_MODULE(Widgets);
70 for (size_t i = 0; i < qtModuleEntries.size(); ++i) {
71 const QtModule &module = qtModuleEntries.moduleById(i);
72 auto it = m.find(module.name);
73 if (it == m.end())
74 continue;
75 *(it->second) = i;
76 }
77}
78
79#undef DECLARE_KNOWN_MODULE
80#undef DEFINE_KNOWN_MODULE
81
82static const char webEngineProcessC[] = "QtWebEngineProcess";
83
84static inline QString webProcessBinary(const char *binaryName, Platform p)
85{
86 const QString webProcess = QLatin1StringView(binaryName);
87 return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess;
88}
89
90static QString moduleNameToOptionName(const QString &moduleName)
91{
92 QString result = moduleName
93 .mid(3) // strip the "Qt6" prefix
94 .toLower();
95 if (result == u"help"_s)
96 result.prepend("qt"_L1);
97 return result;
98}
99
101{
103 for (const auto &qtModule : qtModuleEntries) {
104 if (mask.test(qtModule.id)) {
105 if (!result.isEmpty())
106 result.append(' ');
107 result.append(option
109 : qtModule.name.toUtf8());
110 }
111 }
112 return result;
113}
114
116{
117 if (xSpec == "linux-g++"_L1)
118 return Unix;
119 if (xSpec.startsWith("win32-"_L1)) {
120 if (xSpec.contains("clang-g++"_L1))
122 if (xSpec.contains("clang-msvc++"_L1))
124 return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvc;
125 }
126 return UnknownPlatform;
127}
128
129// Helpers for exclusive options, "-foo", "--no-foo"
135
137 const QCommandLineOption &enableOption,
138 const QCommandLineOption &disableOption)
139{
140 const bool enabled = parser->isSet(enableOption);
141 const bool disabled = parser->isSet(disableOption);
142 if (enabled) {
143 if (disabled) {
144 std::wcerr << "Warning: both -" << enableOption.names().first()
145 << " and -" << disableOption.names().first() << " were specified, defaulting to -"
146 << enableOption.names().first() << ".\n";
147 }
148 return OptionEnabled;
149 }
151}
152
153struct Options {
158 };
159
160 bool plugins = true;
161 bool libraries = true;
162 bool quickImports = true;
163 bool translations = true;
164 bool systemD3dCompiler = true;
165 bool systemDxc = true;
166 bool compilerRunTime = false;
172 unsigned updateFileFlags = 0;
173 QStringList qmlDirectories; // Project's QML files.
174 QStringList qmlImportPaths; // Custom QML module locations.
177 QString translationsDirectory; // Translations target directory
183 JsonOutput *json = nullptr;
186 bool deployPdb = false;
187 bool dryRun = false;
188 bool patchQt = true;
190};
191
192// Return binary to be deployed from folder, ignore pre-existing web engine process.
194{
195 const QStringList nameFilters = (platform & WindowsBased) ?
197 const QFileInfoList &binaries =
199 for (const QFileInfo &binaryFi : binaries) {
200 const QString binary = binaryFi.fileName();
202 return binaryFi.absoluteFilePath();
203 }
204 }
205 return QString();
206}
207
209{
210 return u'"' + QDir::toNativeSeparators(file) + "\" does not exist."_L1;
211}
212
217
219{
220 return {
221 u"qmake"_s,
222 u"Use specified qmake instead of qmake from PATH. Deprecated, use qtpaths instead."_s,
223 u"path"_s
224 };
225}
226
228{
229 return {
230 u"qtpaths"_s,
231 u"Use specified qtpaths.exe instead of qtpaths.exe from PATH."_s,
232 u"path"_s
233 };
234}
235
237{
238 return {
239 u"verbose"_s,
240 u"Verbose level (0-2)."_s,
241 u"level"_s
242 };
243}
244
247{
248 QCommandLineParser parser;
250
252 parser.addOption(qmakeOption);
253
254 QCommandLineOption qtpathsOption = createQtPathsOption();
255 parser.addOption(qtpathsOption);
256
257 QCommandLineOption verboseOption = createVerboseOption();
258 parser.addOption(verboseOption);
259
260 // Deliberately don't check for errors. We want to ignore options we don't know about.
261 parser.parse(arguments);
262
263 if (parser.isSet(qmakeOption) && parser.isSet(qtpathsOption)) {
264 *errorMessage = QStringLiteral("-qmake and -qtpaths are mutually exclusive.");
266 }
267
268 if (parser.isSet(qmakeOption) && optVerboseLevel >= 1)
269 std::wcerr << "Warning: -qmake option is deprecated. Use -qpaths instead.\n";
270
271 if (parser.isSet(qtpathsOption) || parser.isSet(qmakeOption)) {
272 const QString qtpathsArg = parser.isSet(qtpathsOption) ? parser.value(qtpathsOption)
273 : parser.value(qmakeOption);
274
275 const QString qtpathsBinary = QDir::cleanPath(qtpathsArg);
276 const QFileInfo fi(qtpathsBinary);
277 if (!fi.exists()) {
278 *errorMessage = msgFileDoesNotExist(qtpathsBinary);
280 }
281
282 if (!fi.isExecutable()) {
283 *errorMessage = u'"' + QDir::toNativeSeparators(qtpathsBinary)
284 + QStringLiteral("\" is not an executable.");
286 }
287 options->qtpathsBinary = qtpathsBinary;
288 }
289
290 if (parser.isSet(verboseOption)) {
291 bool ok;
292 const QString value = parser.value(verboseOption);
293 optVerboseLevel = value.toInt(&ok);
294 if (!ok || optVerboseLevel < 0) {
295 *errorMessage = QStringLiteral("Invalid value \"%1\" passed for verbose level.")
296 .arg(value);
298 }
299 }
300
301 return 0;
302}
303
304static inline int parseArguments(const QStringList &arguments, QCommandLineParser *parser,
305 Options *options, QString *errorMessage)
306{
307 using CommandLineOptionPtr = QSharedPointer<QCommandLineOption>;
308 using OptionPtrVector = QList<CommandLineOptionPtr>;
309
311 parser->setApplicationDescription(u"Qt Deploy Tool " QT_VERSION_STR
312 "\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n"
313 "installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n\n"
314 "If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>"_s);
315 const QCommandLineOption helpOption = parser->addHelpOption();
316 parser->addVersionOption();
317
318 QCommandLineOption dirOption(QStringLiteral("dir"),
319 QStringLiteral("Use directory instead of binary directory."),
320 QStringLiteral("directory"));
321 parser->addOption(dirOption);
322
323 // Add early options to have them available in the help text.
324 parser->addOption(createQMakeOption());
326
327 QCommandLineOption libDirOption(QStringLiteral("libdir"),
328 QStringLiteral("Copy libraries to path."),
329 QStringLiteral("path"));
330 parser->addOption(libDirOption);
331
332 QCommandLineOption pluginDirOption(QStringLiteral("plugindir"),
333 QStringLiteral("Copy plugins to path."),
334 QStringLiteral("path"));
335 parser->addOption(pluginDirOption);
336
337 const QCommandLineOption translationDirOption(
338 u"translationdir"_s,
339 u"Copy translations to path."_s,
340 u"path"_s);
341 parser->addOption(translationDirOption);
342
343 QCommandLineOption qmlDeployDirOption(QStringLiteral("qml-deploy-dir"),
344 QStringLiteral("Copy qml files to path."),
345 QStringLiteral("path"));
346 parser->addOption(qmlDeployDirOption);
347
348 QCommandLineOption debugOption(QStringLiteral("debug"),
349 QStringLiteral("Assume debug binaries."));
350 parser->addOption(debugOption);
351 QCommandLineOption releaseOption(QStringLiteral("release"),
352 QStringLiteral("Assume release binaries."));
353 parser->addOption(releaseOption);
354 QCommandLineOption releaseWithDebugInfoOption(QStringLiteral("release-with-debug-info"),
355 QStringLiteral("Assume release binaries with debug information."));
356 releaseWithDebugInfoOption.setFlags(QCommandLineOption::HiddenFromHelp); // Deprecated by improved debug detection.
357 parser->addOption(releaseWithDebugInfoOption);
358
359 QCommandLineOption deployPdbOption(QStringLiteral("pdb"),
360 QStringLiteral("Deploy .pdb files (MSVC)."));
361 parser->addOption(deployPdbOption);
362
363 QCommandLineOption forceOption(QStringLiteral("force"),
364 QStringLiteral("Force updating files."));
365 parser->addOption(forceOption);
366
367 QCommandLineOption dryRunOption(QStringLiteral("dry-run"),
368 QStringLiteral("Simulation mode. Behave normally, but do not copy/update any files."));
369 parser->addOption(dryRunOption);
370
371 QCommandLineOption noPatchQtOption(QStringLiteral("no-patchqt"),
372 QStringLiteral("Do not patch the Qt6Core library."));
373 parser->addOption(noPatchQtOption);
374
375 QCommandLineOption ignoreErrorOption(QStringLiteral("ignore-library-errors"),
376 QStringLiteral("Ignore errors when libraries cannot be found."));
377 parser->addOption(ignoreErrorOption);
378
379 QCommandLineOption noPluginsOption(QStringLiteral("no-plugins"),
380 QStringLiteral("Skip plugin deployment."));
381 parser->addOption(noPluginsOption);
382
383 QCommandLineOption skipPluginTypesOption(QStringLiteral("skip-plugin-types"),
384 QStringLiteral("A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
385 QStringLiteral("plugin types"));
386 parser->addOption(skipPluginTypesOption);
387
388 QCommandLineOption noLibraryOption(QStringLiteral("no-libraries"),
389 QStringLiteral("Skip library deployment."));
390 parser->addOption(noLibraryOption);
391
392 QCommandLineOption qmlDirOption(QStringLiteral("qmldir"),
393 QStringLiteral("Scan for QML-imports starting from directory."),
394 QStringLiteral("directory"));
395 parser->addOption(qmlDirOption);
396
397 QCommandLineOption qmlImportOption(QStringLiteral("qmlimport"),
398 QStringLiteral("Add the given path to the QML module search locations."),
399 QStringLiteral("directory"));
400 parser->addOption(qmlImportOption);
401
402 QCommandLineOption noQuickImportOption(QStringLiteral("no-quick-import"),
403 QStringLiteral("Skip deployment of Qt Quick imports."));
404 parser->addOption(noQuickImportOption);
405
406
407 QCommandLineOption translationOption(QStringLiteral("translations"),
408 QStringLiteral("A comma-separated list of languages to deploy (de,fi)."),
409 QStringLiteral("languages"));
410 parser->addOption(translationOption);
411
412 QCommandLineOption noTranslationOption(QStringLiteral("no-translations"),
413 QStringLiteral("Skip deployment of translations."));
414 parser->addOption(noTranslationOption);
415
416 QCommandLineOption noSystemD3DCompilerOption(QStringLiteral("no-system-d3d-compiler"),
417 QStringLiteral("Skip deployment of the system D3D compiler."));
418 parser->addOption(noSystemD3DCompilerOption);
419
420 QCommandLineOption noSystemDxcOption(QStringLiteral("no-system-dxc-compiler"),
421 QStringLiteral("Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
422 parser->addOption(noSystemDxcOption);
423
424
425 QCommandLineOption compilerRunTimeOption(QStringLiteral("compiler-runtime"),
426 QStringLiteral("Deploy compiler runtime (Desktop only)."));
427 parser->addOption(compilerRunTimeOption);
428
429 QCommandLineOption noCompilerRunTimeOption(QStringLiteral("no-compiler-runtime"),
430 QStringLiteral("Do not deploy compiler runtime (Desktop only)."));
431 parser->addOption(noCompilerRunTimeOption);
432
433 QCommandLineOption jsonOption(QStringLiteral("json"),
434 QStringLiteral("Print to stdout in JSON format."));
435 parser->addOption(jsonOption);
436
437 QCommandLineOption suppressSoftwareRasterizerOption(QStringLiteral("no-opengl-sw"),
438 QStringLiteral("Do not deploy the software rasterizer library."));
439 parser->addOption(suppressSoftwareRasterizerOption);
440
441 QCommandLineOption listOption(QStringLiteral("list"),
442 "Print only the names of the files copied.\n"
443 "Available options:\n"
444 " source: absolute path of the source files\n"
445 " target: absolute path of the target files\n"
446 " relative: paths of the target files, relative\n"
447 " to the target directory\n"
448 " mapping: outputs the source and the relative\n"
449 " target, suitable for use within an\n"
450 " Appx mapping file"_L1,
451 QStringLiteral("option"));
452 parser->addOption(listOption);
453
454 // Add early option to have it available in the help text.
456
457 parser->addPositionalArgument(QStringLiteral("[files]"),
458 QStringLiteral("Binaries or directory containing the binary."));
459
460 OptionPtrVector enabledModuleOptions;
461 OptionPtrVector disabledModuleOptions;
462 const size_t qtModulesCount = qtModuleEntries.size();
463 enabledModuleOptions.reserve(qtModulesCount);
464 disabledModuleOptions.reserve(qtModulesCount);
465 for (const QtModule &module : qtModuleEntries) {
466 const QString option = moduleNameToOptionName(module.name);
467 const QString name = module.name;
468 const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module.");
469 CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription));
470 parser->addOption(*enabledOption.data());
471 enabledModuleOptions.append(enabledOption);
472 const QString disabledDescription = QStringLiteral("Remove ") + name + QStringLiteral(" module.");
473 CommandLineOptionPtr disabledOption(new QCommandLineOption(QStringLiteral("no-") + option,
474 disabledDescription));
475 disabledModuleOptions.append(disabledOption);
476 parser->addOption(*disabledOption.data());
477 }
478
479 const bool success = parser->parse(arguments);
480 if (parser->isSet(helpOption))
482 if (!success) {
483 *errorMessage = parser->errorText();
485 }
486
487 options->libraryDirectory = parser->value(libDirOption);
488 options->pluginDirectory = parser->value(pluginDirOption);
489 options->translationsDirectory = parser->value(translationDirOption);
490 options->qmlDirectory = parser->value(qmlDeployDirOption);
491 options->plugins = !parser->isSet(noPluginsOption);
492 options->libraries = !parser->isSet(noLibraryOption);
493 options->translations = !parser->isSet(noTranslationOption);
494 if (parser->isSet(translationOption))
495 options->languages = parser->value(translationOption).split(u',');
496 options->systemD3dCompiler = !parser->isSet(noSystemD3DCompilerOption);
497 options->systemDxc = !parser->isSet(noSystemDxcOption);
498 options->quickImports = !parser->isSet(noQuickImportOption);
499
500 // default to deployment of compiler runtime for windows desktop configurations
501 if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc
502 || parser->isSet(compilerRunTimeOption))
503 options->compilerRunTime = true;
504 if (parser->isSet(noCompilerRunTimeOption))
505 options->compilerRunTime = false;
506
507 if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) {
508 *errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
510 }
511
512 if (parser->isSet(skipPluginTypesOption))
513 options->disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
514
515 if (parser->isSet(releaseWithDebugInfoOption))
516 std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete.";
517
518 switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
519 case OptionAuto:
520 break;
521 case OptionEnabled:
523 break;
524 case OptionDisabled:
526 break;
527 }
528
529 if (parser->isSet(deployPdbOption)) {
530 if (options->platform.testFlag(WindowsBased) && !options->platform.testFlag(MinGW))
531 options->deployPdb = true;
532 else
533 std::wcerr << "Warning: --" << deployPdbOption.names().first() << " is not supported on this platform.\n";
534 }
535
536 if (parser->isSet(suppressSoftwareRasterizerOption))
537 options->softwareRasterizer = false;
538
539 if (parser->isSet(forceOption))
541 if (parser->isSet(dryRunOption)) {
542 options->dryRun = true;
544 }
545
546 options->patchQt = !parser->isSet(noPatchQtOption);
547 options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
548
549 for (const QtModule &module : qtModuleEntries) {
550 if (parser->isSet(*enabledModuleOptions.at(module.id)))
551 options->additionalLibraries[module.id] = 1;
552 if (parser->isSet(*disabledModuleOptions.at(module.id)))
553 options->disabledLibraries[module.id] = 1;
554 }
555
556 // Add some dependencies
557 if (options->additionalLibraries.test(QtQuickModuleId))
558 options->additionalLibraries[QtQmlModuleId] = 1;
559 if (options->additionalLibraries.test(QtDesignerComponentsModuleId))
560 options->additionalLibraries[QtDesignerModuleId] = 1;
561
562 if (parser->isSet(listOption)) {
563 const QString value = parser->value(listOption);
564 if (value == QStringLiteral("source")) {
565 options->list = ListSource;
566 } else if (value == QStringLiteral("target")) {
567 options->list = ListTarget;
568 } else if (value == QStringLiteral("relative")) {
569 options->list = ListRelative;
570 } else if (value == QStringLiteral("mapping")) {
571 options->list = ListMapping;
572 } else {
573 *errorMessage = QStringLiteral("Please specify a valid option for -list (source, target, relative, mapping).");
575 }
576 }
577
578 if (parser->isSet(jsonOption) || options->list) {
579 optVerboseLevel = 0;
580 options->json = new JsonOutput;
581 }
582
583 const QStringList posArgs = parser->positionalArguments();
584 if (posArgs.isEmpty()) {
585 *errorMessage = QStringLiteral("Please specify the binary or folder.");
587 }
588
589 if (parser->isSet(dirOption))
590 options->directory = parser->value(dirOption);
591
592 if (parser->isSet(qmlDirOption))
593 options->qmlDirectories = parser->values(qmlDirOption);
594
595 if (parser->isSet(qmlImportOption))
596 options->qmlImportPaths = parser->values(qmlImportOption);
597
598 const QString &file = posArgs.front();
600 if (!fi.exists()) {
603 }
604
605 if (!options->directory.isEmpty() && !fi.isFile()) { // -dir was specified - expecting file.
606 *errorMessage = u'"' + file + QStringLiteral("\" is not an executable file.");
608 }
609
610 if (fi.isFile()) {
611 options->binaries.append(fi.absoluteFilePath());
612 if (options->directory.isEmpty())
613 options->directory = fi.absolutePath();
614 } else {
616 if (binary.isEmpty()) {
617 *errorMessage = QStringLiteral("Unable to find binary in \"") + file + u'"';
619 }
620 options->directory = fi.absoluteFilePath();
621 options->binaries.append(binary);
622 } // directory.
623
624 // Remaining files or plugin directories
625 bool multipleDirs = false;
626 for (int i = 1; i < posArgs.size(); ++i) {
627 const QFileInfo fi(QDir::cleanPath(posArgs.at(i)));
629 if (!fi.exists()) {
632 }
633 if (fi.isDir()) {
634 const QStringList libraries =
636 for (const QString &library : libraries)
637 options->binaries.append(path + u'/' + library);
638 } else {
639 if (fi.absolutePath() != options->directory)
640 multipleDirs = true;
641 options->binaries.append(path);
642 }
643 }
644 if (multipleDirs)
645 std::wcerr << "Warning: using binaries from different directories\n";
646 if (options->translationsDirectory.isEmpty())
647 options->translationsDirectory = options->directory + "/translations"_L1;
648 return 0;
649}
650
651// Simple line wrapping at 80 character boundaries.
653{
654 for (qsizetype i = 80; i < s.size(); i += 80) {
655 const qsizetype lastBlank = s.lastIndexOf(u' ', i);
656 if (lastBlank >= 0) {
657 s[lastBlank] = u'\n';
658 i = lastBlank + 1;
659 }
660 }
661 return s;
662}
663
665{
666 QString result = p.helpText();
667 // Replace the default-generated text which is too long by a short summary
668 // explaining how to enable single libraries.
669 if (qtModuleEntries.size() == 0)
670 return result;
671 const QtModule &firstModule = qtModuleEntries.moduleById(0);
672 const QString firstModuleOption = moduleNameToOptionName(firstModule.name);
673 const qsizetype moduleStart = result.indexOf("\n --"_L1 + firstModuleOption);
674 const qsizetype argumentsStart = result.lastIndexOf("\nArguments:"_L1);
675 if (moduleStart >= argumentsStart)
676 return result;
677 QString moduleHelp;
678 moduleHelp +=
679 "\n\nQt libraries can be added by passing their name (-xml) or removed by passing\n"
680 "the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
682 moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
683 moduleHelp += u'\n';
684 result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp);
685 return result;
686}
687
688static inline bool isQtModule(const QString &libName)
689{
690 // Match Standard modules named Qt6XX.dll
691 if (libName.size() < 3 || !libName.startsWith("Qt"_L1, Qt::CaseInsensitive))
692 return false;
693 const QChar version = libName.at(2);
694 return version.isDigit() && (version.toLatin1() - '0') == QT_VERSION_MAJOR;
695}
696
697// Helper for recursively finding all dependent Qt libraries.
698static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary, Platform platform,
700 unsigned *wordSize = nullptr, bool *isDebug = nullptr,
701 unsigned short *machineArch = nullptr,
702 int *directDependencyCount = nullptr, int recursionDepth = 0)
703{
704 QStringList dependentLibs;
705 if (directDependencyCount)
706 *directDependencyCount = 0;
707 if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug, machineArch)) {
708 errorMessage->prepend("Unable to find dependent libraries of "_L1 +
710 return false;
711 }
712 // Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we
713 // are run the 2nd time (updating). We want to check against the Qt bin dir libraries
714 const int start = result->size();
715 for (const QString &lib : std::as_const(dependentLibs)) {
716 if (isQtModule(lib)) {
717 const QString path = normalizeFileName(qtBinDir + u'/' + QFileInfo(lib).fileName());
718 if (!result->contains(path))
719 result->append(path);
720 }
721 }
722 const int end = result->size();
723 if (directDependencyCount)
724 *directDependencyCount = end - start;
725 // Recurse
726 for (int i = start; i < end; ++i)
728 nullptr, nullptr, nullptr, nullptr, recursionDepth + 1))
729 return false;
730 return true;
731}
732
733// Base class to filter debug/release Windows DLLs for functions to be passed to updateFile().
734// Tries to pre-filter by namefilter and does check via PE.
736public:
738 DebugMatchMode debugMatchMode, const QString &prefix = QString()) :
739 m_platform(platform), m_debugMatchMode(debugMatchMode), m_prefix(prefix) {}
740
742 { return findSharedLibraries(dir, m_platform, m_debugMatchMode, m_prefix); }
743
744private:
745 const Platform m_platform;
746 const DebugMatchMode m_debugMatchMode;
747 const QString m_prefix;
748};
749
750static QString pdbFileName(QString libraryFileName)
751{
752 const qsizetype lastDot = libraryFileName.lastIndexOf(u'.') + 1;
753 if (lastDot <= 0)
754 return QString();
755 libraryFileName.replace(lastDot, libraryFileName.size() - lastDot, "pdb"_L1);
756 return libraryFileName;
757}
759{
760 return QStringList() << QStringLiteral("*.jsc") << QStringLiteral("*.qmlc");
761}
762
763// File entry filter function for updateFile() that returns a list of files for
764// QML import trees: DLLs (matching debug) and .qml/,js, etc.
766public:
767 enum Flags {
769 SkipSources = 0x2
770 };
771
773 : m_flags(flags), m_qmlNameFilter(QmlDirectoryFileEntryFunction::qmlNameFilters(flags))
774 , m_dllFilter(platform, debugMatchMode)
775 {}
776
778 {
780 const QStringList &libraries = m_dllFilter(dir);
781 for (const QString &library : libraries) {
782 result.append(library);
783 if (m_flags & DeployPdb) {
784 const QString pdb = pdbFileName(library);
785 if (QFileInfo(dir.absoluteFilePath(pdb)).isFile())
786 result.append(pdb);
787 }
788 }
789 result.append(m_qmlNameFilter(dir));
790 return result;
791 }
792
793private:
794 static inline QStringList qmlNameFilters(unsigned flags)
795 {
797 result << QStringLiteral("qmldir") << QStringLiteral("*.qmltypes")
798 << QStringLiteral("*.frag") << QStringLiteral("*.vert") // Shaders
799 << QStringLiteral("*.ttf");
800 if (!(flags & SkipSources)) {
801 result << QStringLiteral("*.js") << QStringLiteral("*.qml") << QStringLiteral("*.png");
802 result.append(qmlCacheFileFilters());
803 }
804 return result;
805 }
806
807 const unsigned m_flags;
808 NameFilterFileEntryFunction m_qmlNameFilter;
810};
811
812static qint64 qtModule(QString module, const QString &infix)
813{
814 // Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0'
815 const qsizetype lastSlashPos = module.lastIndexOf(u'/');
816 if (lastSlashPos > 0)
817 module.remove(0, lastSlashPos + 1);
818 if (module.startsWith("lib"_L1))
819 module.remove(0, 3);
820 int endPos = infix.isEmpty() ? -1 : module.lastIndexOf(infix);
821 if (endPos == -1)
822 endPos = module.indexOf(u'.'); // strip suffixes '.so.5.0'.
823 if (endPos > 0)
824 module.truncate(endPos);
825 // That should leave us with 'Qt6Core<d>'.
826 for (const auto &qtModule : qtModuleEntries) {
827 const QString &libraryName = qtModule.name;
828 if (module == libraryName
829 || (module.size() == libraryName.size() + 1 && module.startsWith(libraryName))) {
830 return qtModule.id;
831 }
832 }
833 std::wcerr << "Warning: module " << qPrintable(module) << " could not be found\n";
834 return -1;
835}
836
837// Return the path if a plugin is to be deployed
838static QString deployPlugin(const QString &plugin, const QDir &subDir,
839 ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
840 const QStringList &disabledPluginTypes,
841 const QString &libraryLocation, const QString &infix,
843{
844 const QString subDirName = subDir.dirName();
845 // Filter out disabled plugins
846 if (disabledPluginTypes.contains(subDirName)) {
847 std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n';
848 return {};
849 }
850
851 const QString pluginPath = subDir.absoluteFilePath(plugin);
852 // Deploy QUiTools plugins as is without further dependency checking.
853 // The user needs to ensure all required libraries are present (would
854 // otherwise pull QtWebEngine for its plugin).
855 if (subDirName == u"designer")
856 return pluginPath;
857
858 QStringList dependentQtLibs;
859 ModuleBitset neededModules;
861 if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
862 &errorMessage, &dependentQtLibs)) {
863 for (int d = 0; d < dependentQtLibs.size(); ++d) {
864 const qint64 module = qtModule(dependentQtLibs.at(d), infix);
865 if (module >= 0)
866 neededModules[module] = 1;
867 }
868 } else {
869 std::wcerr << "Warning: Cannot determine dependencies of "
870 << QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
871 }
872
873 ModuleBitset missingModules;
874 missingModules = neededModules & disabledQtModules;
875 if (missingModules.any()) {
876 if (optVerboseLevel) {
877 std::wcout << "Skipping plugin " << plugin
878 << " due to disabled dependencies ("
879 << formatQtModules(missingModules).constData() << ").\n";
880 }
881 return {};
882 }
883
884 missingModules = (neededModules & ~*usedQtModules);
885 if (missingModules.any()) {
886 *usedQtModules |= missingModules;
887 if (optVerboseLevel) {
888 std::wcout << "Adding " << formatQtModules(missingModules).constData()
889 << " for " << plugin << '\n';
890 }
891 }
892 return pluginPath;
893}
894
895QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
896 const QStringList &disabledPluginTypes,
897 const QString &qtPluginsDirName, const QString &libraryLocation,
898 const QString &infix,
899 DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin)
900{
901 if (qtPluginsDirName.isEmpty())
902 return QStringList();
903 QDir pluginsDir(qtPluginsDirName);
905 const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
906 for (const QFileInfo &subDirFi : pluginDirs) {
907 const QString subDirName = subDirFi.fileName();
908 const size_t module = qtModuleEntries.moduleIdForPluginType(subDirName);
909 if (module == QtModule::InvalidId) {
910 if (optVerboseLevel > 1) {
911 std::wcerr << "No Qt module found for plugin type \"" << subDirName << "\".\n";
912 }
913 continue;
914 }
915 if (usedQtModules->test(module)) {
916 const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
917 ? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all.
918 : debugMatchModeIn;
919 QDir subDir(subDirFi.absoluteFilePath());
920
921 // Filter for platform or any.
923 const bool isPlatformPlugin = subDirName == "platforms"_L1;
924 if (isPlatformPlugin) {
925 switch (platform) {
928 filter = QStringLiteral("qwindows");
929 if (!infix.isEmpty())
930 filter += infix;
931 break;
932 case Unix:
933 filter = QStringLiteral("libqxcb");
934 break;
935 case UnknownPlatform:
936 break;
937 }
938 } else {
939 filter = u"*"_s;
940 }
941 const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter);
942 for (const QString &plugin : plugins) {
943 const QString pluginPath =
944 deployPlugin(plugin, subDir, usedQtModules, disabledQtModules,
945 disabledPluginTypes, libraryLocation, infix, platform);
946 if (!pluginPath.isEmpty()) {
947 if (isPlatformPlugin)
948 *platformPlugin = subDir.absoluteFilePath(plugin);
949 result.append(pluginPath);
950 }
951 } // for filter
952 } // type matches
953 } // for plugin folder
954 return result;
955}
956
957static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
958{
960 for (const auto &qtModule : qtModuleEntries) {
961 if (modules.test(qtModule.id) && !qtModule.translationCatalog.isEmpty()) {
962 const QString name = qtModule.translationCatalog + u'_' + prefix + ".qm"_L1;
963 if (!result.contains(name))
965 }
966 }
967 return result;
968}
969
970static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules,
971 const QString &target, const Options &options,
973{
974 // Find available languages prefixes by checking on qtbase.
975 QStringList prefixes;
976 QDir sourceDir(sourcePath);
977 const QStringList qmFilter = QStringList(QStringLiteral("qtbase_*.qm"));
978 const QFileInfoList &qmFiles = sourceDir.entryInfoList(qmFilter);
979 for (const QFileInfo &qmFi : qmFiles) {
980 const QString prefix = qmFi.baseName().mid(7);
981 if (options.languages.isEmpty() || options.languages.contains(prefix))
982 prefixes.append(prefix);
983 }
984 if (prefixes.isEmpty()) {
985 std::wcerr << "Warning: Could not find any translations in "
986 << QDir::toNativeSeparators(sourcePath) << " (developer build?)\n.";
987 return true;
988 }
989 // Run lconvert to concatenate all files into a single named "qt_<prefix>.qm" in the application folder
990 // Use QT_INSTALL_TRANSLATIONS as working directory to keep the command line short.
991 const QString absoluteTarget = QFileInfo(target).absoluteFilePath();
992 const QString binary = QStringLiteral("lconvert");
994 for (const QString &prefix : std::as_const(prefixes)) {
996 const QString targetFile = QStringLiteral("qt_") + prefix + QStringLiteral(".qm");
998 const QString targetFilePath = absoluteTarget + u'/' + targetFile;
999 if (options.json)
1000 options.json->addFile(sourcePath + u'/' + targetFile, absoluteTarget);
1001 arguments.append(QDir::toNativeSeparators(targetFilePath));
1002 const QStringList translationFilters = translationNameFilters(usedQtModules, prefix);
1003 if (translationFilters.isEmpty()){
1004 std::wcerr << "Warning: translation catalogs are all empty, skipping translation deployment\n";
1005 return true;
1006 }
1007 const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationFilters);
1008 for (const QFileInfo &langQmFileFi : langQmFiles) {
1009 if (options.json) {
1010 options.json->addFile(langQmFileFi.absoluteFilePath(),
1011 absoluteTarget);
1012 }
1013 arguments.append(langQmFileFi.fileName());
1014 }
1015 if (optVerboseLevel)
1016 std::wcout << "Creating " << targetFile << "...\n";
1017 unsigned long exitCode;
1018 if ((options.updateFileFlags & SkipUpdateFile) == 0
1019 && (!runProcess(binary, arguments, sourcePath, &exitCode, nullptr, nullptr, errorMessage)
1020 || exitCode)) {
1021 return false;
1022 }
1023 } // for prefixes.
1024 return true;
1025}
1026
1028{
1029 operator bool() const { return success; }
1030
1031 bool success = false;
1032 bool isDebug = false;
1036};
1037
1038static QString libraryPath(const QString &libraryLocation, const char *name,
1039 const QString &infix, Platform platform, bool debug)
1040{
1041 QString result = libraryLocation + u'/';
1042 if (platform & WindowsBased) {
1044 result += infix;
1046 result += u'd';
1047 } else if (platform.testFlag(UnixBased)) {
1048 result += QStringLiteral("lib");
1050 result += infix;
1051 }
1053 return result;
1054}
1055
1056static QString vcDebugRedistDir() { return QStringLiteral("Debug_NonRedist"); }
1057
1059{
1060 const char vcDirVar[] = "VCINSTALLDIR";
1061 const QChar slash(u'/');
1062 QString vcRedistDirName = QDir::cleanPath(QFile::decodeName(qgetenv(vcDirVar)));
1063 if (vcRedistDirName.isEmpty()) {
1064 std::wcerr << "Warning: Cannot find Visual Studio installation directory, " << vcDirVar
1065 << " is not set.\n";
1066 return QString();
1067 }
1068 if (!vcRedistDirName.endsWith(slash))
1069 vcRedistDirName.append(slash);
1070 vcRedistDirName.append(QStringLiteral("redist/MSVC"));
1071 if (!QFileInfo(vcRedistDirName).isDir()) {
1072 std::wcerr << "Warning: Cannot find Visual Studio redist directory, "
1073 << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1074 return QString();
1075 }
1076 // Look in reverse order for folder containing the debug redist folder
1077 const QFileInfoList subDirs =
1078 QDir(vcRedistDirName)
1080 for (const QFileInfo &f : subDirs) {
1081 QString path = f.absoluteFilePath();
1082 if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
1083 return path;
1084 path += QStringLiteral("/onecore");
1085 if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
1086 return path;
1087 }
1088 std::wcerr << "Warning: Cannot find Visual Studio redist directory under "
1089 << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1090 return QString();
1091}
1092
1093static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
1094{
1095 //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found.
1097 const bool isClang = platform == WindowsDesktopClangMinGW;
1099 const QString suffix = u'*' + sharedLibrarySuffix(platform);
1100 for (const auto &minGWRuntime : runtimeFilters)
1101 filters.append(minGWRuntime + suffix);
1102
1104 if (dlls.isEmpty()) {
1105 std::wcerr << "Warning: Runtime libraries not found in Qt binary folder, defaulting to looking in path\n";
1106 const QString binaryPath = isClang ? findInPath("clang++.exe"_L1) : findInPath("g++.exe"_L1);
1107 if (binaryPath.isEmpty()) {
1108 std::wcerr << "Warning: Cannot find " << (isClang ? "Clang" : "GCC") << " installation directory, " << (isClang ? "clang++" : "g++") << ".exe must be in the path\n";
1109 return {};
1110 }
1111 const QString binaryFolder = QFileInfo(binaryPath).absolutePath();
1112 dlls = QDir(binaryFolder).entryInfoList(filters, QDir::Files);
1113 }
1114
1115 for (const QFileInfo &dllFi : dlls)
1116 result.append(dllFi.absoluteFilePath());
1117
1118 return result;
1119}
1120
1121static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
1122{
1124 switch (platform) {
1125 case WindowsDesktopMinGW: {
1126 const QStringList minGWRuntimes = { "*gcc_"_L1, "*stdc++"_L1, "*winpthread"_L1 };
1127 result.append(findMinGWRuntimePaths(qtBinDir, platform, minGWRuntimes));
1128 break;
1129 }
1131 const QStringList clangMinGWRuntimes = { "*unwind"_L1, "*c++"_L1 };
1132 result.append(findMinGWRuntimePaths(qtBinDir, platform, clangMinGWRuntimes));
1133 break;
1134 }
1135#ifdef Q_OS_WIN
1136 case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages.
1137 QString vcRedistDirName = vcRedistDir();
1138 if (vcRedistDirName.isEmpty())
1139 break;
1140 QStringList redistFiles;
1141 QDir vcRedistDir(vcRedistDirName);
1142 const QString machineArchString = getArchString(machineArch);
1143 if (isDebug) {
1144 // Append DLLs from Debug_NonRedist\x??\Microsoft.VC<version>.DebugCRT.
1145 if (vcRedistDir.cd(vcDebugRedistDir()) && vcRedistDir.cd(machineArchString)) {
1146 const QStringList names = vcRedistDir.entryList(QStringList(QStringLiteral("Microsoft.VC*.DebugCRT")), QDir::Dirs);
1147 if (!names.isEmpty() && vcRedistDir.cd(names.first())) {
1148 const QFileInfoList &dlls = vcRedistDir.entryInfoList(QStringList("*.dll"_L1));
1149 for (const QFileInfo &dll : dlls)
1150 redistFiles.append(dll.absoluteFilePath());
1151 }
1152 }
1153 } else { // release: Bundle vcredist<>.exe
1154 QString releaseRedistDir = vcRedistDirName;
1155 const QStringList countryCodes = vcRedistDir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Dirs);
1156 if (!countryCodes.isEmpty()) // Pre MSVC2017
1157 releaseRedistDir += u'/' + countryCodes.constFirst();
1158 QFileInfo fi(releaseRedistDir + "/vc_redist."_L1
1159 + machineArchString + ".exe"_L1);
1160 if (!fi.isFile()) { // Pre MSVC2017/15.5
1161 fi.setFile(releaseRedistDir + "/vcredist_"_L1
1162 + machineArchString + ".exe"_L1);
1163 }
1164 if (fi.isFile())
1165 redistFiles.append(fi.absoluteFilePath());
1166 }
1167 if (redistFiles.isEmpty()) {
1168 std::wcerr << "Warning: Cannot find Visual Studio " << (isDebug ? "debug" : "release")
1169 << " redistributable files in " << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
1170 break;
1171 }
1172 result.append(redistFiles);
1173 }
1174 break;
1175#endif // Q_OS_WIN
1176 default:
1177 break;
1178 }
1179 return result;
1180}
1181
1182static inline int qtVersion(const QMap<QString, QString> &qtpathsVariables)
1183{
1184 const QString versionString = qtpathsVariables.value(QStringLiteral("QT_VERSION"));
1185 const QChar dot = u'.';
1186 const int majorVersion = versionString.section(dot, 0, 0).toInt();
1187 const int minorVersion = versionString.section(dot, 1, 1).toInt();
1188 const int patchVersion = versionString.section(dot, 2, 2).toInt();
1189 return (majorVersion << 16) | (minorVersion << 8) | patchVersion;
1190}
1191
1192// Deploy a library along with its .pdb debug info file (MSVC) should it exist.
1193static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory,
1194 const Options &options, QString *errorMessage)
1195{
1196 if (!updateFile(sourceFileName, targetDirectory, options.updateFileFlags, options.json, errorMessage)) {
1197 if (options.ignoreLibraryErrors) {
1198 std::wcerr << "Warning: Could not update " << sourceFileName << " :" << *errorMessage << '\n';
1200 return true;
1201 }
1202 return false;
1203 }
1204
1205 if (options.deployPdb) {
1206 const QFileInfo pdb(pdbFileName(sourceFileName));
1207 if (pdb.isFile())
1208 return updateFile(pdb.absoluteFilePath(), targetDirectory, options.updateFileFlags, nullptr, errorMessage);
1209 }
1210 return true;
1211}
1212
1213// Find out the ICU version to add the data library icudtXX.dll, which does not
1214// show as a dependency.
1215static QString getIcuVersion(const QString &libName)
1216{
1217 QString version;
1218 std::copy_if(libName.cbegin(), libName.cend(), std::back_inserter(version),
1219 [](QChar c) { return c.isDigit(); });
1220 return version;
1221}
1222
1223static DeployResult deploy(const Options &options, const QMap<QString, QString> &qtpathsVariables,
1225{
1227
1228 const QChar slash = u'/';
1229
1230 const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
1231 const QString libraryLocation = options.platform == Unix
1232 ? qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBS"))
1233 : qtBinDir;
1234 const QString infix = qtpathsVariables.value(QLatin1StringView(qmakeInfixKey));
1235 const int version = qtVersion(qtpathsVariables);
1236 Q_UNUSED(version);
1237
1238 if (optVerboseLevel > 1)
1239 std::wcout << "Qt binaries in " << QDir::toNativeSeparators(qtBinDir) << '\n';
1240
1241 QStringList dependentQtLibs;
1242 bool detectedDebug;
1243 unsigned wordSize;
1244 unsigned short machineArch;
1245 int directDependencyCount = 0;
1246 if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform, errorMessage, &dependentQtLibs, &wordSize,
1247 &detectedDebug, &machineArch, &directDependencyCount)) {
1248 return result;
1249 }
1250 for (int b = 1; b < options.binaries.size(); ++b) {
1251 if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform, errorMessage, &dependentQtLibs,
1252 nullptr, nullptr, nullptr)) {
1253 return result;
1254 }
1255 }
1256
1257 DebugMatchMode debugMatchMode = MatchDebugOrRelease;
1258 result.isDebug = false;
1259 switch (options.debugDetection) {
1261 // Debug detection is only relevant for Msvc/ClangMsvc which have distinct
1262 // runtimes and binaries. For anything else, use MatchDebugOrRelease
1263 // since also debug cannot be reliably detect for MinGW.
1264 if (options.platform.testFlag(Msvc) || options.platform.testFlag(ClangMsvc)) {
1265 result.isDebug = detectedDebug;
1266 debugMatchMode = result.isDebug ? MatchDebug : MatchRelease;
1267 }
1268 break;
1270 result.isDebug = true;
1271 debugMatchMode = MatchDebug;
1272 break;
1274 debugMatchMode = MatchRelease;
1275 break;
1276 }
1277
1278 // Determine application type, check Quick2 is used by looking at the
1279 // direct dependencies (do not be fooled by QtWebKit depending on it).
1280 for (int m = 0; m < dependentQtLibs.size(); ++m) {
1281 const qint64 module = qtModule(dependentQtLibs.at(m), infix);
1282 if (module >= 0)
1283 result.directlyUsedQtLibraries[module] = 1;
1284 }
1285
1286 const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
1287 const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModuleId);
1288 const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModuleId);
1289 const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModuleId))
1290 && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModuleId)));
1291
1292 if (optVerboseLevel) {
1293 std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' '
1294 << wordSize << " bit, " << (result.isDebug ? "debug" : "release")
1295 << " executable";
1296 if (usesQml2)
1297 std::wcout << " [QML]";
1298 std::wcout << '\n';
1299 }
1300
1301 if (dependentQtLibs.isEmpty()) {
1302 *errorMessage = QDir::toNativeSeparators(options.binaries.first()) + QStringLiteral(" does not seem to be a Qt executable.");
1303 return result;
1304 }
1305
1306 // Some Windows-specific checks: Qt5Core depends on ICU when configured with "-icu". Other than
1307 // that, Qt5WebKit has a hard dependency on ICU.
1308 if (options.platform.testFlag(WindowsBased)) {
1309 const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral("Qt6Core"), Qt::CaseInsensitive)
1310 + dependentQtLibs.filter(QStringLiteral("Qt5WebKit"), Qt::CaseInsensitive);
1311 for (const QString &qtLib : qtLibs) {
1313 if (!icuLibs.isEmpty()) {
1314 // Find out the ICU version to add the data library icudtXX.dll, which does not show
1315 // as a dependency.
1316 const QString icuVersion = getIcuVersion(icuLibs.constFirst());
1317 if (!icuVersion.isEmpty()) {
1318 if (optVerboseLevel > 1)
1319 std::wcout << "Adding ICU version " << icuVersion << '\n';
1320 QString icuLib = QStringLiteral("icudt") + icuVersion
1322 // Some packages contain debug dlls of ICU libraries even though it's a C
1323 // library and the official packages do not differentiate (QTBUG-87677)
1324 if (result.isDebug) {
1325 const QString icuLibCandidate = QStringLiteral("icudtd") + icuVersion
1327 if (!findInPath(icuLibCandidate).isEmpty()) {
1328 icuLib = icuLibCandidate;
1329 }
1330 }
1331 icuLibs.push_back(icuLib);
1332 }
1333 for (const QString &icuLib : std::as_const(icuLibs)) {
1334 const QString icuPath = findInPath(icuLib);
1335 if (icuPath.isEmpty()) {
1336 *errorMessage = QStringLiteral("Unable to locate ICU library ") + icuLib;
1337 return result;
1338 }
1339 dependentQtLibs.push_back(icuPath);
1340 } // for each icuLib
1341 break;
1342 } // !icuLibs.isEmpty()
1343 } // Qt6Core/Qt6WebKit
1344 } // Windows
1345
1346 // Scan Quick2 imports
1347 QmlImportScanResult qmlScanResult;
1348 if (options.quickImports && usesQml2) {
1349 // Custom list of import paths provided by user
1350 QStringList qmlImportPaths = options.qmlImportPaths;
1351 // Qt's own QML modules
1352 qmlImportPaths << qtpathsVariables.value(QStringLiteral("QT_INSTALL_QML"));
1353 QStringList qmlDirectories = options.qmlDirectories;
1354 if (qmlDirectories.isEmpty()) {
1355 const QString qmlDirectory = findQmlDirectory(options.platform, options.directory);
1356 if (!qmlDirectory.isEmpty())
1357 qmlDirectories.append(qmlDirectory);
1358 }
1359 for (const QString &qmlDirectory : std::as_const(qmlDirectories)) {
1360 if (optVerboseLevel >= 1)
1361 std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
1362 const QmlImportScanResult scanResult =
1363 runQmlImportScanner(qmlDirectory, qmlImportPaths,
1364 result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
1365 options.platform, debugMatchMode, errorMessage);
1366 if (!scanResult.ok)
1367 return result;
1368 qmlScanResult.append(scanResult);
1369 // Additional dependencies of QML plugins.
1370 for (const QString &plugin : std::as_const(qmlScanResult.plugins)) {
1371 if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &detectedDebug, &machineArch))
1372 return result;
1373 }
1374 if (optVerboseLevel >= 1) {
1375 std::wcout << "QML imports:\n";
1376 for (const QmlImportScanResult::Module &mod : std::as_const(qmlScanResult.modules)) {
1377 std::wcout << " '" << mod.name << "' "
1378 << QDir::toNativeSeparators(mod.sourcePath) << '\n';
1379 }
1380 if (optVerboseLevel >= 2) {
1381 std::wcout << "QML plugins:\n";
1382 for (const QString &p : std::as_const(qmlScanResult.plugins))
1383 std::wcout << " " << QDir::toNativeSeparators(p) << '\n';
1384 }
1385 }
1386 }
1387 }
1388
1389 QString platformPlugin;
1390 // Sort apart Qt 5 libraries in the ones that are represented by the
1391 // QtModule enumeration (and thus controlled by flags) and others.
1392 QStringList deployedQtLibraries;
1393 for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
1394 const qint64 module = qtModule(dependentQtLibs.at(i), infix);
1395 if (module >= 0)
1396 result.usedQtLibraries[module] = 1;
1397 else
1398 deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
1399 }
1400 result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
1401
1403 if (!usesQml2) {
1404 disabled[QtQmlModuleId] = 1;
1405 disabled[QtQuickModuleId] = 1;
1406 }
1407 const QStringList plugins = findQtPlugins(
1408 &result.deployedQtLibraries,
1409 // For non-QML applications, disable QML to prevent it from being pulled in by the
1410 // qtaccessiblequick plugin.
1411 disabled,
1412 options.disabledPluginTypes, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
1413 libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin);
1414
1415 // Apply options flags and re-add library names.
1416 QString qtGuiLibrary;
1417 for (const auto &qtModule : qtModuleEntries) {
1418 if (result.deployedQtLibraries.test(qtModule.id)) {
1419 const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
1420 options.platform, result.isDebug);
1421 deployedQtLibraries.append(library);
1422 if (qtModule.id == QtGuiModuleId)
1423 qtGuiLibrary = library;
1424 }
1425 }
1426
1427 if (optVerboseLevel >= 1) {
1428 std::wcout << "Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData()
1429 << "\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData()
1430 << "\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() << '\n';
1431 }
1432
1433 if (optVerboseLevel > 1)
1434 std::wcout << "Plugins: " << plugins.join(u',') << '\n';
1435
1436 if (result.deployedQtLibraries.test(QtGuiModuleId) && platformPlugin.isEmpty()) {
1437 *errorMessage =QStringLiteral("Unable to find the platform plugin.");
1438 return result;
1439 }
1440
1441 if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) {
1442 const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, options.platform, errorMessage);
1443 const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty();
1444 if (options.softwareRasterizer && !dependsOnOpenGl) {
1445 const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1StringView(windowsSharedLibrarySuffix));
1446 if (softwareRasterizer.isFile())
1447 deployedQtLibraries.append(softwareRasterizer.absoluteFilePath());
1448 }
1449 if (options.systemD3dCompiler && machineArch != IMAGE_FILE_MACHINE_ARM64) {
1450 const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir, wordSize);
1451 if (d3dCompiler.isEmpty()) {
1452 std::wcerr << "Warning: Cannot find any version of the d3dcompiler DLL.\n";
1453 } else {
1454 deployedQtLibraries.push_back(d3dCompiler);
1455 }
1456 }
1457 if (options.systemDxc) {
1458 const QStringList dxcLibs = findDxc(options.platform, qtBinDir, wordSize);
1459 if (!dxcLibs.isEmpty())
1460 deployedQtLibraries.append(dxcLibs);
1461 else
1462 std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
1463 }
1464 } // Windows
1465
1466 // Update libraries
1467 if (options.libraries) {
1468 const QString targetPath = options.libraryDirectory.isEmpty() ?
1469 options.directory : options.libraryDirectory;
1470 QStringList libraries = deployedQtLibraries;
1471 if (options.compilerRunTime)
1472 libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug, machineArch));
1473 for (const QString &qtLib : std::as_const(libraries)) {
1474 if (!updateLibrary(qtLib, targetPath, options, errorMessage))
1475 return result;
1476 }
1477
1478#if !QT_CONFIG(relocatable)
1479 if (options.patchQt && !options.dryRun) {
1480 const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", infix,
1481 options.platform, result.isDebug)).fileName();
1482 if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
1483 std::wcerr << "Warning: " << *errorMessage << '\n';
1485 }
1486 }
1487#endif // QT_CONFIG(relocatable)
1488 } // optLibraries
1489
1490 // Update plugins
1491 if (options.plugins) {
1492 const QString targetPath = options.pluginDirectory.isEmpty() ?
1493 options.directory : options.pluginDirectory;
1494 QDir dir(targetPath);
1495 if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
1496 *errorMessage = "Cannot create "_L1 +
1497 QDir::toNativeSeparators(dir.absolutePath()) + u'.';
1498 return result;
1499 }
1500 for (const QString &plugin : plugins) {
1501 const QString targetDirName = plugin.section(slash, -2, -2);
1502 const QString targetPath = dir.absoluteFilePath(targetDirName);
1503 if (!dir.exists(targetDirName)) {
1504 if (optVerboseLevel)
1505 std::wcout << "Creating directory " << targetPath << ".\n";
1506 if (!(options.updateFileFlags & SkipUpdateFile) && !dir.mkdir(targetDirName)) {
1507 *errorMessage = QStringLiteral("Cannot create ") + targetDirName + u'.';
1508 return result;
1509 }
1510 }
1511 if (!updateLibrary(plugin, targetPath, options, errorMessage))
1512 return result;
1513 }
1514 } // optPlugins
1515
1516 // Update Quick imports
1517 // Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
1518 // for WebKit1-applications. Check direct dependency only.
1519 if (options.quickImports && usesQml2) {
1520 const QString targetPath = options.qmlDirectory.isEmpty()
1521 ? options.directory + QStringLiteral("/qml")
1522 : options.qmlDirectory;
1523 if (!createDirectory(targetPath, errorMessage, options.dryRun))
1524 return result;
1525 for (const QmlImportScanResult::Module &module : std::as_const(qmlScanResult.modules)) {
1526 const QString installPath = module.installPath(targetPath);
1527 if (optVerboseLevel > 1)
1528 std::wcout << "Installing: '" << module.name
1529 << "' from " << module.sourcePath << " to "
1530 << QDir::toNativeSeparators(installPath) << '\n';
1531 if (installPath != targetPath && !createDirectory(installPath, errorMessage, options.dryRun))
1532 return result;
1533 unsigned updateFileFlags = options.updateFileFlags
1535 unsigned qmlDirectoryFileFlags = 0;
1536 if (options.deployPdb)
1537 qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
1538 if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform,
1539 debugMatchMode,
1540 qmlDirectoryFileFlags),
1541 installPath, updateFileFlags, options.json, errorMessage)) {
1542 return result;
1543 }
1544 }
1545 } // optQuickImports
1546
1547 if (options.translations) {
1549 return result;
1550 if (!deployTranslations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS")),
1551 result.deployedQtLibraries, options.translationsDirectory, options,
1552 errorMessage)) {
1553 return result;
1554 }
1555 }
1556
1557 result.success = true;
1558 return result;
1559}
1560
1561static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, const char *binaryName,
1562 const Options &sourceOptions, QString *errorMessage)
1563{
1564 // Copy the web process and its dependencies
1565 const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform);
1566 const QString webProcessSource = qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBEXECS"))
1567 + u'/' + webProcess;
1568 if (!updateFile(webProcessSource, sourceOptions.directory, sourceOptions.updateFileFlags, sourceOptions.json, errorMessage))
1569 return false;
1570 Options options(sourceOptions);
1571 options.binaries.append(options.directory + u'/' + webProcess);
1572 options.quickImports = false;
1573 options.translations = false;
1574 return deploy(options, qtpathsVariables, errorMessage);
1575}
1576
1577static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
1578 const Options &options, bool isDebug, QString *errorMessage)
1579{
1580 static const char *installDataFiles[] = {"icudtl.dat",
1581 "qtwebengine_devtools_resources.pak",
1582 "qtwebengine_resources.pak",
1583 "qtwebengine_resources_100p.pak",
1584 "qtwebengine_resources_200p.pak"};
1585 QByteArray webEngineProcessName(webEngineProcessC);
1586 if (isDebug && platformHasDebugSuffix(options.platform))
1587 webEngineProcessName.append('d');
1588 if (optVerboseLevel)
1589 std::wcout << "Deploying: " << webEngineProcessName.constData() << "...\n";
1590 if (!deployWebProcess(qtpathsVariables, webEngineProcessName, options, errorMessage))
1591 return false;
1592 const QString resourcesSubDir = QStringLiteral("/resources");
1593 const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_DATA"))
1594 + resourcesSubDir + u'/';
1595 const QString resourcesTargetDir(options.directory + resourcesSubDir);
1596 if (!createDirectory(resourcesTargetDir, errorMessage, options.dryRun))
1597 return false;
1598 for (auto installDataFile : installDataFiles) {
1599 if (!updateFile(resourcesSourceDir + QLatin1StringView(installDataFile),
1600 resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) {
1601 return false;
1602 }
1603 }
1604 const QFileInfo translations(qtpathsVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS"))
1605 + QStringLiteral("/qtwebengine_locales"));
1606 if (!translations.isDir()) {
1607 std::wcerr << "Warning: Cannot find the translation files of the QtWebEngine module at "
1608 << QDir::toNativeSeparators(translations.absoluteFilePath()) << ".\n";
1609 return true;
1610 }
1611 if (options.translations) {
1612 // Copy the whole translations directory.
1614 && updateFile(translations.absoluteFilePath(), options.translationsDirectory,
1615 options.updateFileFlags, options.json, errorMessage);
1616 }
1617 // Translations have been turned off, but QtWebEngine needs at least one.
1618 const QFileInfo enUSpak(translations.filePath() + QStringLiteral("/en-US.pak"));
1619 if (!enUSpak.exists()) {
1620 std::wcerr << "Warning: Cannot find "
1621 << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) << ".\n";
1622 return true;
1623 }
1624 const QString webEngineTranslationsDir = options.translationsDirectory + u'/'
1625 + translations.fileName();
1626 if (!createDirectory(webEngineTranslationsDir, errorMessage, options.dryRun))
1627 return false;
1628 return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir,
1629 options.updateFileFlags, options.json, errorMessage);
1630}
1631
1633
1635
1636int main(int argc, char **argv)
1637{
1638 QCoreApplication a(argc, argv);
1639 QCoreApplication::setApplicationVersion(QT_VERSION_STR ""_L1);
1640
1642 QByteArray path = qgetenv("PATH");
1643 if (!path.contains(qtBinPath)) { // QTBUG-39177, ensure Qt is in the path so that qt.conf is taken into account.
1644 path.prepend(QDir::listSeparator().toLatin1());
1645 path.prepend(qtBinPath);
1646 qputenv("PATH", path);
1647 }
1648
1649 Options options;
1651
1652 // Early parse the --qmake and --qtpaths options, because they are needed to determine the
1653 // options that select/deselect Qt modules.
1654 {
1657 std::wcerr << "Error: " << errorMessage << "\n";
1658 return 1;
1659 }
1660 }
1661
1662 const QMap<QString, QString> qtpathsVariables =
1664 const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
1665 options.platform = platformFromMkSpec(xSpec);
1666 if (options.platform == UnknownPlatform) {
1667 std::wcerr << "Unsupported platform " << xSpec << '\n';
1668 return 1;
1669 }
1670
1671 if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
1672 || !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
1673 std::wcerr << "Unable to query qtpaths: " << errorMessage << '\n';
1674 return 1;
1675 }
1676
1677 // Read the Qt module information from the Qt installation directory.
1678 const QString modulesDir
1679 = qtpathsVariables.value(QLatin1String("QT_INSTALL_ARCHDATA"))
1680 + QLatin1String("/modules");
1681 const QString translationsDir
1682 = qtpathsVariables.value(QLatin1String("QT_INSTALL_TRANSLATIONS"));
1683 if (!qtModuleEntries.populate(modulesDir, translationsDir, optVerboseLevel > 1,
1684 &errorMessage)) {
1685 std::wcerr << "Error: " << errorMessage << "\n";
1686 return 1;
1687 }
1689
1690 // Parse the full command line.
1691 {
1692 QCommandLineParser parser;
1694 const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
1696 std::wcerr << errorMessage << "\n\n";
1698 std::fputs(qPrintable(helpText(parser)), stdout);
1700 return 1;
1702 return 0;
1703 }
1704
1705 // Create directories
1706 if (!createDirectory(options.directory, &errorMessage, options.dryRun)) {
1707 std::wcerr << errorMessage << '\n';
1708 return 1;
1709 }
1710 if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory
1711 && !createDirectory(options.libraryDirectory, &errorMessage, options.dryRun)) {
1712 std::wcerr << errorMessage << '\n';
1713 return 1;
1714 }
1715
1716 const DeployResult result = deploy(options, qtpathsVariables, &errorMessage);
1717 if (!result) {
1718 std::wcerr << errorMessage << '\n';
1719 return 1;
1720 }
1721
1722 if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
1723 if (!deployWebEngineCore(qtpathsVariables, options, result.isDebug, &errorMessage)) {
1724 std::wcerr << errorMessage << '\n';
1725 return 1;
1726 }
1727 }
1728
1729 if (options.json) {
1730 if (options.list)
1731 std::fputs(options.json->toList(options.list, options.directory).constData(), stdout);
1732 else
1733 std::fputs(options.json->toJson().constData(), stdout);
1734 delete options.json;
1735 options.json = nullptr;
1736 }
1737
1738 return 0;
1739}
QStringList operator()(const QDir &dir) const
Definition main.cpp:741
DllDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, const QString &prefix=QString())
Definition main.cpp:737
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
\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:122
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore
Definition qchar.h:48
constexpr bool isDigit() const noexcept
Returns true if the character is a decimal digit (Number_DecimalDigit); otherwise returns false.
Definition qchar.h:473
constexpr char toLatin1() const noexcept
Returns the Latin-1 character equivalent to the QChar, or 0.
Definition qchar.h:457
The QCommandLineOption class defines a possible command-line option. \inmodule QtCore.
void setFlags(Flags aflags)
Set the set of flags that affect this command-line option to flags.
QStringList names() const
Returns the names set for this option.
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:19
QString dirName() const
Returns the name of the directory; this is not the same as the path, e.g.
Definition qdir.cpp:715
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:1387
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2395
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
QString absoluteFilePath(const QString &fileName) const
Returns the absolute path name of a file in the directory.
Definition qdir.cpp:809
@ Name
Definition qdir.h:49
@ Reversed
Definition qdir.h:56
@ Executable
Definition qdir.h:30
@ Files
Definition qdir.h:22
@ NoDotAndDotDot
Definition qdir.h:43
@ Dirs
Definition qdir.h:21
static constexpr QChar listSeparator() noexcept
Definition qdir.h:197
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString fileName() const
Returns the name of the file, excluding the path.
bool isExecutable() const
Returns true if the file is executable; otherwise returns false.
void setFile(const QString &file)
Sets the file that the QFileInfo provides information about to file.
QString absoluteFilePath() const
Returns an absolute path including the file name.
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 a file's path absolute path.
QString filePath() const
Returns the file name, including the path (which may be absolute or relative).
bool exists() const
Returns true if the file exists; otherwise returns false.
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
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
Definition qmap.h:186
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:356
bool contains(const Key &key) const
Definition qmap.h:340
bool isEmpty() const
Definition qmap.h:268
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
\inmodule QtCore
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
std::wstring toStdWString() const
Returns a std::wstring object with the data contained in this QString.
Definition qstring.h:1325
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:660
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:5299
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
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:7956
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6159
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
const_iterator cbegin() const
Definition qstring.h:1201
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
const_iterator cend() const
Definition qstring.h:1209
void push_back(QChar c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.h:868
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
QString section(QChar sep, qsizetype start, qsizetype end=-1, SectionFlags flags=SectionDefault) const
This function returns a section of the string.
Definition qstring.h:1139
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString toLower() const &
Definition qstring.h:368
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1217
QString & append(QChar c)
Definition qstring.cpp:3227
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
QByteArray toUtf8() const &
Definition qstring.h:563
QString & prepend(QChar c)
Definition qstring.h:411
QStringList operator()(const QDir &dir) const
Definition main.cpp:777
QmlDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
Definition main.cpp:772
bool populate(const QString &modulesDir, const QString &translationsDir, bool verbose, QString *errorString)
size_t size() const
const QtModule & moduleById(size_t id) const
size_t moduleIdForPluginType(const QString &pluginType) const
int main()
[0]
QSet< QString >::iterator it
QList< QVariant > arguments
Combined button and popup list for selecting options.
@ CaseInsensitive
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
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint start
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
const GLubyte * c
GLuint GLuint * names
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLuint GLenum option
static qreal dot(const QPointF &a, const QPointF &b)
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
bool updateFile(const QString &fileName, const QHash< QString, QString > &replacements)
Definition main.cpp:1503
QString findInPath(const QString &fileName)
Definition main.cpp:2597
static Platform platformFromMkSpec(const QString &xSpec)
Definition main.cpp:115
static bool isQtModule(const QString &libName)
Definition main.cpp:688
static bool deployWebEngineCore(const QMap< QString, QString > &qtpathsVariables, const Options &options, bool isDebug, QString *errorMessage)
Definition main.cpp:1577
static QtModuleInfoStore qtModuleEntries
Definition main.cpp:38
static QString libraryPath(const QString &libraryLocation, const char *name, const QString &infix, Platform platform, bool debug)
Definition main.cpp:1038
static QString lineBreak(QString s)
Definition main.cpp:652
static QString deployPlugin(const QString &plugin, const QDir &subDir, ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules, const QStringList &disabledPluginTypes, const QString &libraryLocation, const QString &infix, Platform platform)
Definition main.cpp:838
static QString msgFileDoesNotExist(const QString &file)
Definition main.cpp:208
static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
Definition main.cpp:1121
static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory, const Options &options, QString *errorMessage)
Definition main.cpp:1193
static bool deployWebProcess(const QMap< QString, QString > &qtpathsVariables, const char *binaryName, const Options &sourceOptions, QString *errorMessage)
Definition main.cpp:1561
static void assignKnownModuleIds()
Definition main.cpp:57
static QCommandLineOption createVerboseOption()
Definition main.cpp:236
ExlusiveOptionValue
Definition main.cpp:130
@ OptionEnabled
Definition main.cpp:132
@ OptionDisabled
Definition main.cpp:133
@ OptionAuto
Definition main.cpp:131
static int parseArguments(const QStringList &arguments, QCommandLineParser *parser, Options *options, QString *errorMessage)
Definition main.cpp:304
static QString moduleNameToOptionName(const QString &moduleName)
Definition main.cpp:90
static ExlusiveOptionValue parseExclusiveOptions(const QCommandLineParser *parser, const QCommandLineOption &enableOption, const QCommandLineOption &disableOption)
Definition main.cpp:136
static int qtVersion(const QMap< QString, QString > &qtpathsVariables)
Definition main.cpp:1182
static QStringList translationNameFilters(const ModuleBitset &modules, const QString &prefix)
Definition main.cpp:957
static QString findBinary(const QString &directory, Platform platform)
Definition main.cpp:193
static int parseEarlyArguments(const QStringList &arguments, Options *options, QString *errorMessage)
Definition main.cpp:245
static QCommandLineOption createQMakeOption()
Definition main.cpp:218
static QStringList qmlCacheFileFilters()
Definition main.cpp:758
static QString pdbFileName(QString libraryFileName)
Definition main.cpp:750
CommandLineParseFlag
Definition main.cpp:213
@ CommandLineParseError
Definition main.cpp:214
@ CommandLineParseHelpRequested
Definition main.cpp:215
#define DECLARE_KNOWN_MODULE(name)
Definition main.cpp:40
static QCommandLineOption createQtPathsOption()
Definition main.cpp:227
static const char webEngineProcessC[]
Definition main.cpp:82
static qint64 qtModule(QString module, const QString &infix)
Definition main.cpp:812
static QString vcRedistDir()
Definition main.cpp:1058
static QString webProcessBinary(const char *binaryName, Platform p)
Definition main.cpp:84
static QString helpText(const QCommandLineParser &p)
Definition main.cpp:664
static DeployResult deploy(const Options &options, const QMap< QString, QString > &qtpathsVariables, QString *errorMessage)
Definition main.cpp:1223
static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
Definition main.cpp:1093
#define DEFINE_KNOWN_MODULE(name)
Definition main.cpp:54
#define IMAGE_FILE_MACHINE_ARM64
Definition main.cpp:23
static QString getIcuVersion(const QString &libName)
Definition main.cpp:1215
QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules, const QStringList &disabledPluginTypes, const QString &qtPluginsDirName, const QString &libraryLocation, const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin)
Definition main.cpp:895
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:698
static bool deployTranslations(const QString &sourcePath, const ModuleBitset &usedQtModules, const QString &target, const Options &options, QString *errorMessage)
Definition main.cpp:970
static QString vcDebugRedistDir()
Definition main.cpp:1056
static QByteArray formatQtModules(const ModuleBitset &mask, bool option=false)
Definition main.cpp:100
QmlImportScanResult runQmlImportScanner(const QString &directory, const QStringList &qmlImportPaths, bool usesWidgets, int platform, DebugMatchMode debugMatchMode, QString *errorMessage)
Definition qmlutils.cpp:75
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:70
long long qint64
Definition qtypes.h:55
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
QT_BEGIN_NAMESPACE Platform platform()
Platform
#define disabled
QFile file
[0]
QFileInfo fi("c:/temp/foo")
[newstuff]
QString dir
[11]
const QStringList filters({"Image files (*.png *.xpm *.jpg)", "Text files (*.txt)", "Any files (*)" })
[6]
ModuleBitset usedQtLibraries
Definition main.cpp:1034
ModuleBitset directlyUsedQtLibraries
Definition main.cpp:1033
bool isDebug
Definition main.cpp:1032
ModuleBitset deployedQtLibraries
Definition main.cpp:1035
bool success
Definition main.cpp:1031
QStringList disabledPluginTypes
Definition main.cpp:167
QString libraryDirectory
Definition main.cpp:179
bool translations
Definition main.cpp:163
DebugDetection debugDetection
Definition main.cpp:185
QStringList binaries
Definition main.cpp:182
bool quickImports
Definition main.cpp:162
bool systemDxc
Definition main.cpp:165
unsigned updateFileFlags
Definition main.cpp:172
ListOption list
Definition main.cpp:184
QStringList qmlImportPaths
Definition main.cpp:159
QString qtpathsBinary
Definition main.cpp:176
bool deployPdb
Definition main.cpp:186
QStringList qmlDirectories
Definition main.cpp:173
QString translationsDirectory
Definition main.cpp:177
QStringList languages
Definition main.cpp:178
ModuleBitset additionalLibraries
Definition main.cpp:170
QString directory
Definition main.cpp:175
bool patchQt
Definition main.cpp:188
bool systemD3dCompiler
Definition main.cpp:164
Platform platform
Definition main.cpp:169
bool ignoreLibraryErrors
Definition main.cpp:189
QString pluginDirectory
Definition main.cpp:180
QString qmlDirectory
Definition main.cpp:181
JsonOutput * json
Definition main.cpp:183
bool softwareRasterizer
Definition main.cpp:168
ModuleBitset disabledLibraries
Definition main.cpp:171
bool dryRun
Definition main.cpp:187
bool plugins
Definition main.cpp:160
DebugDetection
Definition main.cpp:154
@ DebugDetectionForceRelease
Definition main.cpp:157
@ DebugDetectionForceDebug
Definition main.cpp:156
@ DebugDetectionAuto
Definition main.cpp:155
bool libraries
Definition main.cpp:161
bool compilerRunTime
Definition main.cpp:166
QStringList plugins
Definition qmlutils.h:29
QList< Module > modules
Definition qmlutils.h:28
void append(const QmlImportScanResult &other)
Definition qmlutils.cpp:125
QString name
static constexpr size_t InvalidId
QStringList findDxc(Platform, const QString &, unsigned)
Definition utils.cpp:960
int optVerboseLevel
Definition utils.cpp:36
QMap< QString, QString > queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
Definition utils.cpp:424
QString findD3dCompiler(Platform, const QString &, unsigned)
Definition utils.cpp:955
bool createDirectory(const QString &directory, QString *errorMessage, bool dryRun)
Definition utils.cpp:65
QStringList findSharedLibraries(const QDir &directory, Platform platform, DebugMatchMode debugMatchMode, const QString &prefix)
Definition utils.cpp:89
bool runProcess(const QString &binary, const QStringList &args, const QString &workingDirectory, unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr, QString *errorMessage)
Definition utils.cpp:312
bool patchQtCore(const QString &path, QString *errorMessage)
Definition utils.cpp:968
const char * qmakeInfixKey
Definition utils.cpp:422
@ MinGW
Definition utils.h:29
@ ClangMsvc
Definition utils.h:30
@ WindowsBased
Definition utils.h:22
@ WindowsDesktopMsvc
Definition utils.h:33
@ Unix
Definition utils.h:37
@ Msvc
Definition utils.h:28
@ WindowsDesktopMinGW
Definition utils.h:34
@ UnixBased
Definition utils.h:23
@ UnknownPlatform
Definition utils.h:38
@ WindowsDesktopClangMinGW
Definition utils.h:36
@ WindowsDesktopClangMsvc
Definition utils.h:35
QStringList findDependentLibraries(const QString &executableFileName, Platform platform, QString *errorMessage)
Definition utils.h:196
bool platformHasDebugSuffix(Platform p)
Definition utils.h:45
@ SkipUpdateFile
Definition utils.h:214
@ ForceUpdateFile
Definition utils.h:213
@ SkipQmlDesignerSpecificsDirectories
Definition utils.h:216
static const char windowsSharedLibrarySuffix[]
Definition utils.h:139
DebugMatchMode
Definition utils.h:153
@ MatchRelease
Definition utils.h:155
@ MatchDebug
Definition utils.h:154
@ MatchDebugOrRelease
Definition utils.h:156
bool readExecutable(const QString &executableFileName, Platform platform, QString *errorMessage, QStringList *dependentLibraries=0, unsigned *wordSize=0, bool *isDebug=0, unsigned short *machineArch=nullptr)
Definition utils.h:177
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 normalizeFileName(const QString &name)
Definition utils.h:136
QString sharedLibrarySuffix(Platform platform)
Definition utils.h:142