338static inline int parseArguments(
const QStringList &arguments, QCommandLineParser *parser,
339 Options *options, QString *errorMessage)
341 using CommandLineOptionPtr = QSharedPointer<QCommandLineOption>;
342 using OptionPtrVector = QList<CommandLineOptionPtr>;
344 parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
345 parser->setApplicationDescription(u"Qt Deploy Tool " QT_VERSION_STR
346 "\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n"
347 "installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n\n"
348 "If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>"_s);
349 const QCommandLineOption helpOption = parser->addHelpOption();
350 const QCommandLineOption versionOption = parser->addVersionOption();
352 QCommandLineOption dirOption(QStringLiteral(
"dir"),
353 QStringLiteral(
"Use directory instead of binary directory."),
354 QStringLiteral(
"directory"));
355 parser->addOption(dirOption);
358 parser->addOption(createQMakeOption());
359 parser->addOption(createQtPathsOption());
361 QCommandLineOption libDirOption(QStringLiteral(
"libdir"),
362 QStringLiteral(
"Copy libraries to path."),
363 QStringLiteral(
"path"));
364 parser->addOption(libDirOption);
366 QCommandLineOption pluginDirOption(QStringLiteral(
"plugindir"),
367 QStringLiteral(
"Copy plugins to path."),
368 QStringLiteral(
"path"));
369 parser->addOption(pluginDirOption);
371 const QCommandLineOption translationDirOption(
373 u"Copy translations to path."_s,
375 parser->addOption(translationDirOption);
377 QCommandLineOption qmlDeployDirOption(QStringLiteral(
"qml-deploy-dir"),
378 QStringLiteral(
"Copy qml files to path."),
379 QStringLiteral(
"path"));
380 parser->addOption(qmlDeployDirOption);
382 QCommandLineOption debugOption(QStringLiteral(
"debug"),
383 QStringLiteral(
"Assume debug binaries."));
384 parser->addOption(debugOption);
385 QCommandLineOption releaseOption(QStringLiteral(
"release"),
386 QStringLiteral(
"Assume release binaries."));
387 parser->addOption(releaseOption);
388 QCommandLineOption releaseWithDebugInfoOption(QStringLiteral(
"release-with-debug-info"),
389 QStringLiteral(
"Assume release binaries with debug information."));
390 releaseWithDebugInfoOption.setFlags(QCommandLineOption::HiddenFromHelp);
391 parser->addOption(releaseWithDebugInfoOption);
393 QCommandLineOption deployPdbOption(QStringLiteral(
"pdb"),
394 QStringLiteral(
"Deploy .pdb files (MSVC)."));
395 parser->addOption(deployPdbOption);
397 QCommandLineOption forceOption(QStringLiteral(
"force"),
398 QStringLiteral(
"Force updating files."));
399 parser->addOption(forceOption);
401 QCommandLineOption dryRunOption(QStringLiteral(
"dry-run"),
402 QStringLiteral(
"Simulation mode. Behave normally, but do not copy/update any files."));
403 parser->addOption(dryRunOption);
405 QCommandLineOption noPatchQtOption(QStringLiteral(
"no-patchqt"),
406 QStringLiteral(
"Do not patch the Qt6Core library."));
407 parser->addOption(noPatchQtOption);
409 QCommandLineOption ignoreErrorOption(QStringLiteral(
"ignore-library-errors"),
410 QStringLiteral(
"Ignore errors when libraries cannot be found."));
411 parser->addOption(ignoreErrorOption);
413 QCommandLineOption noPluginsOption(QStringLiteral(
"no-plugins"),
414 QStringLiteral(
"Skip plugin deployment."));
415 parser->addOption(noPluginsOption);
417 QCommandLineOption skipPluginTypesOption(QStringLiteral(
"skip-plugin-types"),
418 QStringLiteral(
"A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
419 QStringLiteral(
"plugin types"));
420 parser->addOption(skipPluginTypesOption);
422 QCommandLineOption addPluginTypesOption(QStringLiteral(
"add-plugin-types"),
423 QStringLiteral(
"A comma-separated list of plugin types that will be added to deployment (imageformats,iconengines)"),
424 QStringLiteral(
"plugin types"));
425 parser->addOption(addPluginTypesOption);
427 QCommandLineOption includePluginsOption(QStringLiteral(
"include-plugins"),
428 QStringLiteral(
"A comma-separated list of individual plugins that will be added to deployment (scene2d,qjpeg)"),
429 QStringLiteral(
"plugins"));
430 parser->addOption(includePluginsOption);
432 QCommandLineOption excludePluginsOption(QStringLiteral(
"exclude-plugins"),
433 QStringLiteral(
"A comma-separated list of individual plugins that will not be deployed (qsvg,qpdf)"),
434 QStringLiteral(
"plugins"));
435 parser->addOption(excludePluginsOption);
437 QCommandLineOption noLibraryOption(QStringLiteral(
"no-libraries"),
438 QStringLiteral(
"Skip library deployment."));
439 parser->addOption(noLibraryOption);
441 QCommandLineOption qmlDirOption(QStringLiteral(
"qmldir"),
442 QStringLiteral(
"Scan for QML-imports starting from directory."),
443 QStringLiteral(
"directory"));
444 parser->addOption(qmlDirOption);
446 QCommandLineOption qmlImportOption(QStringLiteral(
"qmlimport"),
447 QStringLiteral(
"Add the given path to the QML module search locations."),
448 QStringLiteral(
"directory"));
449 parser->addOption(qmlImportOption);
451 QCommandLineOption qmlImportTimeoutOption(QStringLiteral(
"qmlimporttimeout"),
452 QStringLiteral(
"Set timeout (in ms for) execution of "
453 "qmlimportscanner."),
454 QStringLiteral(
"timeout"));
455 parser->addOption(qmlImportTimeoutOption);
457 QCommandLineOption noQuickImportOption(QStringLiteral(
"no-quick-import"),
458 QStringLiteral(
"Skip deployment of Qt Quick imports."));
459 parser->addOption(noQuickImportOption);
462 QCommandLineOption translationOption(QStringLiteral(
"translations"),
463 QStringLiteral(
"A comma-separated list of languages to deploy (de,fi)."),
464 QStringLiteral(
"languages"));
465 parser->addOption(translationOption);
467 QCommandLineOption noTranslationOption(QStringLiteral(
"no-translations"),
468 QStringLiteral(
"Skip deployment of translations."));
469 parser->addOption(noTranslationOption);
471 QCommandLineOption noSystemD3DCompilerOption(QStringLiteral(
"no-system-d3d-compiler"),
472 QStringLiteral(
"Skip deployment of the system D3D compiler."));
473 parser->addOption(noSystemD3DCompilerOption);
475 QCommandLineOption noSystemDxcOption(QStringLiteral(
"no-system-dxc-compiler"),
476 QStringLiteral(
"Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
477 parser->addOption(noSystemDxcOption);
480 QCommandLineOption compilerRunTimeOption(QStringLiteral(
"compiler-runtime"),
481 QStringLiteral(
"Deploy compiler runtime (Desktop only)."));
482 parser->addOption(compilerRunTimeOption);
484 QCommandLineOption noCompilerRunTimeOption(QStringLiteral(
"no-compiler-runtime"),
485 QStringLiteral(
"Do not deploy compiler runtime (Desktop only)."));
486 parser->addOption(noCompilerRunTimeOption);
488 QCommandLineOption jsonOption(QStringLiteral(
"json"),
489 QStringLiteral(
"Print to stdout in JSON format."));
490 parser->addOption(jsonOption);
492 QCommandLineOption suppressSoftwareRasterizerOption(QStringLiteral(
"no-opengl-sw"),
493 QStringLiteral(
"Do not deploy the software rasterizer library."));
494 parser->addOption(suppressSoftwareRasterizerOption);
496 QCommandLineOption noFFmpegOption(QStringLiteral(
"no-ffmpeg"),
497 QStringLiteral(
"Do not deploy the FFmpeg libraries."));
498 parser->addOption(noFFmpegOption);
500 QCommandLineOption noThirdPartyLibrariesOption(
501 QStringLiteral(
"no-third-party-libraries"),
502 QStringLiteral(
"Do not deploy the non-Qt libraries from the Qt binary directory "
503 "that the deployed binaries link against."));
504 parser->addOption(noThirdPartyLibrariesOption);
506 QCommandLineOption forceOpenSslOption(QStringLiteral(
"force-openssl"),
507 QStringLiteral(
"Deploy openssl plugin but ignore openssl library dependency"));
508 parser->addOption(forceOpenSslOption);
510 QCommandLineOption openSslRootOption(QStringLiteral(
"openssl-root"),
511 QStringLiteral(
"Directory containing openSSL libraries."),
512 QStringLiteral(
"directory"));
513 parser->addOption(openSslRootOption);
516 QCommandLineOption listOption(QStringLiteral(
"list"),
517 "Print only the names of the files copied.\n"
518 "Available options:\n"
519 " source: absolute path of the source files\n"
520 " target: absolute path of the target files\n"
521 " relative: paths of the target files, relative\n"
522 " to the target directory\n"
523 " mapping: outputs the source and the relative\n"
524 " target, suitable for use within an\n"
525 " Appx mapping file"_L1,
526 QStringLiteral(
"option"));
527 parser->addOption(listOption);
529 QCommandLineOption appxOption(QStringLiteral(
"appx"),
530 QStringLiteral(
"Create an appx package for the Windows Store"));
531 parser->addOption(appxOption);
533 QCommandLineOption appxCertificatePath(QStringLiteral(
"appx-certificate"),
534 QStringLiteral(
"Path to appx certificate to sign appx package"),
535 QStringLiteral(
".cer file"));
536 parser->addOption(appxCertificatePath);
539 parser->addOption(createVerboseOption());
541 parser->addPositionalArgument(QStringLiteral(
"[files]"),
542 QStringLiteral(
"Binaries or directory containing the binary."));
544 QCommandLineOption deployInsightTrackerOption(QStringLiteral(
"deploy-insighttracker"),
545 QStringLiteral(
"Deploy insight tracker plugin."));
547 bool insightTrackerModuleAvailable =
false;
549 OptionPtrVector enabledModuleOptions;
550 OptionPtrVector disabledModuleOptions;
552 enabledModuleOptions.reserve(qtModulesCount);
553 disabledModuleOptions.reserve(qtModulesCount);
554 for (
const QtModule &module : qtModuleEntries) {
555 const QString option = moduleNameToOptionName(module.name, module.internal);
556 const QString name = module.name;
557 if (name == u"InsightTracker") {
558 parser->addOption(deployInsightTrackerOption);
559 insightTrackerModuleAvailable =
true;
561 const QString enabledDescription = QStringLiteral(
"Add ") + name + QStringLiteral(
" module.");
562 CommandLineOptionPtr enabledOption(
new QCommandLineOption(option, enabledDescription));
563 parser->addOption(*enabledOption.data());
564 enabledModuleOptions.append(enabledOption);
565 const QString disabledDescription = QStringLiteral(
"Remove ") + name + QStringLiteral(
" module.");
566 CommandLineOptionPtr disabledOption(
new QCommandLineOption(QStringLiteral(
"no-") + option,
567 disabledDescription));
568 disabledModuleOptions.append(disabledOption);
569 parser->addOption(*disabledOption.data());
572 const bool success = parser->parse(arguments);
573 if (parser->isSet(helpOption))
575 if (parser->isSet(versionOption))
578 *errorMessage = parser->errorText();
582 options->libraryDirectory = parser->value(libDirOption);
583 options->pluginDirectory = parser->value(pluginDirOption);
584 options->translationsDirectory = parser->value(translationDirOption);
585 options->qmlDirectory = parser->value(qmlDeployDirOption);
586 options
->plugins = !parser->isSet(noPluginsOption);
587 options
->libraries = !parser->isSet(noLibraryOption);
589 if (parser->isSet(translationOption))
590 options->languages = parser->value(translationOption).split(u',');
592 options
->systemDxc = !parser->isSet(noSystemDxcOption);
596 if (!parser->isSet(appxCertificatePath)) {
597 *errorMessage = QStringLiteral(
"--appx requires --appx-certificate with a valid certificate");
600 options->appxCertificatePath = parser->value(appxCertificatePath);
605 || options->platform.testFlags(
WindowsDesktopMsvc) || parser->isSet(compilerRunTimeOption))
607 if (parser->isSet(noCompilerRunTimeOption))
613 *errorMessage = QStringLiteral(
"Deployment of the compiler runtime is implemented for "
614 "Desktop MSVC and MinGW (g++ and Clang) only.");
618 if (parser->isSet(skipPluginTypesOption))
619 options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
621 if (parser->isSet(addPluginTypesOption))
622 options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
624 if (parser->isSet(includePluginsOption))
625 options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
627 if (parser->isSet(excludePluginsOption))
628 options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
630 if (parser->isSet(releaseWithDebugInfoOption))
631 std::wcerr <<
"Warning: " << releaseWithDebugInfoOption.names().first() <<
" is obsolete.";
633 switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
644 if (parser->isSet(deployPdbOption)) {
645 if (options->platform.testFlag(
WindowsBased) && !options->platform.testFlag(
MinGW))
648 std::wcerr <<
"Warning: --" << deployPdbOption.names().first() <<
" is not supported on this platform.\n";
651 if (parser->isSet(suppressSoftwareRasterizerOption))
654 if (parser->isSet(noFFmpegOption))
657 if (parser->isSet(noThirdPartyLibrariesOption))
660 if (parser->isSet(forceOpenSslOption))
663 if (parser->isSet(openSslRootOption))
664 options->openSslRootDirectory = parser->value(openSslRootOption);
667 *errorMessage = QStringLiteral(
"force-openssl and openssl-root are mutually exclusive");
671 if (parser->isSet(forceOption))
673 if (parser->isSet(dryRunOption)) {
678 options
->patchQt = !parser->isSet(noPatchQtOption);
680 if (insightTrackerModuleAvailable)
683 for (
const QtModule &module : qtModuleEntries) {
684 if (parser->isSet(*enabledModuleOptions.at(module.id)))
685 options->additionalLibraries[module.id] = 1;
686 if (parser->isSet(*disabledModuleOptions.at(module.id)))
687 options->disabledLibraries[module.id] = 1;
691 if (options->additionalLibraries.test(QtQuickModuleId))
692 options->additionalLibraries[QtQmlModuleId] = 1;
693 if (options->additionalLibraries.test(QtDesignerComponentsModuleId))
694 options->additionalLibraries[QtDesignerModuleId] = 1;
696 if (parser->isSet(listOption)) {
697 const QString value = parser->value(listOption);
698 if (value == QStringLiteral(
"source")) {
699 options->list = ListSource;
700 }
else if (value == QStringLiteral(
"target")) {
701 options->list = ListTarget;
702 }
else if (value == QStringLiteral(
"relative")) {
703 options->list = ListRelative;
704 }
else if (value == QStringLiteral(
"mapping")) {
705 options->list = ListMapping;
707 *errorMessage = QStringLiteral(
"Please specify a valid option for -list (source, target, relative, mapping).");
712 if (parser->isSet(jsonOption) || options->list) {
717 const QStringList posArgs = parser->positionalArguments();
718 if (posArgs.isEmpty()) {
719 *errorMessage = QStringLiteral(
"Please specify the binary or folder.");
723 if (parser->isSet(dirOption))
724 options->directory = parser->value(dirOption);
726 if (parser->isSet(qmlDirOption))
727 options->qmlDirectories = parser->values(qmlDirOption);
729 if (parser->isSet(qmlImportOption))
730 options->qmlImportPaths = parser->values(qmlImportOption);
732 if (parser->isSet(qmlImportTimeoutOption)) {
733 const QString timeoutString = parser->value(qmlImportTimeoutOption);
735 int timeout = timeoutString.toInt(&ok);
737 *errorMessage = u'"' + timeoutString + QStringLiteral(
"\" is not an acceptable timeout "
744 const QString &file = posArgs.front();
745 const QFileInfo fi(QDir::cleanPath(file));
747 *errorMessage = msgFileDoesNotExist(file);
751 if (!options->directory.isEmpty() && !fi.isFile()) {
752 *errorMessage = u'"' + file + QStringLiteral(
"\" is not an executable file.");
757 options->binaries.append(fi.absoluteFilePath());
758 if (options->directory.isEmpty())
759 options->directory = fi.absolutePath();
761 const QString binary = findBinary(fi.absoluteFilePath(), options->platform);
762 if (binary.isEmpty()) {
763 *errorMessage = QStringLiteral(
"Unable to find binary in \"") + file + u'"';
766 options->directory = fi.absoluteFilePath();
767 options->binaries.append(binary);
771 bool multipleDirs =
false;
772 for (
int i = 1; i < posArgs.size(); ++i) {
773 const QFileInfo fi(QDir::cleanPath(posArgs.at(i)));
774 const QString path = fi.absoluteFilePath();
776 *errorMessage = msgFileDoesNotExist(path);
780 const QStringList libraries =
781 findSharedLibraries(QDir(path), options->platform, MatchDebugOrRelease, QString());
782 for (
const QString &library : libraries)
783 options->binaries.append(path + u'/' + library);
785 if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
787 options->binaries.append(path);
791 std::wcerr <<
"Warning: using binaries from different directories, deploying to following path: "
792 << options->directory <<
'\n' <<
"To disable this warning, use the --dir option\n";
794 if (options->translationsDirectory.isEmpty())
795 options->translationsDirectory = options->directory +
"/translations"_L1;
1124 const QString &qtPluginsDirName,
const QString &libraryLocation,
1125 const QString &infix,
DebugMatchMode debugMatchModeIn, Platform platform,
1126 QString *platformPlugin,
bool deployInsightTrackerPlugin,
1127 bool deployOpenSslPlugin)
1129 if (qtPluginsDirName.isEmpty())
1130 return QStringList();
1131 QDir pluginsDir(qtPluginsDirName);
1133 bool missingQtModulesAdded =
false;
1134 const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
1135 for (
const QFileInfo &subDirFi : pluginDirs) {
1136 const QString subDirName = subDirFi.fileName();
1137 const size_t module = qtModuleEntries.moduleIdForPluginType(subDirName);
1138 if (module == QtModule::InvalidId) {
1139 if (optVerboseLevel > 1) {
1140 std::wcerr <<
"No Qt module found for plugin type \"" << subDirName <<
"\".\n";
1144 const bool dueToModule = usedQtModules->test(module);
1145 if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
1146 const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
1147 ? MatchDebugOrRelease
1149 QDir subDir(subDirFi.absoluteFilePath());
1150 if (optVerboseLevel)
1151 std::wcout <<
"Adding in plugin type " << subDirFi.baseName() <<
" for module: " << qtModuleEntries.moduleById(module).name <<
'\n';
1153 const bool isPlatformPlugin = subDirName ==
"platforms"_L1;
1154 const QStringList plugins =
1155 findSharedLibraries(subDir, platform, debugMatchMode, QString());
1156 for (
const QString &plugin : plugins) {
1157 ModuleBitset pluginNeededQtModules;
1158 const QString pluginPath =
1159 deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
1160 disabledQtModules, pluginSelections, libraryLocation, infix,
1161 platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
1162 if (!pluginPath.isEmpty()) {
1163 if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
1164 *platformPlugin = subDir.absoluteFilePath(plugin);
1165 result.append(pluginPath);
1167 const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
1168 if (missingModules.any()) {
1169 *usedQtModules |= missingModules;
1170 missingQtModulesAdded =
true;
1171 if (optVerboseLevel) {
1172 std::wcout <<
"Adding " << formatQtModules(missingModules).constData()
1173 <<
" for " << plugin <<
" from plugin type: " << subDirName <<
'\n';
1183 if (missingQtModulesAdded) {
1185 std::wcout <<
"Performing additional pass of finding Qt plugins due to updated Qt module list: "
1186 << formatQtModules(*usedQtModules).constData() <<
"\n";
1188 return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
1189 libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
1190 deployInsightTrackerPlugin, deployOpenSslPlugin);
1621 const QChar slash = u'/';
1623 const QString qtBinDir = qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_BINS"));
1624 const QString libraryLocation = qtBinDir;
1625 const QString infix = qtpathsVariables.value(QLatin1StringView(
qmakeInfixKey));
1626 const int version = qtVersion(qtpathsVariables);
1629 if (optVerboseLevel > 1)
1630 std::wcout <<
"Qt binaries in " << QDir::toNativeSeparators(qtBinDir) <<
'\n';
1632 QStringList dependentQtLibs;
1633 QStringList dependentNonQtLibs;
1634 PeHeaderInfoStruct peHeaderInfo;
1636 if (!readPeExecutableInfo(options.binaries.first(), errorMessage, &peHeaderInfo))
1638 if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform,
1639 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1642 for (
int b = 1; b < options.binaries.size(); ++b) {
1643 if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform,
1644 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1649 const QFileInfo fi(options.binaries.first());
1650 const QString canonicalBinPath = fi.canonicalPath();
1653 for (qsizetype i = 0; i < dependentNonQtLibs.size(); ++i) {
1654 const QString nonQtLib = dependentNonQtLibs.at(i);
1655 const QString path = canonicalBinPath + u'/' + nonQtLib;
1656 if (!QFileInfo::exists(path))
1660 std::wcout <<
"Adding local dependency" << path <<
'\n';
1662 if (!findDependentQtLibraries(libraryLocation, path, options.platform,
1663 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1675 if (options.platform.testFlag(
Msvc) || options.platform.testFlag(
ClangMsvc)) {
1676 result
.isDebug = peHeaderInfo.isDebug;
1691 for (
int m = 0; m < dependentQtLibs.size(); ++m) {
1692 const qint64 module = qtModule(dependentQtLibs.at(m), infix);
1694 result.directlyUsedQtLibraries[module] = 1;
1697 const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
1698 const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModuleId);
1699 const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModuleId);
1700 const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModuleId))
1701 && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModuleId)));
1704 std::wcout << QDir::toNativeSeparators(options.binaries.first()) <<
' '
1705 << peHeaderInfo.wordSize <<
" bit, " << (result.isDebug ?
"debug" :
"release")
1708 std::wcout <<
" [QML]";
1712 if (dependentQtLibs.isEmpty()) {
1713 *errorMessage = QDir::toNativeSeparators(options.binaries.first()) + QStringLiteral(
" does not seem to be a Qt executable.");
1721 QStringList qmlImportPaths = options.qmlImportPaths;
1723 qmlImportPaths << qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_QML"));
1724 QStringList qmlDirectories = options.qmlDirectories;
1725 if (qmlDirectories.isEmpty()) {
1726 const QString qmlDirectory = findQmlDirectory(options.platform, options.directory);
1727 if (!qmlDirectory.isEmpty())
1728 qmlDirectories.append(qmlDirectory);
1730 for (
const QString &qmlDirectory : std::as_const(qmlDirectories)) {
1731 if (optVerboseLevel >= 1)
1732 std::wcout <<
"Scanning " << QDir::toNativeSeparators(qmlDirectory) <<
":\n";
1733 const QmlImportScanResult scanResult =
1734 runQmlImportScanner(qmlDirectory, qmlImportPaths,
1735 result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
1736 options.platform, debugMatchMode, errorMessage,
1737 options.qmlImportTimeout);
1740 qmlScanResult.append(scanResult);
1742 for (
const QString &plugin : std::as_const(qmlScanResult.plugins)) {
1743 if (!findDependentQtLibraries(libraryLocation, plugin, options.platform,
1744 errorMessage, &dependentQtLibs,
nullptr)) {
1748 if (optVerboseLevel >= 1) {
1749 std::wcout <<
"QML imports:\n";
1750 for (
const QmlImportScanResult::Module &mod : std::as_const(qmlScanResult.modules)) {
1751 std::wcout <<
" '" << mod.name <<
"' "
1752 << QDir::toNativeSeparators(mod.sourcePath) <<
'\n';
1754 if (optVerboseLevel >= 2) {
1755 std::wcout <<
"QML plugins:\n";
1756 for (
const QString &p : std::as_const(qmlScanResult.plugins))
1757 std::wcout <<
" " << QDir::toNativeSeparators(p) <<
'\n';
1763 QString platformPlugin;
1766 QStringList deployedQtLibraries;
1767 for (
int i = 0 ; i < dependentQtLibs.size(); ++i) {
1768 const qint64 module = qtModule(dependentQtLibs.at(i), infix);
1770 result.usedQtLibraries[module] = 1;
1772 deployedQtLibraries.push_back(dependentQtLibs.at(i));
1774 result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
1776 ModuleBitset disabled = options.disabledLibraries;
1778 disabled[QtQmlModuleId] = 1;
1779 disabled[QtQuickModuleId] = 1;
1785 const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral(
"Qt6Core"), Qt::CaseInsensitive)
1786 + dependentQtLibs.filter(QStringLiteral(
"Qt5WebKit"), Qt::CaseInsensitive);
1787 for (
const QString &qtLib : qtLibs) {
1788 QStringList icuLibs = findDependentLibraries(qtLib, errorMessage).filter(QStringLiteral(
"ICU"), Qt::CaseInsensitive);
1789 if (!icuLibs.isEmpty()) {
1792 const QString icuVersion = getIcuVersion(icuLibs.constFirst());
1793 if (!icuVersion.isEmpty()) {
1794 if (optVerboseLevel > 1)
1795 std::wcout <<
"Adding ICU version " << icuVersion <<
'\n';
1796 QString icuLib = QStringLiteral(
"icudt") + icuVersion
1797 + QLatin1StringView(windowsSharedLibrarySuffix);
1800 if (result.isDebug) {
1801 const QString icuLibCandidate = QStringLiteral(
"icudtd") + icuVersion
1802 + QLatin1StringView(windowsSharedLibrarySuffix);
1803 if (!findInPath(icuLibCandidate).isEmpty()) {
1804 icuLib = icuLibCandidate;
1807 icuLibs.push_back(icuLib);
1809 for (
const QString &icuLib : std::as_const(icuLibs)) {
1810 const QString icuPath = findInPath(icuLib);
1811 if (icuPath.isEmpty()) {
1812 *errorMessage = QStringLiteral(
"Unable to locate ICU library ") + icuLib;
1815 deployedQtLibraries.push_back(icuPath);
1822 QStringList openSslLibs;
1823 if (!options.openSslRootDirectory.isEmpty()) {
1824 openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
1825 if (openSslLibs.isEmpty()) {
1826 *errorMessage = QStringLiteral(
"Unable to find openSSL libraries in ")
1827 + options.openSslRootDirectory;
1831 deployedQtLibraries.append(openSslLibs);
1835 const QStringList plugins = findQtPlugins(
1836 &result.deployedQtLibraries,
1839 disabled, pluginInfo,
1840 options.pluginSelections, qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_PLUGINS")),
1841 libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
1842 options.deployInsightTrackerPlugin, deployOpenSslPlugin);
1845 QString qtGuiLibrary;
1846 for (
const auto &qtModule : qtModuleEntries) {
1847 if (result.deployedQtLibraries.test(qtModule.id)) {
1848 const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
1849 options.platform, result.isDebug);
1850 deployedQtLibraries.append(library);
1851 if (qtModule.id == QtGuiModuleId)
1852 qtGuiLibrary = library;
1857 std::wcout <<
"Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData()
1858 <<
"\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData()
1859 <<
"\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() <<
'\n';
1863 std::wcout <<
"Plugins: " << plugins.join(u',') <<
'\n';
1865 if (result.deployedQtLibraries.test(QtGuiModuleId) && platformPlugin.isEmpty()) {
1866 *errorMessage =QStringLiteral(
"Unable to find the platform plugin.");
1870 if (options.platform.testFlag(
WindowsBased) && !qtGuiLibrary.isEmpty()) {
1871 const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
1872 const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral(
"opengl32"), Qt::CaseInsensitive).isEmpty();
1874 const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral(
"opengl32sw") + QLatin1StringView(
windowsSharedLibrarySuffix));
1875 if (softwareRasterizer.isFile())
1876 deployedQtLibraries.append(softwareRasterizer.absoluteFilePath());
1879 const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir,
1880 peHeaderInfo.wordSize);
1881 if (d3dCompiler.isEmpty()) {
1882 std::wcerr <<
"Warning: Cannot find any version of the d3dcompiler DLL.\n";
1884 deployedQtLibraries.push_back(d3dCompiler);
1888 const QStringList dxcLibs = findDxc(options.platform, qtBinDir,
1889 peHeaderInfo.wordSize);
1890 if (!dxcLibs.isEmpty()) {
1891 deployedQtLibraries.append(dxcLibs);
1893 std::wcerr <<
"Warning: Cannot find any version of the dxcompiler.dll and dxil.dll."
1894 <<
" This is not a problem unless Direct3D 12 and certain features are used by the application.\n";
1901 && !plugins.filter(QStringLiteral(
"ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
1902 deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
1908 QStringList scanned = options.binaries + deployedQtLibraries;
1912 scanned += qmlScanResult.plugins;
1915 QSet<QString> excludedFileNames;
1916 for (
const QString &lib : std::as_const(deployedQtLibraries))
1917 excludedFileNames.insert(QFileInfo(lib).fileName().toLower());
1918 for (
const QString &lib : compilerRunTimeLibsInQtBinDir(qtBinDir, options.platform))
1919 excludedFileNames.insert(lib.toLower());
1921 QStringList thirdPartyLibraries;
1922 if (!findThirdPartyDependencies(qtBinDir, scanned, !options.ffmpeg, excludedFileNames,
1923 &thirdPartyLibraries, errorMessage)) {
1926 deployedQtLibraries += thirdPartyLibraries;
1931 const QString targetPath = options.libraryDirectory.isEmpty() ?
1932 options.directory : options.libraryDirectory;
1933 QStringList libraries = deployedQtLibraries;
1935 libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug,
1936 peHeaderInfo.machineArch));
1938 for (
const QString &qtLib : std::as_const(libraries)) {
1939 if (isSystemLibrary(qtLib)) {
1940 if (optVerboseLevel)
1941 std::wcout <<
"Skipping system library " << qtLib <<
"\n";
1944 if (!updateLibrary(qtLib, targetPath, options, errorMessage))
1948#if !QT_CONFIG(relocatable)
1949 if (options.patchQt && !options.dryRun) {
1950 const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation,
"Qt6Core", infix,
1951 options.platform, result.isDebug)).fileName();
1952 if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
1953 std::wcerr <<
"Warning: " << *errorMessage <<
'\n';
1954 errorMessage->clear();
1962 const QString targetPath = options.pluginDirectory.isEmpty() ?
1963 options.directory : options.pluginDirectory;
1964 QDir dir(targetPath);
1965 if (!dir.exists() && !dir.mkpath(QStringLiteral(
"."))) {
1966 *errorMessage =
"Cannot create "_L1 +
1967 QDir::toNativeSeparators(dir.absolutePath()) + u'.';
1970 for (
const QString &plugin : plugins) {
1971 const QString targetDirName = plugin.section(slash, -2, -2);
1972 const QString targetPath = dir.absoluteFilePath(targetDirName);
1973 if (!dir.exists(targetDirName)) {
1974 if (optVerboseLevel)
1975 std::wcout <<
"Creating directory " << targetPath <<
".\n";
1976 if (!(options.updateFileFlags & SkipUpdateFile) && !dir.mkdir(targetDirName)) {
1977 *errorMessage = QStringLiteral(
"Cannot create ") + targetDirName + u'.';
1981 if (!updateLibrary(plugin, targetPath, options, errorMessage))
1990 const QString targetPath = options.qmlDirectory.isEmpty()
1991 ? options.directory + QStringLiteral(
"/qml")
1992 : options.qmlDirectory;
1993 if (!createDirectory(targetPath, errorMessage, options.dryRun))
1995 for (
const QmlImportScanResult::Module &module : std::as_const(qmlScanResult.modules)) {
1996 const QString installPath = module.installPath(targetPath);
1997 if (optVerboseLevel > 1)
1998 std::wcout <<
"Installing: '" << module.name
1999 <<
"' from " << module.sourcePath <<
" to "
2000 << QDir::toNativeSeparators(installPath) <<
'\n';
2001 if (installPath != targetPath && !createDirectory(installPath, errorMessage, options.dryRun))
2003 unsigned updateFileFlags = options.updateFileFlags
2004 | SkipQmlDesignerSpecificsDirectories;
2005 unsigned qmlDirectoryFileFlags = 0;
2006 if (options.deployPdb)
2007 qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
2008 if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
2011 qmlDirectoryFileFlags),
2012 installPath, updateFileFlags, options.json, errorMessage)) {
2019 const QString &catalogsError =
qtModuleEntries.translationCatalogsError();
2020 if (catalogsError.isEmpty()) {
2021 if (!createDirectory(options.translationsDirectory, errorMessage, options.dryRun))
2023 if (!deployTranslations(qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_TRANSLATIONS")),
2024 result.deployedQtLibraries, options.translationsDirectory,
2025 options, errorMessage)) {
2029 std::wcerr <<
"Warning: Translations will not be deployed due to the following error."
2030 <<
std::endl << catalogsError <<
std::endl;
2061 bool isDebug, QString *errorMessage)
2063 static const char *installDataFilesRelease[] = {
2064 "icudtl.dat",
"qtwebengine_devtools_resources.pak",
"qtwebengine_resources.pak",
2065 "qtwebengine_resources_100p.pak",
"qtwebengine_resources_200p.pak"
2067 static const char *installDataFilesDebug[] = {
2068 "icudtl.dat",
"qtwebengine_devtools_resources.debug.pak",
"qtwebengine_resources.debug.pak",
2069 "qtwebengine_resources_100p.debug.pak",
"qtwebengine_resources_200p.debug.pak"
2071 static const auto &installDataFiles = isDebug ? installDataFilesDebug : installDataFilesRelease;
2072 static const auto installV8SnapshotFile =
2073 isDebug ?
"v8_context_snapshot.debug.bin" :
"v8_context_snapshot.bin";
2076 if (isDebug && platformHasDebugSuffix(options.platform))
2077 webEngineProcessName.append(
'd');
2079 std::wcout <<
"Deploying: " << webEngineProcessName.constData() <<
"...\n";
2080 if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
2082 const QString resourcesSubDir = QStringLiteral(
"/resources");
2083 const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_DATA"))
2084 + resourcesSubDir + u'/';
2085 const QString resourcesTargetDir(options.directory + resourcesSubDir);
2086 if (!createDirectory(resourcesTargetDir, errorMessage, options.dryRun))
2088 for (
auto installDataFile : installDataFiles) {
2089 if (!updateFile(resourcesSourceDir + QLatin1StringView(installDataFile),
2090 resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) {
2095 updateFile(resourcesSourceDir + QLatin1StringView(installV8SnapshotFile), resourcesTargetDir,
2097 errorMessage->clear();
2098 const QFileInfo translations(qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_TRANSLATIONS"))
2099 + QStringLiteral(
"/qtwebengine_locales"));
2100 if (!translations.isDir()) {
2101 std::wcerr <<
"Warning: Cannot find the translation files of the QtWebEngine module at "
2102 << QDir::toNativeSeparators(translations.absoluteFilePath()) <<
".\n";
2107 return createDirectory(options.translationsDirectory, errorMessage, options.dryRun)
2108 && updateFile(translations.absoluteFilePath(), options.translationsDirectory,
2109 options.updateFileFlags, options.json, errorMessage);
2112 const QFileInfo enUSpak(translations.filePath() + QStringLiteral(
"/en-US.pak"));
2113 if (!enUSpak.exists()) {
2114 std::wcerr <<
"Warning: Cannot find "
2115 << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) <<
".\n";
2118 const QString webEngineTranslationsDir = options.translationsDirectory + u'/'
2119 + translations.fileName();
2120 if (!createDirectory(webEngineTranslationsDir, errorMessage, options.dryRun))
2122 return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir,
2123 options.updateFileFlags, options.json, errorMessage);
2132 QCoreApplication a(argc, argv);
2133 QCoreApplication::setApplicationVersion(QT_VERSION_STR
""_L1);
2135 const QByteArray qtBinPath = QFile::encodeName(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
2136 QByteArray path = qgetenv(
"PATH");
2137 if (!path.contains(qtBinPath)) {
2138 path.prepend(QDir::listSeparator().toLatin1());
2139 path.prepend(qtBinPath);
2140 qputenv(
"PATH", path);
2144 QString errorMessage;
2149 int result = parseEarlyArguments(QCoreApplication::arguments(), &options, &errorMessage);
2151 std::wcerr <<
"Error: " << errorMessage <<
"\n";
2156 const QMap<QString, QString> qtpathsVariables =
2157 queryQtPaths(options.qtpathsBinary, &errorMessage);
2158 const QString xSpec = qtpathsVariables.value(QStringLiteral(
"QMAKE_XSPEC"));
2159 if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
2160 || !qtpathsVariables.contains(QStringLiteral(
"QT_INSTALL_BINS"))) {
2161 std::wcerr <<
"Unable to query qtpaths: " << errorMessage <<
'\n';
2165 options.platform = platformFromMkSpec(xSpec);
2170 switch (si.wProcessorArchitecture) {
2171 case PROCESSOR_ARCHITECTURE_INTEL:
2172 case PROCESSOR_ARCHITECTURE_IA64:
2173 case PROCESSOR_ARCHITECTURE_AMD64:
2176 case PROCESSOR_ARCHITECTURE_ARM:
2177 case PROCESSOR_ARCHITECTURE_ARM64:
2185 std::wcerr <<
"Unsupported platform " << xSpec <<
'\n';
2190 const QString modulesDir
2191 = qtpathsVariables.value(QLatin1String(
"QT_INSTALL_ARCHDATA"))
2192 + QLatin1String(
"/modules");
2193 const QString translationsDir
2194 = qtpathsVariables.value(QLatin1String(
"QT_INSTALL_TRANSLATIONS"));
2197 std::wcerr <<
"Error: " << errorMessage <<
"\n";
2204 pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
2208 QCommandLineParser parser;
2209 QString errorMessage;
2210 const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
2212 std::wcerr << errorMessage <<
"\n\n";
2214 std::fputs(QT_VERSION_STR
"\n", stdout);
2218 std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
2226 if (!createDirectory(options.directory, &errorMessage, options.dryRun)) {
2227 std::wcerr << errorMessage <<
'\n';
2230 if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory
2231 && !createDirectory(options.libraryDirectory, &errorMessage, options.dryRun)) {
2232 std::wcerr << errorMessage <<
'\n';
2236 const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
2238 std::wcerr << errorMessage <<
'\n';
2242 if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
2243 if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
2245 std::wcerr << errorMessage <<
'\n';
2250 if (options
.createAppx && !options.appxCertificatePath.isEmpty()) {
2251 const QFileInfo storeLogo(options.directory + QStringLiteral(
"/Assets/StoreLogo.png"));
2252 if (!storeLogo.exists()) {
2253 std::wcerr <<
"Error: Could not open application logo file " << storeLogo.absoluteFilePath() <<
'\n';
2257 QFile certFile(options.appxCertificatePath);
2258 if (!certFile.open(QIODevice::ReadOnly)) {
2259 std::wcerr <<
"Could not open certificate file" <<
'\n';
2263 QSslCertificate cert(&certFile, QSsl::Der);
2264 QString publisher = cert.subjectDisplayName();
2266 const QString applicationName = QFileInfo(options.binaries.first()).baseName();
2267 const QString platform = options.platform.testFlag(
PlatformFlag::IntelBased) ? QStringLiteral(
"x64") : QStringLiteral(
"arm64");
2268 const QString appxFilePath(options.directory + QStringLiteral(
"/") + QStringLiteral(
"AppxManifest.xml"));
2269 QFile f(appxFilePath);
2270 if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
2271 std::wcerr <<
"Could not create AppxManifest.xml" <<
'\n';
2275 QXmlStreamWriter manifestWriter(&f);
2276 manifestWriter.setAutoFormatting(
true);
2277 manifestWriter.writeStartDocument();
2278 manifestWriter.writeStartElement(QStringLiteral(
"Package"));
2279 manifestWriter.writeAttribute(QStringLiteral(
"xmlns"), QStringLiteral(
"http://schemas.microsoft.com/appx/manifest/foundation/windows10"));
2280 manifestWriter.writeAttribute(QStringLiteral(
"xmlns:uap"), QStringLiteral(
"http://schemas.microsoft.com/appx/manifest/uap/windows10"));
2281 manifestWriter.writeAttribute(QStringLiteral(
"xmlns:rescap"), QStringLiteral(
"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"));
2283 manifestWriter.writeStartElement(QStringLiteral(
"Identity"));
2284 manifestWriter.writeAttribute(
"Name", QUuid::createUuid().toString(QUuid::WithoutBraces));
2285 manifestWriter.writeAttribute(
"Publisher", QStringLiteral(
"CN=") + publisher);
2286 manifestWriter.writeAttribute(
"Version",
"1.0.0.0");
2287 manifestWriter.writeAttribute(
"ProcessorArchitecture", platform);
2288 manifestWriter.writeEndElement();
2290 manifestWriter.writeStartElement(
"Properties");
2291 manifestWriter.writeStartElement(
"DisplayName");
2292 manifestWriter.writeCharacters(applicationName);
2293 manifestWriter.writeEndElement();
2294 manifestWriter.writeStartElement(
"PublisherDisplayName");
2295 manifestWriter.writeCharacters(publisher);
2296 manifestWriter.writeEndElement();
2297 manifestWriter.writeStartElement(
"Logo");
2298 manifestWriter.writeCharacters(
"Assets/StoreLogo.png");
2299 manifestWriter.writeEndElement();
2300 manifestWriter.writeEndElement();
2302 manifestWriter.writeStartElement(
"Dependencies");
2303 manifestWriter.writeStartElement(
"TargetDeviceFamily");
2304 manifestWriter.writeAttribute(
"Name",
"Windows.Desktop");
2305 manifestWriter.writeAttribute(
"MinVersion",
"10.0.14316.0");
2306 manifestWriter.writeAttribute(
"MaxVersionTested",
"10.0.14316.0");
2307 manifestWriter.writeEndElement();
2308 manifestWriter.writeEndElement();
2310 manifestWriter.writeStartElement(
"Capabilities");
2311 manifestWriter.writeStartElement(
"rescap:Capability");
2312 manifestWriter.writeAttribute(
"Name",
"runFullTrust");
2313 manifestWriter.writeEndElement();
2314 manifestWriter.writeEndElement();
2316 manifestWriter.writeStartElement(
"Resources");
2317 manifestWriter.writeStartElement(
"Resource");
2318 if (options.languages.isEmpty()) {
2319 QLocale locale = QLocale::system();
2320 manifestWriter.writeAttribute(
"Language", locale.bcp47Name());
2322 for (
const auto& language : options.languages) {
2323 manifestWriter.writeAttribute(
"Language", language);
2326 manifestWriter.writeEndElement();
2327 manifestWriter.writeEndElement();
2329 manifestWriter.writeStartElement(
"Applications");
2330 for (
const auto& binary : options.binaries) {
2331 const QString binaryRelative = binary.split(QStringLiteral(
"/")).last();
2332 const QString displayName = binaryRelative.split(QStringLiteral(
".")).first();
2333 QFile descriptionFile(options.directory + QStringLiteral(
"/") + QStringLiteral(
"Assets/Description_") + displayName + QStringLiteral(
".txt"));
2334 QString description;
2335 if (!descriptionFile.exists())
2336 std::wcerr <<
"Warning: No package description was provided " << descriptionFile.fileName() <<
'\n';
2337 if (descriptionFile.open(QIODevice::ReadOnly | QIODevice::Text))
2338 description = QString::fromUtf8(descriptionFile.readAll());
2340 manifestWriter.writeStartElement(
"Application");
2341 manifestWriter.writeAttribute(
"Id", displayName);
2342 manifestWriter.writeAttribute(
"Executable", binaryRelative);
2343 manifestWriter.writeAttribute(
"EntryPoint",
"Windows.FullTrustApplication");
2344 manifestWriter.writeStartElement(
"uap:VisualElements");
2345 manifestWriter.writeAttribute(
"DisplayName", displayName);
2346 manifestWriter.writeAttribute(
"Description", description);
2347 manifestWriter.writeAttribute(
"BackgroundColor",
"transparent");
2348 manifestWriter.writeAttribute(
"Square150x150Logo",
"Assets/Logo.png");
2349 manifestWriter.writeAttribute(
"Square44x44Logo",
"Assets/SmallLogo.png");
2350 manifestWriter.writeStartElement(
"uap:DefaultTile");
2351 manifestWriter.writeEndElement();
2352 manifestWriter.writeEndElement();
2353 manifestWriter.writeEndElement();
2355 manifestWriter.writeEndElement();
2356 manifestWriter.writeEndElement();
2357 manifestWriter.writeEndDocument();
2362 std::fputs(options
.json->toList(options.list, options.directory).constData(), stdout);
2364 std::fputs(options
.json->toJson().constData(), stdout);
2365 delete options
.json;
2366 options
.json =
nullptr;