335static inline int parseArguments(
const QStringList &arguments, QCommandLineParser *parser,
336 Options *options, QString *errorMessage)
338 using CommandLineOptionPtr = QSharedPointer<QCommandLineOption>;
339 using OptionPtrVector = QList<CommandLineOptionPtr>;
341 parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
342 parser->setApplicationDescription(u"Qt Deploy Tool " QT_VERSION_STR
343 "\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n"
344 "installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n\n"
345 "If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>"_s);
346 const QCommandLineOption helpOption = parser->addHelpOption();
347 const QCommandLineOption versionOption = parser->addVersionOption();
349 QCommandLineOption dirOption(QStringLiteral(
"dir"),
350 QStringLiteral(
"Use directory instead of binary directory."),
351 QStringLiteral(
"directory"));
352 parser->addOption(dirOption);
355 parser->addOption(createQMakeOption());
356 parser->addOption(createQtPathsOption());
358 QCommandLineOption libDirOption(QStringLiteral(
"libdir"),
359 QStringLiteral(
"Copy libraries to path."),
360 QStringLiteral(
"path"));
361 parser->addOption(libDirOption);
363 QCommandLineOption pluginDirOption(QStringLiteral(
"plugindir"),
364 QStringLiteral(
"Copy plugins to path."),
365 QStringLiteral(
"path"));
366 parser->addOption(pluginDirOption);
368 const QCommandLineOption translationDirOption(
370 u"Copy translations to path."_s,
372 parser->addOption(translationDirOption);
374 QCommandLineOption qmlDeployDirOption(QStringLiteral(
"qml-deploy-dir"),
375 QStringLiteral(
"Copy qml files to path."),
376 QStringLiteral(
"path"));
377 parser->addOption(qmlDeployDirOption);
379 QCommandLineOption debugOption(QStringLiteral(
"debug"),
380 QStringLiteral(
"Assume debug binaries."));
381 parser->addOption(debugOption);
382 QCommandLineOption releaseOption(QStringLiteral(
"release"),
383 QStringLiteral(
"Assume release binaries."));
384 parser->addOption(releaseOption);
385 QCommandLineOption releaseWithDebugInfoOption(QStringLiteral(
"release-with-debug-info"),
386 QStringLiteral(
"Assume release binaries with debug information."));
387 releaseWithDebugInfoOption.setFlags(QCommandLineOption::HiddenFromHelp);
388 parser->addOption(releaseWithDebugInfoOption);
390 QCommandLineOption deployPdbOption(QStringLiteral(
"pdb"),
391 QStringLiteral(
"Deploy .pdb files (MSVC)."));
392 parser->addOption(deployPdbOption);
394 QCommandLineOption forceOption(QStringLiteral(
"force"),
395 QStringLiteral(
"Force updating files."));
396 parser->addOption(forceOption);
398 QCommandLineOption dryRunOption(QStringLiteral(
"dry-run"),
399 QStringLiteral(
"Simulation mode. Behave normally, but do not copy/update any files."));
400 parser->addOption(dryRunOption);
402 QCommandLineOption noPatchQtOption(QStringLiteral(
"no-patchqt"),
403 QStringLiteral(
"Do not patch the Qt6Core library."));
404 parser->addOption(noPatchQtOption);
406 QCommandLineOption ignoreErrorOption(QStringLiteral(
"ignore-library-errors"),
407 QStringLiteral(
"Ignore errors when libraries cannot be found."));
408 parser->addOption(ignoreErrorOption);
410 QCommandLineOption noPluginsOption(QStringLiteral(
"no-plugins"),
411 QStringLiteral(
"Skip plugin deployment."));
412 parser->addOption(noPluginsOption);
414 QCommandLineOption skipPluginTypesOption(QStringLiteral(
"skip-plugin-types"),
415 QStringLiteral(
"A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
416 QStringLiteral(
"plugin types"));
417 parser->addOption(skipPluginTypesOption);
419 QCommandLineOption addPluginTypesOption(QStringLiteral(
"add-plugin-types"),
420 QStringLiteral(
"A comma-separated list of plugin types that will be added to deployment (imageformats,iconengines)"),
421 QStringLiteral(
"plugin types"));
422 parser->addOption(addPluginTypesOption);
424 QCommandLineOption includePluginsOption(QStringLiteral(
"include-plugins"),
425 QStringLiteral(
"A comma-separated list of individual plugins that will be added to deployment (scene2d,qjpeg)"),
426 QStringLiteral(
"plugins"));
427 parser->addOption(includePluginsOption);
429 QCommandLineOption excludePluginsOption(QStringLiteral(
"exclude-plugins"),
430 QStringLiteral(
"A comma-separated list of individual plugins that will not be deployed (qsvg,qpdf)"),
431 QStringLiteral(
"plugins"));
432 parser->addOption(excludePluginsOption);
434 QCommandLineOption noLibraryOption(QStringLiteral(
"no-libraries"),
435 QStringLiteral(
"Skip library deployment."));
436 parser->addOption(noLibraryOption);
438 QCommandLineOption qmlDirOption(QStringLiteral(
"qmldir"),
439 QStringLiteral(
"Scan for QML-imports starting from directory."),
440 QStringLiteral(
"directory"));
441 parser->addOption(qmlDirOption);
443 QCommandLineOption qmlImportOption(QStringLiteral(
"qmlimport"),
444 QStringLiteral(
"Add the given path to the QML module search locations."),
445 QStringLiteral(
"directory"));
446 parser->addOption(qmlImportOption);
448 QCommandLineOption qmlImportTimeoutOption(QStringLiteral(
"qmlimporttimeout"),
449 QStringLiteral(
"Set timeout (in ms for) execution of "
450 "qmlimportscanner."),
451 QStringLiteral(
"timeout"));
452 parser->addOption(qmlImportTimeoutOption);
454 QCommandLineOption noQuickImportOption(QStringLiteral(
"no-quick-import"),
455 QStringLiteral(
"Skip deployment of Qt Quick imports."));
456 parser->addOption(noQuickImportOption);
459 QCommandLineOption translationOption(QStringLiteral(
"translations"),
460 QStringLiteral(
"A comma-separated list of languages to deploy (de,fi)."),
461 QStringLiteral(
"languages"));
462 parser->addOption(translationOption);
464 QCommandLineOption noTranslationOption(QStringLiteral(
"no-translations"),
465 QStringLiteral(
"Skip deployment of translations."));
466 parser->addOption(noTranslationOption);
468 QCommandLineOption noSystemD3DCompilerOption(QStringLiteral(
"no-system-d3d-compiler"),
469 QStringLiteral(
"Skip deployment of the system D3D compiler."));
470 parser->addOption(noSystemD3DCompilerOption);
472 QCommandLineOption noSystemDxcOption(QStringLiteral(
"no-system-dxc-compiler"),
473 QStringLiteral(
"Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
474 parser->addOption(noSystemDxcOption);
477 QCommandLineOption compilerRunTimeOption(QStringLiteral(
"compiler-runtime"),
478 QStringLiteral(
"Deploy compiler runtime (Desktop only)."));
479 parser->addOption(compilerRunTimeOption);
481 QCommandLineOption noCompilerRunTimeOption(QStringLiteral(
"no-compiler-runtime"),
482 QStringLiteral(
"Do not deploy compiler runtime (Desktop only)."));
483 parser->addOption(noCompilerRunTimeOption);
485 QCommandLineOption jsonOption(QStringLiteral(
"json"),
486 QStringLiteral(
"Print to stdout in JSON format."));
487 parser->addOption(jsonOption);
489 QCommandLineOption suppressSoftwareRasterizerOption(QStringLiteral(
"no-opengl-sw"),
490 QStringLiteral(
"Do not deploy the software rasterizer library."));
491 parser->addOption(suppressSoftwareRasterizerOption);
493 QCommandLineOption noFFmpegOption(QStringLiteral(
"no-ffmpeg"),
494 QStringLiteral(
"Do not deploy the FFmpeg libraries."));
495 parser->addOption(noFFmpegOption);
497 QCommandLineOption forceOpenSslOption(QStringLiteral(
"force-openssl"),
498 QStringLiteral(
"Deploy openssl plugin but ignore openssl library dependency"));
499 parser->addOption(forceOpenSslOption);
501 QCommandLineOption openSslRootOption(QStringLiteral(
"openssl-root"),
502 QStringLiteral(
"Directory containing openSSL libraries."),
503 QStringLiteral(
"directory"));
504 parser->addOption(openSslRootOption);
507 QCommandLineOption listOption(QStringLiteral(
"list"),
508 "Print only the names of the files copied.\n"
509 "Available options:\n"
510 " source: absolute path of the source files\n"
511 " target: absolute path of the target files\n"
512 " relative: paths of the target files, relative\n"
513 " to the target directory\n"
514 " mapping: outputs the source and the relative\n"
515 " target, suitable for use within an\n"
516 " Appx mapping file"_L1,
517 QStringLiteral(
"option"));
518 parser->addOption(listOption);
520 QCommandLineOption appxOption(QStringLiteral(
"appx"),
521 QStringLiteral(
"Create an appx package for the Windows Store"));
522 parser->addOption(appxOption);
524 QCommandLineOption appxCertificatePath(QStringLiteral(
"appx-certificate"),
525 QStringLiteral(
"Path to appx certificate to sign appx package"),
526 QStringLiteral(
".cer file"));
527 parser->addOption(appxCertificatePath);
530 parser->addOption(createVerboseOption());
532 parser->addPositionalArgument(QStringLiteral(
"[files]"),
533 QStringLiteral(
"Binaries or directory containing the binary."));
535 QCommandLineOption deployInsightTrackerOption(QStringLiteral(
"deploy-insighttracker"),
536 QStringLiteral(
"Deploy insight tracker plugin."));
538 bool insightTrackerModuleAvailable =
false;
540 OptionPtrVector enabledModuleOptions;
541 OptionPtrVector disabledModuleOptions;
543 enabledModuleOptions.reserve(qtModulesCount);
544 disabledModuleOptions.reserve(qtModulesCount);
545 for (
const QtModule &module : qtModuleEntries) {
546 const QString option = moduleNameToOptionName(module.name, module.internal);
547 const QString name = module.name;
548 if (name == u"InsightTracker") {
549 parser->addOption(deployInsightTrackerOption);
550 insightTrackerModuleAvailable =
true;
552 const QString enabledDescription = QStringLiteral(
"Add ") + name + QStringLiteral(
" module.");
553 CommandLineOptionPtr enabledOption(
new QCommandLineOption(option, enabledDescription));
554 parser->addOption(*enabledOption.data());
555 enabledModuleOptions.append(enabledOption);
556 const QString disabledDescription = QStringLiteral(
"Remove ") + name + QStringLiteral(
" module.");
557 CommandLineOptionPtr disabledOption(
new QCommandLineOption(QStringLiteral(
"no-") + option,
558 disabledDescription));
559 disabledModuleOptions.append(disabledOption);
560 parser->addOption(*disabledOption.data());
563 const bool success = parser->parse(arguments);
564 if (parser->isSet(helpOption))
566 if (parser->isSet(versionOption))
569 *errorMessage = parser->errorText();
573 options->libraryDirectory = parser->value(libDirOption);
574 options->pluginDirectory = parser->value(pluginDirOption);
575 options->translationsDirectory = parser->value(translationDirOption);
576 options->qmlDirectory = parser->value(qmlDeployDirOption);
577 options
->plugins = !parser->isSet(noPluginsOption);
578 options
->libraries = !parser->isSet(noLibraryOption);
580 if (parser->isSet(translationOption))
581 options->languages = parser->value(translationOption).split(u',');
583 options
->systemDxc = !parser->isSet(noSystemDxcOption);
587 if (!parser->isSet(appxCertificatePath)) {
588 *errorMessage = QStringLiteral(
"--appx requires --appx-certificate with a valid certificate");
591 options->appxCertificatePath = parser->value(appxCertificatePath);
596 || parser->isSet(compilerRunTimeOption))
598 if (parser->isSet(noCompilerRunTimeOption))
603 *errorMessage = QStringLiteral(
"Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
607 if (parser->isSet(skipPluginTypesOption))
608 options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
610 if (parser->isSet(addPluginTypesOption))
611 options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
613 if (parser->isSet(includePluginsOption))
614 options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
616 if (parser->isSet(excludePluginsOption))
617 options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
619 if (parser->isSet(releaseWithDebugInfoOption))
620 std::wcerr <<
"Warning: " << releaseWithDebugInfoOption.names().first() <<
" is obsolete.";
622 switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
633 if (parser->isSet(deployPdbOption)) {
634 if (options->platform.testFlag(
WindowsBased) && !options->platform.testFlag(
MinGW))
637 std::wcerr <<
"Warning: --" << deployPdbOption.names().first() <<
" is not supported on this platform.\n";
640 if (parser->isSet(suppressSoftwareRasterizerOption))
643 if (parser->isSet(noFFmpegOption))
646 if (parser->isSet(forceOpenSslOption))
649 if (parser->isSet(openSslRootOption))
650 options->openSslRootDirectory = parser->value(openSslRootOption);
653 *errorMessage = QStringLiteral(
"force-openssl and openssl-root are mutually exclusive");
657 if (parser->isSet(forceOption))
659 if (parser->isSet(dryRunOption)) {
664 options
->patchQt = !parser->isSet(noPatchQtOption);
666 if (insightTrackerModuleAvailable)
669 for (
const QtModule &module : qtModuleEntries) {
670 if (parser->isSet(*enabledModuleOptions.at(module.id)))
671 options->additionalLibraries[module.id] = 1;
672 if (parser->isSet(*disabledModuleOptions.at(module.id)))
673 options->disabledLibraries[module.id] = 1;
677 if (options->additionalLibraries.test(QtQuickModuleId))
678 options->additionalLibraries[QtQmlModuleId] = 1;
679 if (options->additionalLibraries.test(QtDesignerComponentsModuleId))
680 options->additionalLibraries[QtDesignerModuleId] = 1;
682 if (parser->isSet(listOption)) {
683 const QString value = parser->value(listOption);
684 if (value == QStringLiteral(
"source")) {
685 options->list = ListSource;
686 }
else if (value == QStringLiteral(
"target")) {
687 options->list = ListTarget;
688 }
else if (value == QStringLiteral(
"relative")) {
689 options->list = ListRelative;
690 }
else if (value == QStringLiteral(
"mapping")) {
691 options->list = ListMapping;
693 *errorMessage = QStringLiteral(
"Please specify a valid option for -list (source, target, relative, mapping).");
698 if (parser->isSet(jsonOption) || options->list) {
703 const QStringList posArgs = parser->positionalArguments();
704 if (posArgs.isEmpty()) {
705 *errorMessage = QStringLiteral(
"Please specify the binary or folder.");
709 if (parser->isSet(dirOption))
710 options->directory = parser->value(dirOption);
712 if (parser->isSet(qmlDirOption))
713 options->qmlDirectories = parser->values(qmlDirOption);
715 if (parser->isSet(qmlImportOption))
716 options->qmlImportPaths = parser->values(qmlImportOption);
718 if (parser->isSet(qmlImportTimeoutOption)) {
719 const QString timeoutString = parser->value(qmlImportTimeoutOption);
721 int timeout = timeoutString.toInt(&ok);
723 *errorMessage = u'"' + timeoutString + QStringLiteral(
"\" is not an acceptable timeout "
730 const QString &file = posArgs.front();
731 const QFileInfo fi(QDir::cleanPath(file));
733 *errorMessage = msgFileDoesNotExist(file);
737 if (!options->directory.isEmpty() && !fi.isFile()) {
738 *errorMessage = u'"' + file + QStringLiteral(
"\" is not an executable file.");
743 options->binaries.append(fi.absoluteFilePath());
744 if (options->directory.isEmpty())
745 options->directory = fi.absolutePath();
747 const QString binary = findBinary(fi.absoluteFilePath(), options->platform);
748 if (binary.isEmpty()) {
749 *errorMessage = QStringLiteral(
"Unable to find binary in \"") + file + u'"';
752 options->directory = fi.absoluteFilePath();
753 options->binaries.append(binary);
757 bool multipleDirs =
false;
758 for (
int i = 1; i < posArgs.size(); ++i) {
759 const QFileInfo fi(QDir::cleanPath(posArgs.at(i)));
760 const QString path = fi.absoluteFilePath();
762 *errorMessage = msgFileDoesNotExist(path);
766 const QStringList libraries =
767 findSharedLibraries(QDir(path), options->platform, MatchDebugOrRelease, QString());
768 for (
const QString &library : libraries)
769 options->binaries.append(path + u'/' + library);
771 if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
773 options->binaries.append(path);
777 std::wcerr <<
"Warning: using binaries from different directories, deploying to following path: "
778 << options->directory <<
'\n' <<
"To disable this warning, use the --dir option\n";
780 if (options->translationsDirectory.isEmpty())
781 options->translationsDirectory = options->directory +
"/translations"_L1;
1102 const QString &qtPluginsDirName,
const QString &libraryLocation,
1103 const QString &infix,
DebugMatchMode debugMatchModeIn, Platform platform,
1104 QString *platformPlugin,
bool deployInsightTrackerPlugin,
1105 bool deployOpenSslPlugin)
1107 if (qtPluginsDirName.isEmpty())
1108 return QStringList();
1109 QDir pluginsDir(qtPluginsDirName);
1111 bool missingQtModulesAdded =
false;
1112 const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
1113 for (
const QFileInfo &subDirFi : pluginDirs) {
1114 const QString subDirName = subDirFi.fileName();
1115 const size_t module = qtModuleEntries.moduleIdForPluginType(subDirName);
1116 if (module == QtModule::InvalidId) {
1117 if (optVerboseLevel > 1) {
1118 std::wcerr <<
"No Qt module found for plugin type \"" << subDirName <<
"\".\n";
1122 const bool dueToModule = usedQtModules->test(module);
1123 if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
1124 const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
1125 ? MatchDebugOrRelease
1127 QDir subDir(subDirFi.absoluteFilePath());
1128 if (optVerboseLevel)
1129 std::wcout <<
"Adding in plugin type " << subDirFi.baseName() <<
" for module: " << qtModuleEntries.moduleById(module).name <<
'\n';
1131 const bool isPlatformPlugin = subDirName ==
"platforms"_L1;
1132 const QStringList plugins =
1133 findSharedLibraries(subDir, platform, debugMatchMode, QString());
1134 for (
const QString &plugin : plugins) {
1135 ModuleBitset pluginNeededQtModules;
1136 const QString pluginPath =
1137 deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
1138 disabledQtModules, pluginSelections, libraryLocation, infix,
1139 platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
1140 if (!pluginPath.isEmpty()) {
1141 if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
1142 *platformPlugin = subDir.absoluteFilePath(plugin);
1143 result.append(pluginPath);
1145 const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
1146 if (missingModules.any()) {
1147 *usedQtModules |= missingModules;
1148 missingQtModulesAdded =
true;
1149 if (optVerboseLevel) {
1150 std::wcout <<
"Adding " << formatQtModules(missingModules).constData()
1151 <<
" for " << plugin <<
" from plugin type: " << subDirName <<
'\n';
1161 if (missingQtModulesAdded) {
1163 std::wcout <<
"Performing additional pass of finding Qt plugins due to updated Qt module list: "
1164 << formatQtModules(*usedQtModules).constData() <<
"\n";
1166 return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
1167 libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
1168 deployInsightTrackerPlugin, deployOpenSslPlugin);
1496 const QChar slash = u'/';
1498 const QString qtBinDir = qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_BINS"));
1499 const QString libraryLocation = qtBinDir;
1500 const QString infix = qtpathsVariables.value(QLatin1StringView(
qmakeInfixKey));
1501 const int version = qtVersion(qtpathsVariables);
1504 if (optVerboseLevel > 1)
1505 std::wcout <<
"Qt binaries in " << QDir::toNativeSeparators(qtBinDir) <<
'\n';
1507 QStringList dependentQtLibs;
1508 QStringList dependentNonQtLibs;
1509 PeHeaderInfoStruct peHeaderInfo;
1511 if (!readPeExecutableInfo(options.binaries.first(), errorMessage, &peHeaderInfo))
1513 if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform,
1514 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1517 for (
int b = 1; b < options.binaries.size(); ++b) {
1518 if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform,
1519 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1524 const QFileInfo fi(options.binaries.first());
1525 const QString canonicalBinPath = fi.canonicalPath();
1528 for (qsizetype i = 0; i < dependentNonQtLibs.size(); ++i) {
1529 const QString nonQtLib = dependentNonQtLibs.at(i);
1530 const QString path = canonicalBinPath + u'/' + nonQtLib;
1531 if (!QFileInfo::exists(path))
1535 std::wcout <<
"Adding local dependency" << path <<
'\n';
1537 if (!findDependentQtLibraries(libraryLocation, path, options.platform,
1538 errorMessage, &dependentQtLibs, &dependentNonQtLibs)) {
1550 if (options.platform.testFlag(
Msvc) || options.platform.testFlag(
ClangMsvc)) {
1551 result
.isDebug = peHeaderInfo.isDebug;
1566 for (
int m = 0; m < dependentQtLibs.size(); ++m) {
1567 const qint64 module = qtModule(dependentQtLibs.at(m), infix);
1569 result.directlyUsedQtLibraries[module] = 1;
1572 const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
1573 const bool usesQuick = result.directlyUsedQtLibraries.test(QtQuickModuleId);
1574 const bool uses3DQuick = result.directlyUsedQtLibraries.test(Qt3DQuickModuleId);
1575 const bool usesQml2 = !(options.disabledLibraries.test(QtQmlModuleId))
1576 && (usesQml || usesQuick || uses3DQuick || (options.additionalLibraries.test(QtQmlModuleId)));
1579 std::wcout << QDir::toNativeSeparators(options.binaries.first()) <<
' '
1580 << peHeaderInfo.wordSize <<
" bit, " << (result.isDebug ?
"debug" :
"release")
1583 std::wcout <<
" [QML]";
1587 if (dependentQtLibs.isEmpty()) {
1588 *errorMessage = QDir::toNativeSeparators(options.binaries.first()) + QStringLiteral(
" does not seem to be a Qt executable.");
1596 QStringList qmlImportPaths = options.qmlImportPaths;
1598 qmlImportPaths << qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_QML"));
1599 QStringList qmlDirectories = options.qmlDirectories;
1600 if (qmlDirectories.isEmpty()) {
1601 const QString qmlDirectory = findQmlDirectory(options.platform, options.directory);
1602 if (!qmlDirectory.isEmpty())
1603 qmlDirectories.append(qmlDirectory);
1605 for (
const QString &qmlDirectory : std::as_const(qmlDirectories)) {
1606 if (optVerboseLevel >= 1)
1607 std::wcout <<
"Scanning " << QDir::toNativeSeparators(qmlDirectory) <<
":\n";
1608 const QmlImportScanResult scanResult =
1609 runQmlImportScanner(qmlDirectory, qmlImportPaths,
1610 result.directlyUsedQtLibraries.test(QtWidgetsModuleId),
1611 options.platform, debugMatchMode, errorMessage,
1612 options.qmlImportTimeout);
1615 qmlScanResult.append(scanResult);
1617 for (
const QString &plugin : std::as_const(qmlScanResult.plugins)) {
1618 if (!findDependentQtLibraries(libraryLocation, plugin, options.platform,
1619 errorMessage, &dependentQtLibs,
nullptr)) {
1623 if (optVerboseLevel >= 1) {
1624 std::wcout <<
"QML imports:\n";
1625 for (
const QmlImportScanResult::Module &mod : std::as_const(qmlScanResult.modules)) {
1626 std::wcout <<
" '" << mod.name <<
"' "
1627 << QDir::toNativeSeparators(mod.sourcePath) <<
'\n';
1629 if (optVerboseLevel >= 2) {
1630 std::wcout <<
"QML plugins:\n";
1631 for (
const QString &p : std::as_const(qmlScanResult.plugins))
1632 std::wcout <<
" " << QDir::toNativeSeparators(p) <<
'\n';
1638 QString platformPlugin;
1641 QStringList deployedQtLibraries;
1642 for (
int i = 0 ; i < dependentQtLibs.size(); ++i) {
1643 const qint64 module = qtModule(dependentQtLibs.at(i), infix);
1645 result.usedQtLibraries[module] = 1;
1647 deployedQtLibraries.push_back(dependentQtLibs.at(i));
1649 result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
1651 ModuleBitset disabled = options.disabledLibraries;
1653 disabled[QtQmlModuleId] = 1;
1654 disabled[QtQuickModuleId] = 1;
1660 const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral(
"Qt6Core"), Qt::CaseInsensitive)
1661 + dependentQtLibs.filter(QStringLiteral(
"Qt5WebKit"), Qt::CaseInsensitive);
1662 for (
const QString &qtLib : qtLibs) {
1663 QStringList icuLibs = findDependentLibraries(qtLib, errorMessage).filter(QStringLiteral(
"ICU"), Qt::CaseInsensitive);
1664 if (!icuLibs.isEmpty()) {
1667 const QString icuVersion = getIcuVersion(icuLibs.constFirst());
1668 if (!icuVersion.isEmpty()) {
1669 if (optVerboseLevel > 1)
1670 std::wcout <<
"Adding ICU version " << icuVersion <<
'\n';
1671 QString icuLib = QStringLiteral(
"icudt") + icuVersion
1672 + QLatin1StringView(windowsSharedLibrarySuffix);
1675 if (result.isDebug) {
1676 const QString icuLibCandidate = QStringLiteral(
"icudtd") + icuVersion
1677 + QLatin1StringView(windowsSharedLibrarySuffix);
1678 if (!findInPath(icuLibCandidate).isEmpty()) {
1679 icuLib = icuLibCandidate;
1682 icuLibs.push_back(icuLib);
1684 for (
const QString &icuLib : std::as_const(icuLibs)) {
1685 const QString icuPath = findInPath(icuLib);
1686 if (icuPath.isEmpty()) {
1687 *errorMessage = QStringLiteral(
"Unable to locate ICU library ") + icuLib;
1690 deployedQtLibraries.push_back(icuPath);
1697 QStringList openSslLibs;
1698 if (!options.openSslRootDirectory.isEmpty()) {
1699 openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
1700 if (openSslLibs.isEmpty()) {
1701 *errorMessage = QStringLiteral(
"Unable to find openSSL libraries in ")
1702 + options.openSslRootDirectory;
1706 deployedQtLibraries.append(openSslLibs);
1710 const QStringList plugins = findQtPlugins(
1711 &result.deployedQtLibraries,
1714 disabled, pluginInfo,
1715 options.pluginSelections, qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_PLUGINS")),
1716 libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
1717 options.deployInsightTrackerPlugin, deployOpenSslPlugin);
1720 QString qtGuiLibrary;
1721 for (
const auto &qtModule : qtModuleEntries) {
1722 if (result.deployedQtLibraries.test(qtModule.id)) {
1723 const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
1724 options.platform, result.isDebug);
1725 deployedQtLibraries.append(library);
1726 if (qtModule.id == QtGuiModuleId)
1727 qtGuiLibrary = library;
1732 std::wcout <<
"Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData()
1733 <<
"\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData()
1734 <<
"\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() <<
'\n';
1738 std::wcout <<
"Plugins: " << plugins.join(u',') <<
'\n';
1740 if (result.deployedQtLibraries.test(QtGuiModuleId) && platformPlugin.isEmpty()) {
1741 *errorMessage =QStringLiteral(
"Unable to find the platform plugin.");
1745 if (options.platform.testFlag(
WindowsBased) && !qtGuiLibrary.isEmpty()) {
1746 const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
1747 const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral(
"opengl32"), Qt::CaseInsensitive).isEmpty();
1749 const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral(
"opengl32sw") + QLatin1StringView(
windowsSharedLibrarySuffix));
1750 if (softwareRasterizer.isFile())
1751 deployedQtLibraries.append(softwareRasterizer.absoluteFilePath());
1754 const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir,
1755 peHeaderInfo.wordSize);
1756 if (d3dCompiler.isEmpty()) {
1757 std::wcerr <<
"Warning: Cannot find any version of the d3dcompiler DLL.\n";
1759 deployedQtLibraries.push_back(d3dCompiler);
1763 const QStringList dxcLibs = findDxc(options.platform, qtBinDir,
1764 peHeaderInfo.wordSize);
1765 if (!dxcLibs.isEmpty())
1766 deployedQtLibraries.append(dxcLibs);
1768 std::wcerr <<
"Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
1774 && !plugins.filter(QStringLiteral(
"ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
1775 deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
1780 const QString targetPath = options.libraryDirectory.isEmpty() ?
1781 options.directory : options.libraryDirectory;
1782 QStringList libraries = deployedQtLibraries;
1784 libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug,
1785 peHeaderInfo.machineArch));
1787 for (
const QString &qtLib : std::as_const(libraries)) {
1788 if (!updateLibrary(qtLib, targetPath, options, errorMessage))
1792#if !QT_CONFIG(relocatable)
1793 if (options.patchQt && !options.dryRun) {
1794 const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation,
"Qt6Core", infix,
1795 options.platform, result.isDebug)).fileName();
1796 if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
1797 std::wcerr <<
"Warning: " << *errorMessage <<
'\n';
1798 errorMessage->clear();
1806 const QString targetPath = options.pluginDirectory.isEmpty() ?
1807 options.directory : options.pluginDirectory;
1808 QDir dir(targetPath);
1809 if (!dir.exists() && !dir.mkpath(QStringLiteral(
"."))) {
1810 *errorMessage =
"Cannot create "_L1 +
1811 QDir::toNativeSeparators(dir.absolutePath()) + u'.';
1814 for (
const QString &plugin : plugins) {
1815 const QString targetDirName = plugin.section(slash, -2, -2);
1816 const QString targetPath = dir.absoluteFilePath(targetDirName);
1817 if (!dir.exists(targetDirName)) {
1818 if (optVerboseLevel)
1819 std::wcout <<
"Creating directory " << targetPath <<
".\n";
1820 if (!(options.updateFileFlags & SkipUpdateFile) && !dir.mkdir(targetDirName)) {
1821 *errorMessage = QStringLiteral(
"Cannot create ") + targetDirName + u'.';
1825 if (!updateLibrary(plugin, targetPath, options, errorMessage))
1834 const QString targetPath = options.qmlDirectory.isEmpty()
1835 ? options.directory + QStringLiteral(
"/qml")
1836 : options.qmlDirectory;
1837 if (!createDirectory(targetPath, errorMessage, options.dryRun))
1839 for (
const QmlImportScanResult::Module &module : std::as_const(qmlScanResult.modules)) {
1840 const QString installPath = module.installPath(targetPath);
1841 if (optVerboseLevel > 1)
1842 std::wcout <<
"Installing: '" << module.name
1843 <<
"' from " << module.sourcePath <<
" to "
1844 << QDir::toNativeSeparators(installPath) <<
'\n';
1845 if (installPath != targetPath && !createDirectory(installPath, errorMessage, options.dryRun))
1847 unsigned updateFileFlags = options.updateFileFlags
1848 | SkipQmlDesignerSpecificsDirectories;
1849 unsigned qmlDirectoryFileFlags = 0;
1850 if (options.deployPdb)
1851 qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
1852 if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
1855 qmlDirectoryFileFlags),
1856 installPath, updateFileFlags, options.json, errorMessage)) {
1863 if (!createDirectory(options.translationsDirectory, errorMessage, options.dryRun))
1865 if (!deployTranslations(qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_TRANSLATIONS")),
1866 result.deployedQtLibraries, options.translationsDirectory, options,
1899 bool isDebug, QString *errorMessage)
1901 static const char *installDataFilesRelease[] = {
1902 "icudtl.dat",
"qtwebengine_devtools_resources.pak",
"qtwebengine_resources.pak",
1903 "qtwebengine_resources_100p.pak",
"qtwebengine_resources_200p.pak"
1905 static const char *installDataFilesDebug[] = {
1906 "icudtl.dat",
"qtwebengine_devtools_resources.debug.pak",
"qtwebengine_resources.debug.pak",
1907 "qtwebengine_resources_100p.debug.pak",
"qtwebengine_resources_200p.debug.pak"
1909 static const auto &installDataFiles = isDebug ? installDataFilesDebug : installDataFilesRelease;
1910 static const auto installV8SnapshotFile =
1911 isDebug ?
"v8_context_snapshot.debug.bin" :
"v8_context_snapshot.bin";
1914 if (isDebug && platformHasDebugSuffix(options.platform))
1915 webEngineProcessName.append(
'd');
1917 std::wcout <<
"Deploying: " << webEngineProcessName.constData() <<
"...\n";
1918 if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
1920 const QString resourcesSubDir = QStringLiteral(
"/resources");
1921 const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_DATA"))
1922 + resourcesSubDir + u'/';
1923 const QString resourcesTargetDir(options.directory + resourcesSubDir);
1924 if (!createDirectory(resourcesTargetDir, errorMessage, options.dryRun))
1926 for (
auto installDataFile : installDataFiles) {
1927 if (!updateFile(resourcesSourceDir + QLatin1StringView(installDataFile),
1928 resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) {
1933 updateFile(resourcesSourceDir + QLatin1StringView(installV8SnapshotFile), resourcesTargetDir,
1935 errorMessage->clear();
1936 const QFileInfo translations(qtpathsVariables.value(QStringLiteral(
"QT_INSTALL_TRANSLATIONS"))
1937 + QStringLiteral(
"/qtwebengine_locales"));
1938 if (!translations.isDir()) {
1939 std::wcerr <<
"Warning: Cannot find the translation files of the QtWebEngine module at "
1940 << QDir::toNativeSeparators(translations.absoluteFilePath()) <<
".\n";
1945 return createDirectory(options.translationsDirectory, errorMessage, options.dryRun)
1946 && updateFile(translations.absoluteFilePath(), options.translationsDirectory,
1947 options.updateFileFlags, options.json, errorMessage);
1950 const QFileInfo enUSpak(translations.filePath() + QStringLiteral(
"/en-US.pak"));
1951 if (!enUSpak.exists()) {
1952 std::wcerr <<
"Warning: Cannot find "
1953 << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) <<
".\n";
1956 const QString webEngineTranslationsDir = options.translationsDirectory + u'/'
1957 + translations.fileName();
1958 if (!createDirectory(webEngineTranslationsDir, errorMessage, options.dryRun))
1960 return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir,
1961 options.updateFileFlags, options.json, errorMessage);
1970 QCoreApplication a(argc, argv);
1971 QCoreApplication::setApplicationVersion(QT_VERSION_STR
""_L1);
1973 const QByteArray qtBinPath = QFile::encodeName(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
1974 QByteArray path = qgetenv(
"PATH");
1975 if (!path.contains(qtBinPath)) {
1976 path.prepend(QDir::listSeparator().toLatin1());
1977 path.prepend(qtBinPath);
1978 qputenv(
"PATH", path);
1982 QString errorMessage;
1987 int result = parseEarlyArguments(QCoreApplication::arguments(), &options, &errorMessage);
1989 std::wcerr <<
"Error: " << errorMessage <<
"\n";
1994 const QMap<QString, QString> qtpathsVariables =
1995 queryQtPaths(options.qtpathsBinary, &errorMessage);
1996 const QString xSpec = qtpathsVariables.value(QStringLiteral(
"QMAKE_XSPEC"));
1997 if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
1998 || !qtpathsVariables.contains(QStringLiteral(
"QT_INSTALL_BINS"))) {
1999 std::wcerr <<
"Unable to query qtpaths: " << errorMessage <<
'\n';
2003 options.platform = platformFromMkSpec(xSpec);
2008 switch (si.wProcessorArchitecture) {
2009 case PROCESSOR_ARCHITECTURE_INTEL:
2010 case PROCESSOR_ARCHITECTURE_IA64:
2011 case PROCESSOR_ARCHITECTURE_AMD64:
2014 case PROCESSOR_ARCHITECTURE_ARM:
2015 case PROCESSOR_ARCHITECTURE_ARM64:
2023 std::wcerr <<
"Unsupported platform " << xSpec <<
'\n';
2028 const QString modulesDir
2029 = qtpathsVariables.value(QLatin1String(
"QT_INSTALL_ARCHDATA"))
2030 + QLatin1String(
"/modules");
2031 const QString translationsDir
2032 = qtpathsVariables.value(QLatin1String(
"QT_INSTALL_TRANSLATIONS"));
2035 std::wcerr <<
"Error: " << errorMessage <<
"\n";
2042 pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
2046 QCommandLineParser parser;
2047 QString errorMessage;
2048 const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
2050 std::wcerr << errorMessage <<
"\n\n";
2052 std::fputs(QT_VERSION_STR
"\n", stdout);
2055 if (result & CommandLineParseHelpRequested)
2056 std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
2064 if (!createDirectory(options.directory, &errorMessage, options.dryRun)) {
2065 std::wcerr << errorMessage <<
'\n';
2068 if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory
2069 && !createDirectory(options.libraryDirectory, &errorMessage, options.dryRun)) {
2070 std::wcerr << errorMessage <<
'\n';
2074 const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
2076 std::wcerr << errorMessage <<
'\n';
2080 if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
2081 if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
2083 std::wcerr << errorMessage <<
'\n';
2088 if (options
.createAppx && !options.appxCertificatePath.isEmpty()) {
2089 const QFileInfo storeLogo(options.directory + QStringLiteral(
"/Assets/StoreLogo.png"));
2090 if (!storeLogo.exists()) {
2091 std::wcerr <<
"Error: Could not open application logo file " << storeLogo.absoluteFilePath() <<
'\n';
2095 QFile certFile(options.appxCertificatePath);
2096 if (!certFile.open(QIODevice::ReadOnly)) {
2097 std::wcerr <<
"Could not open certificate file" <<
'\n';
2101 QSslCertificate cert(&certFile, QSsl::Der);
2102 QString publisher = cert.subjectDisplayName();
2104 const QString applicationName = QFileInfo(options.binaries.first()).baseName();
2105 const QString platform = options.platform.testFlag(
PlatformFlag::IntelBased) ? QStringLiteral(
"x64") : QStringLiteral(
"arm64");
2106 const QString appxFilePath(options.directory + QStringLiteral(
"/") + QStringLiteral(
"AppxManifest.xml"));
2107 QFile f(appxFilePath);
2108 if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
2109 std::wcerr <<
"Could not create AppxManifest.xml" <<
'\n';
2113 QXmlStreamWriter manifestWriter(&f);
2114 manifestWriter.setAutoFormatting(
true);
2115 manifestWriter.writeStartDocument();
2116 manifestWriter.writeStartElement(QStringLiteral(
"Package"));
2117 manifestWriter.writeAttribute(QStringLiteral(
"xmlns"), QStringLiteral(
"http://schemas.microsoft.com/appx/manifest/foundation/windows10"));
2118 manifestWriter.writeAttribute(QStringLiteral(
"xmlns:uap"), QStringLiteral(
"http://schemas.microsoft.com/appx/manifest/uap/windows10"));
2119 manifestWriter.writeAttribute(QStringLiteral(
"xmlns:rescap"), QStringLiteral(
"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"));
2121 manifestWriter.writeStartElement(QStringLiteral(
"Identity"));
2122 manifestWriter.writeAttribute(
"Name", QUuid::createUuid().toString(QUuid::WithoutBraces));
2123 manifestWriter.writeAttribute(
"Publisher", QStringLiteral(
"CN=") + publisher);
2124 manifestWriter.writeAttribute(
"Version",
"1.0.0.0");
2125 manifestWriter.writeAttribute(
"ProcessorArchitecture", platform);
2126 manifestWriter.writeEndElement();
2128 manifestWriter.writeStartElement(
"Properties");
2129 manifestWriter.writeStartElement(
"DisplayName");
2130 manifestWriter.writeCharacters(applicationName);
2131 manifestWriter.writeEndElement();
2132 manifestWriter.writeStartElement(
"PublisherDisplayName");
2133 manifestWriter.writeCharacters(publisher);
2134 manifestWriter.writeEndElement();
2135 manifestWriter.writeStartElement(
"Logo");
2136 manifestWriter.writeCharacters(
"Assets/StoreLogo.png");
2137 manifestWriter.writeEndElement();
2138 manifestWriter.writeEndElement();
2140 manifestWriter.writeStartElement(
"Dependencies");
2141 manifestWriter.writeStartElement(
"TargetDeviceFamily");
2142 manifestWriter.writeAttribute(
"Name",
"Windows.Desktop");
2143 manifestWriter.writeAttribute(
"MinVersion",
"10.0.14316.0");
2144 manifestWriter.writeAttribute(
"MaxVersionTested",
"10.0.14316.0");
2145 manifestWriter.writeEndElement();
2146 manifestWriter.writeEndElement();
2148 manifestWriter.writeStartElement(
"Capabilities");
2149 manifestWriter.writeStartElement(
"rescap:Capability");
2150 manifestWriter.writeAttribute(
"Name",
"runFullTrust");
2151 manifestWriter.writeEndElement();
2152 manifestWriter.writeEndElement();
2154 manifestWriter.writeStartElement(
"Resources");
2155 manifestWriter.writeStartElement(
"Resource");
2156 if (options.languages.isEmpty()) {
2157 QLocale locale = QLocale::system();
2158 manifestWriter.writeAttribute(
"Language", locale.bcp47Name());
2160 for (
const auto& language : options.languages) {
2161 manifestWriter.writeAttribute(
"Language", language);
2164 manifestWriter.writeEndElement();
2165 manifestWriter.writeEndElement();
2167 manifestWriter.writeStartElement(
"Applications");
2168 for (
const auto& binary : options.binaries) {
2169 const QString binaryRelative = binary.split(QStringLiteral(
"/")).last();
2170 const QString displayName = binaryRelative.split(QStringLiteral(
".")).first();
2171 QFile descriptionFile(options.directory + QStringLiteral(
"/") + QStringLiteral(
"Assets/Description_") + displayName + QStringLiteral(
".txt"));
2172 QString description;
2173 if (!descriptionFile.exists())
2174 std::wcerr <<
"Warning: No package description was provided " << descriptionFile.fileName() <<
'\n';
2175 if (descriptionFile.open(QIODevice::ReadOnly | QIODevice::Text))
2176 description = QString::fromUtf8(descriptionFile.readAll());
2178 manifestWriter.writeStartElement(
"Application");
2179 manifestWriter.writeAttribute(
"Id", displayName);
2180 manifestWriter.writeAttribute(
"Executable", binaryRelative);
2181 manifestWriter.writeAttribute(
"EntryPoint",
"Windows.FullTrustApplication");
2182 manifestWriter.writeStartElement(
"uap:VisualElements");
2183 manifestWriter.writeAttribute(
"DisplayName", displayName);
2184 manifestWriter.writeAttribute(
"Description", description);
2185 manifestWriter.writeAttribute(
"BackgroundColor",
"transparent");
2186 manifestWriter.writeAttribute(
"Square150x150Logo",
"Assets/Logo.png");
2187 manifestWriter.writeAttribute(
"Square44x44Logo",
"Assets/SmallLogo.png");
2188 manifestWriter.writeStartElement(
"uap:DefaultTile");
2189 manifestWriter.writeEndElement();
2190 manifestWriter.writeEndElement();
2191 manifestWriter.writeEndElement();
2193 manifestWriter.writeEndElement();
2194 manifestWriter.writeEndElement();
2195 manifestWriter.writeEndDocument();
2200 std::fputs(options
.json->toList(options.list, options.directory).constData(), stdout);
2202 std::fputs(options
.json->toJson().constData(), stdout);
2203 delete options
.json;
2204 options
.json =
nullptr;