diff options
Diffstat (limited to 'src/windeployqt/main.cpp')
-rw-r--r-- | src/windeployqt/main.cpp | 1724 |
1 files changed, 0 insertions, 1724 deletions
diff --git a/src/windeployqt/main.cpp b/src/windeployqt/main.cpp deleted file mode 100644 index 213214576..000000000 --- a/src/windeployqt/main.cpp +++ /dev/null @@ -1,1724 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "utils.h" -#include "qmlutils.h" - -#include <QtCore/QCommandLineOption> -#include <QtCore/QCommandLineParser> -#include <QtCore/QDir> -#include <QtCore/QFileInfo> -#include <QtCore/QCoreApplication> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonObject> -#include <QtCore/QJsonArray> -#include <QtCore/QList> -#include <QtCore/QOperatingSystemVersion> -#include <QtCore/QSharedPointer> - -#ifdef Q_OS_WIN -#include <QtCore/qt_windows.h> -#else -#define IMAGE_FILE_MACHINE_ARM64 0xaa64 -#endif - -#include <algorithm> -#include <iostream> -#include <iterator> -#include <cstdio> - -QT_BEGIN_NAMESPACE - -enum QtModule -#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) - : quint64 -#endif -{ - QtBluetoothModule = 0x0000000000000001, - QtConcurrentModule = 0x0000000000000002, - QtCoreModule = 0x0000000000000004, - QtDeclarativeModule = 0x0000000000000008, - QtDesignerComponents = 0x0000000000000010, - QtDesignerModule = 0x0000000000000020, - QtGuiModule = 0x0000000000000040, - QtHelpModule = 0x0000000000000080, - QtMultimediaModule = 0x0000000000000100, - QtMultimediaWidgetsModule = 0x0000000000000200, - QtMultimediaQuickModule = 0x0000000000000400, - QtNetworkModule = 0x0000000000000800, - QtNfcModule = 0x0000000000001000, - QtOpenGLModule = 0x0000000000002000, - QtPositioningModule = 0x0000000000004000, - QtPrintSupportModule = 0x0000000000008000, - QtQmlModule = 0x0000000000010000, - QtQuickModule = 0x0000000000020000, - QtQuickParticlesModule = 0x0000000000040000, - QtScriptModule = 0x0000000000080000, - QtScriptToolsModule = 0x0000000000100000, - QtSensorsModule = 0x0000000000200000, - QtSerialPortModule = 0x0000000000400000, - QtSqlModule = 0x0000000000800000, - QtSvgModule = 0x0000000001000000, - QtTestModule = 0x0000000002000000, - QtWidgetsModule = 0x0000000004000000, - QtWinExtrasModule = 0x0000000008000000, - QtXmlModule = 0x0000000010000000, - QtXmlPatternsModule = 0x0000000020000000, - QtWebKitModule = 0x0000000040000000, - QtWebKitWidgetsModule = 0x0000000080000000, - QtQuickWidgetsModule = 0x0000000100000000, - QtWebSocketsModule = 0x0000000200000000, - QtEnginioModule = 0x0000000400000000, - QtWebEngineCoreModule = 0x0000000800000000, - QtWebEngineModule = 0x0000001000000000, - QtWebEngineWidgetsModule = 0x0000002000000000, - QtQmlToolingModule = 0x0000004000000000, - Qt3DCoreModule = 0x0000008000000000, - Qt3DRendererModule = 0x0000010000000000, - Qt3DQuickModule = 0x0000020000000000, - Qt3DQuickRendererModule = 0x0000040000000000, - Qt3DInputModule = 0x0000080000000000, - QtLocationModule = 0x0000100000000000, - QtWebChannelModule = 0x0000200000000000, - QtTextToSpeechModule = 0x0000400000000000, - QtSerialBusModule = 0x0000800000000000, - QtGamePadModule = 0x0001000000000000, - Qt3DAnimationModule = 0x0002000000000000, - QtWebViewModule = 0x0004000000000000, - Qt3DExtrasModule = 0x0008000000000000 -}; - -struct QtModuleEntry { - quint64 module; - const char *option; - const char *libraryName; - const char *translation; -}; - -static QtModuleEntry qtModuleEntries[] = { - { QtBluetoothModule, "bluetooth", "Qt6Bluetooth", nullptr }, - { QtConcurrentModule, "concurrent", "Qt6Concurrent", "qtbase" }, - { QtCoreModule, "core", "Qt6Core", "qtbase" }, - { QtDeclarativeModule, "declarative", "Qt6Declarative", "qtquick1" }, - { QtDesignerModule, "designer", "Qt6Designer", nullptr }, - { QtDesignerComponents, "designercomponents", "Qt6DesignerComponents", nullptr }, - { QtEnginioModule, "enginio", "Enginio", nullptr }, - { QtGamePadModule, "gamepad", "Qt6Gamepad", nullptr }, - { QtGuiModule, "gui", "Qt6Gui", "qtbase" }, - { QtHelpModule, "qthelp", "Qt6Help", "qt_help" }, - { QtMultimediaModule, "multimedia", "Qt6Multimedia", "qtmultimedia" }, - { QtMultimediaWidgetsModule, "multimediawidgets", "Qt6MultimediaWidgets", "qtmultimedia" }, - { QtMultimediaQuickModule, "multimediaquick", "Qt6MultimediaQuick_p", "qtmultimedia" }, - { QtNetworkModule, "network", "Qt6Network", "qtbase" }, - { QtNfcModule, "nfc", "Qt6Nfc", nullptr }, - { QtOpenGLModule, "opengl", "Qt6OpenGL", nullptr }, - { QtPositioningModule, "positioning", "Qt6Positioning", nullptr }, - { QtPrintSupportModule, "printsupport", "Qt6PrintSupport", nullptr }, - { QtQmlModule, "qml", "Qt6Qml", "qtdeclarative" }, - { QtQmlToolingModule, "qmltooling", "qmltooling", nullptr }, - { QtQuickModule, "quick", "Qt6Quick", "qtdeclarative" }, - { QtQuickParticlesModule, "quickparticles", "Qt6QuickParticles", nullptr }, - { QtQuickWidgetsModule, "quickwidgets", "Qt6QuickWidgets", nullptr }, - { QtScriptModule, "script", "Qt6Script", "qtscript" }, - { QtScriptToolsModule, "scripttools", "Qt6ScriptTools", "qtscript" }, - { QtSensorsModule, "sensors", "Qt6Sensors", nullptr }, - { QtSerialPortModule, "serialport", "Qt6SerialPort", "qtserialport" }, - { QtSqlModule, "sql", "Qt6Sql", "qtbase" }, - { QtSvgModule, "svg", "Qt6Svg", nullptr }, - { QtTestModule, "test", "Qt6Test", "qtbase" }, - { QtWebKitModule, "webkit", "Qt6WebKit", nullptr }, - { QtWebKitWidgetsModule, "webkitwidgets", "Qt6WebKitWidgets", nullptr }, - { QtWebSocketsModule, "websockets", "Qt6WebSockets", nullptr }, - { QtWidgetsModule, "widgets", "Qt6Widgets", "qtbase" }, - { QtWinExtrasModule, "winextras", "Qt6WinExtras", nullptr }, - { QtXmlModule, "xml", "Qt6Xml", "qtbase" }, - { QtXmlPatternsModule, "xmlpatterns", "Qt6XmlPatterns", "qtxmlpatterns" }, - { QtWebEngineCoreModule, "webenginecore", "Qt6WebEngineCore", nullptr }, - { QtWebEngineModule, "webengine", "Qt6WebEngine", "qtwebengine" }, - { QtWebEngineWidgetsModule, "webenginewidgets", "Qt6WebEngineWidgets", nullptr }, - { Qt3DCoreModule, "3dcore", "Qt63DCore", nullptr }, - { Qt3DRendererModule, "3drenderer", "Qt63DRender", nullptr }, - { Qt3DQuickModule, "3dquick", "Qt63DQuick", nullptr }, - { Qt3DQuickRendererModule, "3dquickrenderer", "Qt63DQuickRender", nullptr }, - { Qt3DInputModule, "3dinput", "Qt63DInput", nullptr }, - { Qt3DAnimationModule, "3danimation", "Qt63DAnimation", nullptr }, - { Qt3DExtrasModule, "3dextras", "Qt63DExtras", nullptr }, - { QtLocationModule, "geoservices", "Qt6Location", nullptr }, - { QtWebChannelModule, "webchannel", "Qt6WebChannel", nullptr }, - { QtTextToSpeechModule, "texttospeech", "Qt6TextToSpeech", nullptr }, - { QtSerialBusModule, "serialbus", "Qt6SerialBus", nullptr }, - { QtWebViewModule, "webview", "Qt6WebView", nullptr } -}; - -enum QtPlugin { - QtVirtualKeyboardPlugin = 0x1 -}; - -static const char webKitProcessC[] = "QtWebProcess"; -static const char webEngineProcessC[] = "QtWebEngineProcess"; - -static inline QString webProcessBinary(const char *binaryName, Platform p) -{ - const QString webProcess = QLatin1String(binaryName); - return (p & WindowsBased) ? webProcess + QStringLiteral(".exe") : webProcess; -} - -static QByteArray formatQtModules(quint64 mask, bool option = false) -{ - QByteArray result; - for (const auto &qtModule : qtModuleEntries) { - if (mask & qtModule.module) { - if (!result.isEmpty()) - result.append(' '); - result.append(option ? qtModule.option : qtModule.libraryName); - } - } - return result; -} - -static Platform platformFromMkSpec(const QString &xSpec) -{ - if (xSpec == QLatin1String("linux-g++")) - return Unix; - if (xSpec.startsWith(QLatin1String("win32-"))) { - if (xSpec.contains(QLatin1String("clang-g++"))) - return WindowsDesktopClangMinGW; - if (xSpec.contains(QLatin1String("clang-msvc++"))) - return WindowsDesktopClangMsvc; - return xSpec.contains(QLatin1String("g++")) ? WindowsDesktopMinGW : WindowsDesktopMsvc; - } - return UnknownPlatform; -} - -// Helpers for exclusive options, "-foo", "--no-foo" -enum ExlusiveOptionValue { - OptionAuto, - OptionEnabled, - OptionDisabled -}; - -static ExlusiveOptionValue parseExclusiveOptions(const QCommandLineParser *parser, - const QCommandLineOption &enableOption, - const QCommandLineOption &disableOption) -{ - const bool enabled = parser->isSet(enableOption); - const bool disabled = parser->isSet(disableOption); - if (enabled) { - if (disabled) { - std::wcerr << "Warning: both -" << enableOption.names().first() - << " and -" << disableOption.names().first() << " were specified, defaulting to -" - << enableOption.names().first() << ".\n"; - } - return OptionEnabled; - } - return disabled ? OptionDisabled : OptionAuto; -} - -static ExlusiveOptionValue optWebKit2 = OptionAuto; - -struct Options { - enum DebugDetection { - DebugDetectionAuto, - DebugDetectionForceDebug, - DebugDetectionForceRelease - }; - - bool plugins = true; - bool libraries = true; - bool quickImports = true; - bool translations = true; - bool systemD3dCompiler = true; - bool compilerRunTime = false; - unsigned disabledPlugins = 0; - bool softwareRasterizer = true; - Platform platform = WindowsDesktopMsvc; - quint64 additionalLibraries = 0; - quint64 disabledLibraries = 0; - unsigned updateFileFlags = 0; - QStringList qmlDirectories; // Project's QML files. - QStringList qmlImportPaths; // Custom QML module locations. - QString directory; - QString qmakePath; - QString translationsDirectory; // Translations target directory - QStringList languages; - QString libraryDirectory; - QString pluginDirectory; - QStringList binaries; - JsonOutput *json = nullptr; - ListOption list = ListNone; - DebugDetection debugDetection = DebugDetectionAuto; - bool deployPdb = false; - bool dryRun = false; - bool patchQt = true; - bool ignoreLibraryErrors = false; -}; - -// Return binary from folder -static inline QString findBinary(const QString &directory, Platform platform) -{ - const QStringList nameFilters = (platform & WindowsBased) ? - QStringList(QStringLiteral("*.exe")) : QStringList(); - const QFileInfoList &binaries = - QDir(QDir::cleanPath(directory)).entryInfoList(nameFilters, QDir::Files | QDir::Executable); - for (const QFileInfo &binaryFi : binaries) { - const QString binary = binaryFi.fileName(); - if (!binary.contains(QLatin1String(webKitProcessC), Qt::CaseInsensitive) - && !binary.contains(QLatin1String(webEngineProcessC), Qt::CaseInsensitive)) { - return binaryFi.absoluteFilePath(); - } - } - return QString(); -} - -static QString msgFileDoesNotExist(const QString & file) -{ - return QLatin1Char('"') + QDir::toNativeSeparators(file) - + QStringLiteral("\" does not exist."); -} - -enum CommandLineParseFlag { - CommandLineParseError = 0x1, - CommandLineParseHelpRequested = 0x2 -}; - -static inline int parseArguments(const QStringList &arguments, QCommandLineParser *parser, - Options *options, QString *errorMessage) -{ - using CommandLineOptionPtr = QSharedPointer<QCommandLineOption>; - using OptionPtrVector = QList<CommandLineOptionPtr>; - - parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - parser->setApplicationDescription(QStringLiteral("Qt Deploy Tool ") + QLatin1String(QT_VERSION_STR) - + QLatin1String("\n\nThe simplest way to use windeployqt is to add the bin directory of your Qt\n" - "installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n" - "If ICU, etc. are not in the bin directory, they need to be in the PATH\nvariable. " - "If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>")); - const QCommandLineOption helpOption = parser->addHelpOption(); - parser->addVersionOption(); - - QCommandLineOption dirOption(QStringLiteral("dir"), - QStringLiteral("Use directory instead of binary directory."), - QStringLiteral("directory")); - parser->addOption(dirOption); - - QCommandLineOption qmakeOption(QStringLiteral("qmake"), - QStringLiteral("Use specified qmake instead of qmake from PATH."), - QStringLiteral("path")); - parser->addOption(qmakeOption); - - QCommandLineOption libDirOption(QStringLiteral("libdir"), - QStringLiteral("Copy libraries to path."), - QStringLiteral("path")); - parser->addOption(libDirOption); - - QCommandLineOption pluginDirOption(QStringLiteral("plugindir"), - QStringLiteral("Copy plugins to path."), - QStringLiteral("path")); - parser->addOption(pluginDirOption); - - QCommandLineOption debugOption(QStringLiteral("debug"), - QStringLiteral("Assume debug binaries.")); - parser->addOption(debugOption); - QCommandLineOption releaseOption(QStringLiteral("release"), - QStringLiteral("Assume release binaries.")); - parser->addOption(releaseOption); - QCommandLineOption releaseWithDebugInfoOption(QStringLiteral("release-with-debug-info"), - QStringLiteral("Assume release binaries with debug information.")); - releaseWithDebugInfoOption.setFlags(QCommandLineOption::HiddenFromHelp); // Deprecated by improved debug detection. - parser->addOption(releaseWithDebugInfoOption); - - QCommandLineOption deployPdbOption(QStringLiteral("pdb"), - QStringLiteral("Deploy .pdb files (MSVC).")); - parser->addOption(deployPdbOption); - - QCommandLineOption forceOption(QStringLiteral("force"), - QStringLiteral("Force updating files.")); - parser->addOption(forceOption); - - QCommandLineOption dryRunOption(QStringLiteral("dry-run"), - QStringLiteral("Simulation mode. Behave normally, but do not copy/update any files.")); - parser->addOption(dryRunOption); - - QCommandLineOption noPatchQtOption(QStringLiteral("no-patchqt"), - QStringLiteral("Do not patch the Qt6Core library.")); - parser->addOption(noPatchQtOption); - - QCommandLineOption ignoreErrorOption(QStringLiteral("ignore-library-errors"), - QStringLiteral("Ignore errors when libraries cannot be found.")); - parser->addOption(ignoreErrorOption); - - QCommandLineOption noPluginsOption(QStringLiteral("no-plugins"), - QStringLiteral("Skip plugin deployment.")); - parser->addOption(noPluginsOption); - - QCommandLineOption noLibraryOption(QStringLiteral("no-libraries"), - QStringLiteral("Skip library deployment.")); - parser->addOption(noLibraryOption); - - QCommandLineOption qmlDirOption(QStringLiteral("qmldir"), - QStringLiteral("Scan for QML-imports starting from directory."), - QStringLiteral("directory")); - parser->addOption(qmlDirOption); - - QCommandLineOption qmlImportOption(QStringLiteral("qmlimport"), - QStringLiteral("Add the given path to the QML module search locations."), - QStringLiteral("directory")); - parser->addOption(qmlImportOption); - - QCommandLineOption noQuickImportOption(QStringLiteral("no-quick-import"), - QStringLiteral("Skip deployment of Qt Quick imports.")); - parser->addOption(noQuickImportOption); - - - QCommandLineOption translationOption(QStringLiteral("translations"), - QStringLiteral("A comma-separated list of languages to deploy (de,fi)."), - QStringLiteral("languages")); - parser->addOption(translationOption); - - QCommandLineOption noTranslationOption(QStringLiteral("no-translations"), - QStringLiteral("Skip deployment of translations.")); - parser->addOption(noTranslationOption); - - QCommandLineOption noSystemD3DCompilerOption(QStringLiteral("no-system-d3d-compiler"), - QStringLiteral("Skip deployment of the system D3D compiler.")); - parser->addOption(noSystemD3DCompilerOption); - - - QCommandLineOption compilerRunTimeOption(QStringLiteral("compiler-runtime"), - QStringLiteral("Deploy compiler runtime (Desktop only).")); - parser->addOption(compilerRunTimeOption); - - QCommandLineOption noVirtualKeyboardOption(QStringLiteral("no-virtualkeyboard"), - QStringLiteral("Disable deployment of the Virtual Keyboard.")); - parser->addOption(noVirtualKeyboardOption); - - QCommandLineOption noCompilerRunTimeOption(QStringLiteral("no-compiler-runtime"), - QStringLiteral("Do not deploy compiler runtime (Desktop only).")); - parser->addOption(noCompilerRunTimeOption); - - QCommandLineOption webKitOption(QStringLiteral("webkit2"), - QStringLiteral("Deployment of WebKit2 (web process).")); - parser->addOption(webKitOption); - - QCommandLineOption noWebKitOption(QStringLiteral("no-webkit2"), - QStringLiteral("Skip deployment of WebKit2.")); - parser->addOption(noWebKitOption); - - QCommandLineOption jsonOption(QStringLiteral("json"), - QStringLiteral("Print to stdout in JSON format.")); - parser->addOption(jsonOption); - - QCommandLineOption suppressSoftwareRasterizerOption(QStringLiteral("no-opengl-sw"), - QStringLiteral("Do not deploy the software rasterizer library.")); - parser->addOption(suppressSoftwareRasterizerOption); - - QCommandLineOption listOption(QStringLiteral("list"), - QLatin1String("Print only the names of the files copied.\n" - "Available options:\n" - " source: absolute path of the source files\n" - " target: absolute path of the target files\n" - " relative: paths of the target files, relative\n" - " to the target directory\n" - " mapping: outputs the source and the relative\n" - " target, suitable for use within an\n" - " Appx mapping file"), - QStringLiteral("option")); - parser->addOption(listOption); - - QCommandLineOption verboseOption(QStringLiteral("verbose"), - QStringLiteral("Verbose level (0-2)."), - QStringLiteral("level")); - parser->addOption(verboseOption); - - parser->addPositionalArgument(QStringLiteral("[files]"), - QStringLiteral("Binaries or directory containing the binary.")); - - OptionPtrVector enabledModuleOptions; - OptionPtrVector disabledModuleOptions; - const int qtModulesCount = int(sizeof(qtModuleEntries) / sizeof(QtModuleEntry)); - enabledModuleOptions.reserve(qtModulesCount); - disabledModuleOptions.reserve(qtModulesCount); - for (int i = 0; i < qtModulesCount; ++i) { - const QString option = QLatin1String(qtModuleEntries[i].option); - const QString name = QLatin1String(qtModuleEntries[i].libraryName); - const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module."); - CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription)); - parser->addOption(*enabledOption.data()); - enabledModuleOptions.append(enabledOption); - const QString disabledDescription = QStringLiteral("Remove ") + name + QStringLiteral(" module."); - CommandLineOptionPtr disabledOption(new QCommandLineOption(QStringLiteral("no-") + option, - disabledDescription)); - disabledModuleOptions.append(disabledOption); - parser->addOption(*disabledOption.data()); - } - - const bool success = parser->parse(arguments); - if (parser->isSet(helpOption)) - return CommandLineParseHelpRequested; - if (!success) { - *errorMessage = parser->errorText(); - return CommandLineParseError; - } - - options->libraryDirectory = parser->value(libDirOption); - options->pluginDirectory = parser->value(pluginDirOption); - options->plugins = !parser->isSet(noPluginsOption); - options->libraries = !parser->isSet(noLibraryOption); - options->translations = !parser->isSet(noTranslationOption); - if (parser->isSet(translationOption)) - options->languages = parser->value(translationOption).split(QLatin1Char(',')); - options->systemD3dCompiler = !parser->isSet(noSystemD3DCompilerOption); - options->quickImports = !parser->isSet(noQuickImportOption); - - if (parser->isSet(compilerRunTimeOption)) - options->compilerRunTime = true; - else if (parser->isSet(noCompilerRunTimeOption)) - options->compilerRunTime = false; - - if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) { - *errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only."); - return CommandLineParseError; - } - - if (parser->isSet(noVirtualKeyboardOption)) - options->disabledPlugins |= QtVirtualKeyboardPlugin; - - if (parser->isSet(releaseWithDebugInfoOption)) - std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete."; - - switch (parseExclusiveOptions(parser, debugOption, releaseOption)) { - case OptionAuto: - break; - case OptionEnabled: - options->debugDetection = Options::DebugDetectionForceDebug; - break; - case OptionDisabled: - options->debugDetection = Options::DebugDetectionForceRelease; - break; - } - - if (parser->isSet(deployPdbOption)) { - if (options->platform.testFlag(WindowsBased) && !options->platform.testFlag(MinGW)) - options->deployPdb = true; - else - std::wcerr << "Warning: --" << deployPdbOption.names().first() << " is not supported on this platform.\n"; - } - - if (parser->isSet(suppressSoftwareRasterizerOption)) - options->softwareRasterizer = false; - - optWebKit2 = parseExclusiveOptions(parser, webKitOption, noWebKitOption); - - if (parser->isSet(forceOption)) - options->updateFileFlags |= ForceUpdateFile; - if (parser->isSet(dryRunOption)) { - options->dryRun = true; - options->updateFileFlags |= SkipUpdateFile; - } - - options->patchQt = !parser->isSet(noPatchQtOption); - options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption); - - for (int i = 0; i < qtModulesCount; ++i) { - if (parser->isSet(*enabledModuleOptions.at(i))) - options->additionalLibraries |= qtModuleEntries[i].module; - if (parser->isSet(*disabledModuleOptions.at(i))) - options->disabledLibraries |= qtModuleEntries[i].module; - } - - // Add some dependencies - if (options->additionalLibraries & QtQuickModule) - options->additionalLibraries |= QtQmlModule; - if (options->additionalLibraries & QtDesignerComponents) - options->additionalLibraries |= QtDesignerModule; - - if (parser->isSet(listOption)) { - const QString value = parser->value(listOption); - if (value == QStringLiteral("source")) { - options->list = ListSource; - } else if (value == QStringLiteral("target")) { - options->list = ListTarget; - } else if (value == QStringLiteral("relative")) { - options->list = ListRelative; - } else if (value == QStringLiteral("mapping")) { - options->list = ListMapping; - } else { - *errorMessage = QStringLiteral("Please specify a valid option for -list (source, target, relative, mapping)."); - return CommandLineParseError; - } - } - - if (parser->isSet(jsonOption) || options->list) { - optVerboseLevel = 0; - options->json = new JsonOutput; - } else { - if (parser->isSet(verboseOption)) { - bool ok; - const QString value = parser->value(verboseOption); - optVerboseLevel = value.toInt(&ok); - if (!ok || optVerboseLevel < 0) { - *errorMessage = QStringLiteral("Invalid value \"%1\" passed for verbose level.").arg(value); - return CommandLineParseError; - } - } - } - - const QStringList posArgs = parser->positionalArguments(); - if (posArgs.isEmpty()) { - *errorMessage = QStringLiteral("Please specify the binary or folder."); - return CommandLineParseError | CommandLineParseHelpRequested; - } - - if (parser->isSet(dirOption)) - options->directory = parser->value(dirOption); - - if (parser->isSet(qmakeOption)) { - const QString qmakePath = QDir::cleanPath(parser->value(qmakeOption)); - const QFileInfo fi(qmakePath); - if (!fi.exists()) { - *errorMessage = msgFileDoesNotExist(qmakePath); - return CommandLineParseError; - } - - if (!fi.isExecutable()) { - *errorMessage = QLatin1Char('"') + QDir::toNativeSeparators(qmakePath) - + QStringLiteral("\" is not an executable."); - return CommandLineParseError; - } - options->qmakePath = qmakePath; - } - - if (parser->isSet(qmlDirOption)) - options->qmlDirectories = parser->values(qmlDirOption); - - if (parser->isSet(qmlImportOption)) - options->qmlImportPaths = parser->values(qmlImportOption); - - const QString &file = posArgs.front(); - const QFileInfo fi(QDir::cleanPath(file)); - if (!fi.exists()) { - *errorMessage = msgFileDoesNotExist(file); - return CommandLineParseError; - } - - if (!options->directory.isEmpty() && !fi.isFile()) { // -dir was specified - expecting file. - *errorMessage = QLatin1Char('"') + file + QStringLiteral("\" is not an executable file."); - return CommandLineParseError; - } - - if (fi.isFile()) { - options->binaries.append(fi.absoluteFilePath()); - if (options->directory.isEmpty()) - options->directory = fi.absolutePath(); - } else { - const QString binary = findBinary(fi.absoluteFilePath(), options->platform); - if (binary.isEmpty()) { - *errorMessage = QStringLiteral("Unable to find binary in \"") + file + QLatin1Char('"'); - return CommandLineParseError; - } - options->directory = fi.absoluteFilePath(); - options->binaries.append(binary); - } // directory. - - // Remaining files or plugin directories - for (int i = 1; i < posArgs.size(); ++i) { - const QFileInfo fi(QDir::cleanPath(posArgs.at(i))); - const QString path = fi.absoluteFilePath(); - if (!fi.exists()) { - *errorMessage = msgFileDoesNotExist(path); - return CommandLineParseError; - } - if (fi.isDir()) { - const QStringList libraries = - findSharedLibraries(QDir(path), options->platform, MatchDebugOrRelease, QString()); - for (const QString &library : libraries) - options->binaries.append(path + QLatin1Char('/') + library); - } else { - options->binaries.append(path); - } - } - options->translationsDirectory = options->directory + QLatin1String("/translations"); - return 0; -} - -// Simple line wrapping at 80 character boundaries. -static inline QString lineBreak(QString s) -{ - for (int i = 80; i < s.size(); i += 80) { - const int lastBlank = s.lastIndexOf(QLatin1Char(' '), i); - if (lastBlank >= 0) { - s[lastBlank] = QLatin1Char('\n'); - i = lastBlank + 1; - } - } - return s; -} - -static inline QString helpText(const QCommandLineParser &p) -{ - QString result = p.helpText(); - // Replace the default-generated text which is too long by a short summary - // explaining how to enable single libraries. - const int moduleStart = result.indexOf(QLatin1String("\n --bluetooth")); - const int argumentsStart = result.lastIndexOf(QLatin1String("\nArguments:")); - if (moduleStart >= argumentsStart) - return result; - QString moduleHelp = QLatin1String( - "\n\nQt libraries can be added by passing their name (-xml) or removed by passing\n" - "the name prepended by --no- (--no-xml). Available libraries:\n"); - moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(0xFFFFFFFFFFFFFFFFull, true))); - moduleHelp += QLatin1Char('\n'); - result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp); - return result; -} - -static inline bool isQtModule(const QString &libName) -{ - // Match Standard modules named Qt6XX.dll - if (libName.size() < 3 || !libName.startsWith(QLatin1String("Qt"), Qt::CaseInsensitive)) - return false; - const QChar version = libName.at(2); - return version.isDigit() && (version.toLatin1() - '0') == QT_VERSION_MAJOR; -} - -// Helper for recursively finding all dependent Qt libraries. -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) -{ - QStringList dependentLibs; - if (directDependencyCount) - *directDependencyCount = 0; - if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug, machineArch)) { - errorMessage->prepend(QLatin1String("Unable to find dependent libraries of ") + - QDir::toNativeSeparators(binary) + QLatin1String(" :")); - return false; - } - // Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we - // are run the 2nd time (updating). We want to check against the Qt bin dir libraries - const int start = result->size(); - for (const QString &lib : qAsConst(dependentLibs)) { - if (isQtModule(lib)) { - const QString path = normalizeFileName(qtBinDir + QLatin1Char('/') + QFileInfo(lib).fileName()); - if (!result->contains(path)) - result->append(path); - } - } - const int end = result->size(); - if (directDependencyCount) - *directDependencyCount = end - start; - // Recurse - for (int i = start; i < end; ++i) - if (!findDependentQtLibraries(qtBinDir, result->at(i), platform, errorMessage, result, - nullptr, nullptr, nullptr, nullptr, recursionDepth + 1)) - return false; - return true; -} - -// Base class to filter debug/release Windows DLLs for functions to be passed to updateFile(). -// Tries to pre-filter by namefilter and does check via PE. -class DllDirectoryFileEntryFunction { -public: - explicit DllDirectoryFileEntryFunction(Platform platform, - DebugMatchMode debugMatchMode, const QString &prefix = QString()) : - m_platform(platform), m_debugMatchMode(debugMatchMode), m_prefix(prefix) {} - - QStringList operator()(const QDir &dir) const - { return findSharedLibraries(dir, m_platform, m_debugMatchMode, m_prefix); } - -private: - const Platform m_platform; - const DebugMatchMode m_debugMatchMode; - const QString m_prefix; -}; - -static QString pdbFileName(QString libraryFileName) -{ - const int lastDot = libraryFileName.lastIndexOf(QLatin1Char('.')) + 1; - if (lastDot <= 0) - return QString(); - libraryFileName.replace(lastDot, libraryFileName.size() - lastDot, QLatin1String("pdb")); - return libraryFileName; -} -static inline QStringList qmlCacheFileFilters() -{ - return QStringList() << QStringLiteral("*.jsc") << QStringLiteral("*.qmlc"); -} - -// File entry filter function for updateFile() that returns a list of files for -// QML import trees: DLLs (matching debgug) and .qml/,js, etc. -class QmlDirectoryFileEntryFunction { -public: - enum Flags { - DeployPdb = 0x1, - SkipSources = 0x2 - }; - - explicit QmlDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, unsigned flags) - : m_flags(flags), m_qmlNameFilter(QmlDirectoryFileEntryFunction::qmlNameFilters(flags)) - , m_dllFilter(platform, debugMatchMode) - {} - - QStringList operator()(const QDir &dir) const - { - QStringList result; - const QStringList &libraries = m_dllFilter(dir); - for (const QString &library : libraries) { - result.append(library); - if (m_flags & DeployPdb) { - const QString pdb = pdbFileName(library); - if (QFileInfo(dir.absoluteFilePath(pdb)).isFile()) - result.append(pdb); - } - } - result.append(m_qmlNameFilter(dir)); - return result; - } - -private: - static inline QStringList qmlNameFilters(unsigned flags) - { - QStringList result; - result << QStringLiteral("qmldir") << QStringLiteral("*.qmltypes") - << QStringLiteral("*.frag") << QStringLiteral("*.vert") // Shaders - << QStringLiteral("*.ttf"); - if (!(flags & SkipSources)) { - result << QStringLiteral("*.js") << QStringLiteral("*.qml") << QStringLiteral("*.png"); - result.append(qmlCacheFileFilters()); - } - return result; - } - - const unsigned m_flags; - NameFilterFileEntryFunction m_qmlNameFilter; - DllDirectoryFileEntryFunction m_dllFilter; -}; - -struct PluginModuleMapping -{ - const char *directoryName; - quint64 module; -}; - -static const PluginModuleMapping pluginModuleMappings[] = -{ - {"qml1tooling", QtDeclarativeModule}, - {"gamepads", QtGamePadModule}, - {"accessible", QtGuiModule}, - {"iconengines", QtGuiModule}, - {"imageformats", QtGuiModule}, - {"platforms", QtGuiModule}, - {"platforminputcontexts", QtGuiModule}, - {"virtualkeyboard", QtGuiModule}, - {"geoservices", QtLocationModule}, - {"audio", QtMultimediaModule}, - {"mediaservice", QtMultimediaModule}, - {"playlistformats", QtMultimediaModule}, - {"bearer", QtNetworkModule}, - {"position", QtPositioningModule}, - {"printsupport", QtPrintSupportModule}, - {"scenegraph", QtQuickModule}, - {"qmltooling", QtQuickModule | QtQmlToolingModule}, - {"sensors", QtSensorsModule}, - {"sensorgestures", QtSensorsModule}, - {"canbus", QtSerialBusModule}, - {"sqldrivers", QtSqlModule}, - {"texttospeech", QtTextToSpeechModule}, - {"qtwebengine", QtWebEngineModule | QtWebEngineCoreModule | QtWebEngineWidgetsModule}, - {"styles", QtWidgetsModule}, - {"sceneparsers", Qt3DRendererModule}, - {"renderers", Qt3DRendererModule}, - {"renderplugins", Qt3DRendererModule}, - {"geometryloaders", Qt3DRendererModule}, - {"webview", QtWebViewModule} -}; - -static inline quint64 qtModuleForPlugin(const QString &subDirName) -{ - const auto end = std::end(pluginModuleMappings); - const auto result = - std::find_if(std::begin(pluginModuleMappings), end, - [&subDirName] (const PluginModuleMapping &m) { return subDirName == QLatin1String(m.directoryName); }); - return result != end ? result->module : 0; // "designer" -} - -static quint64 qtModule(QString module, const QString &infix) -{ - // Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0' - const int lastSlashPos = module.lastIndexOf(QLatin1Char('/')); - if (lastSlashPos > 0) - module.remove(0, lastSlashPos + 1); - if (module.startsWith(QLatin1String("lib"))) - module.remove(0, 3); - int endPos = infix.isEmpty() ? -1 : module.lastIndexOf(infix); - if (endPos == -1) - endPos = module.indexOf(QLatin1Char('.')); // strip suffixes '.so.5.0'. - if (endPos > 0) - module.truncate(endPos); - // That should leave us with 'Qt6Core<d>'. - for (const auto &qtModule : qtModuleEntries) { - const QLatin1String libraryName(qtModule.libraryName); - if (module == libraryName - || (module.size() == libraryName.size() + 1 && module.startsWith(libraryName))) { - return qtModule.module; - } - } - return 0; -} - -QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules, - unsigned disabledPlugins, - const QString &qtPluginsDirName, const QString &libraryLocation, - const QString &infix, - DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin) -{ - QString errorMessage; - if (qtPluginsDirName.isEmpty()) - return QStringList(); - QDir pluginsDir(qtPluginsDirName); - QStringList result; - const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(QLatin1String("*")), QDir::Dirs | QDir::NoDotAndDotDot); - for (const QFileInfo &subDirFi : pluginDirs) { - const QString subDirName = subDirFi.fileName(); - const quint64 module = qtModuleForPlugin(subDirName); - if (module & *usedQtModules) { - const DebugMatchMode debugMatchMode = (module & QtWebEngineCoreModule) - ? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all. - : debugMatchModeIn; - QDir subDir(subDirFi.absoluteFilePath()); - // Filter out disabled plugins - if ((disabledPlugins & QtVirtualKeyboardPlugin) && subDirName == QLatin1String("virtualkeyboard")) - continue; - if (disabledQtModules & QtQmlToolingModule && subDirName == QLatin1String("qmltooling")) - continue; - // Filter for platform or any. - QString filter; - const bool isPlatformPlugin = subDirName == QLatin1String("platforms"); - if (isPlatformPlugin) { - switch (platform) { - case WindowsDesktopMsvc: - case WindowsDesktopMinGW: - filter = QStringLiteral("qwindows"); - break; - case Unix: - filter = QStringLiteral("libqxcb"); - break; - case UnknownPlatform: - break; - } - } else { - filter = QLatin1String("*"); - } - const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter); - for (const QString &plugin : plugins) { - // Filter out disabled plugins - if ((disabledPlugins & QtVirtualKeyboardPlugin) - && plugin.startsWith(QLatin1String("qtvirtualkeyboardplugin"))) { - continue; - } - const QString pluginPath = subDir.absoluteFilePath(plugin); - if (isPlatformPlugin) - *platformPlugin = pluginPath; - QStringList dependentQtLibs; - quint64 neededModules = 0; - if (findDependentQtLibraries(libraryLocation, pluginPath, platform, &errorMessage, &dependentQtLibs)) { - for (int d = 0; d < dependentQtLibs.size(); ++ d) - neededModules |= qtModule(dependentQtLibs.at(d), infix); - } else { - std::wcerr << "Warning: Cannot determine dependencies of " - << QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n'; - } - if (const quint64 missingModules = neededModules & disabledQtModules) { - if (optVerboseLevel) { - std::wcout << "Skipping plugin " << plugin - << " due to disabled dependencies (" - << formatQtModules(missingModules).constData() << ").\n"; - } - } else { - if (const quint64 missingModules = (neededModules & ~*usedQtModules)) { - *usedQtModules |= missingModules; - if (optVerboseLevel) - std::wcout << "Adding " << formatQtModules(missingModules).constData() << " for " << plugin << '\n'; - } - result.append(pluginPath); - } - } // for filter - } // type matches - } // for plugin folder - return result; -} - -static QStringList translationNameFilters(quint64 modules, const QString &prefix) -{ - QStringList result; - for (const auto &qtModule : qtModuleEntries) { - if ((qtModule.module & modules) && qtModule.translation) { - const QString name = QLatin1String(qtModule.translation) + - QLatin1Char('_') + prefix + QStringLiteral(".qm"); - if (!result.contains(name)) - result.push_back(name); - } - } - return result; -} - -static bool deployTranslations(const QString &sourcePath, quint64 usedQtModules, - const QString &target, const Options &options, - QString *errorMessage) -{ - // Find available languages prefixes by checking on qtbase. - QStringList prefixes; - QDir sourceDir(sourcePath); - const QStringList qmFilter = QStringList(QStringLiteral("qtbase_*.qm")); - const QFileInfoList &qmFiles = sourceDir.entryInfoList(qmFilter); - for (const QFileInfo &qmFi : qmFiles) { - const QString prefix = qmFi.baseName().mid(7); - if (options.languages.isEmpty() || options.languages.contains(prefix)) - prefixes.append(prefix); - } - if (prefixes.isEmpty()) { - std::wcerr << "Warning: Could not find any translations in " - << QDir::toNativeSeparators(sourcePath) << " (developer build?)\n."; - return true; - } - // Run lconvert to concatenate all files into a single named "qt_<prefix>.qm" in the application folder - // Use QT_INSTALL_TRANSLATIONS as working directory to keep the command line short. - const QString absoluteTarget = QFileInfo(target).absoluteFilePath(); - const QString binary = QStringLiteral("lconvert"); - QStringList arguments; - for (const QString &prefix : qAsConst(prefixes)) { - arguments.clear(); - const QString targetFile = QStringLiteral("qt_") + prefix + QStringLiteral(".qm"); - arguments.append(QStringLiteral("-o")); - const QString targetFilePath = absoluteTarget + QLatin1Char('/') + targetFile; - if (options.json) - options.json->addFile(sourcePath + QLatin1Char('/') + targetFile, absoluteTarget); - arguments.append(QDir::toNativeSeparators(targetFilePath)); - const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationNameFilters(usedQtModules, prefix)); - for (const QFileInfo &langQmFileFi : langQmFiles) { - if (options.json) { - options.json->addFile(langQmFileFi.absoluteFilePath(), - absoluteTarget); - } - arguments.append(langQmFileFi.fileName()); - } - if (optVerboseLevel) - std::wcout << "Creating " << targetFile << "...\n"; - unsigned long exitCode; - if ((options.updateFileFlags & SkipUpdateFile) == 0 - && (!runProcess(binary, arguments, sourcePath, &exitCode, nullptr, nullptr, errorMessage) - || exitCode)) { - return false; - } - } // for prefixes. - return true; -} - -struct DeployResult -{ - operator bool() const { return success; } - - bool success = false; - bool isDebug = false; - quint64 directlyUsedQtLibraries = 0; - quint64 usedQtLibraries = 0; - quint64 deployedQtLibraries = 0; -}; - -static QString libraryPath(const QString &libraryLocation, const char *name, - const QString &qtLibInfix, Platform platform, bool debug) -{ - QString result = libraryLocation + QLatin1Char('/'); - if (platform & WindowsBased) { - result += QLatin1String(name); - result += qtLibInfix; - if (debug && platformHasDebugSuffix(platform)) - result += QLatin1Char('d'); - } else if (platform.testFlag(UnixBased)) { - result += QStringLiteral("lib"); - result += QLatin1String(name); - result += qtLibInfix; - } - result += sharedLibrarySuffix(platform); - return result; -} - -static QString vcDebugRedistDir() { return QStringLiteral("Debug_NonRedist"); } - -static QString vcRedistDir() -{ - const char vcDirVar[] = "VCINSTALLDIR"; - const QChar slash(QLatin1Char('/')); - QString vcRedistDirName = QDir::cleanPath(QFile::decodeName(qgetenv(vcDirVar))); - if (vcRedistDirName.isEmpty()) { - std::wcerr << "Warning: Cannot find Visual Studio installation directory, " << vcDirVar - << " is not set.\n"; - return QString(); - } - if (!vcRedistDirName.endsWith(slash)) - vcRedistDirName.append(slash); - vcRedistDirName.append(QStringLiteral("redist")); - if (!QFileInfo(vcRedistDirName).isDir()) { - std::wcerr << "Warning: Cannot find Visual Studio redist directory, " - << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n"; - return QString(); - } - const QString vc2017RedistDirName = vcRedistDirName + QStringLiteral("/MSVC"); - if (!QFileInfo(vc2017RedistDirName).isDir()) - return vcRedistDirName; // pre 2017 - // Look in reverse order for folder containing the debug redist folder - const QFileInfoList subDirs = - QDir(vc2017RedistDirName).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed); - const bool isWindows10 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10; - for (const QFileInfo &f : subDirs) { - QString path = f.absoluteFilePath(); - if (QFileInfo(path + slash + vcDebugRedistDir()).isDir()) - return path; - if (isWindows10) { - path += QStringLiteral("/onecore"); - if (QFileInfo(path + slash + vcDebugRedistDir()).isDir()) - return path; - } - } - std::wcerr << "Warning: Cannot find Visual Studio redist directory under " - << QDir::toNativeSeparators(vc2017RedistDirName).toStdWString() << ".\n"; - return QString(); -} - -static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned short machineArch) -{ - QStringList result; - switch (platform) { - case WindowsDesktopMinGW: { // MinGW: Add runtime libraries - static const char *minGwRuntimes[] = {"*gcc_", "*stdc++", "*winpthread"}; - const QString gcc = findInPath(QStringLiteral("g++.exe")); - if (gcc.isEmpty()) { - std::wcerr << "Warning: Cannot find GCC installation directory. g++.exe must be in the path.\n"; - break; - } - const QString binPath = QFileInfo(gcc).absolutePath(); - QStringList filters; - const QString suffix = QLatin1Char('*') + sharedLibrarySuffix(platform); - for (auto minGwRuntime : minGwRuntimes) - filters.append(QLatin1String(minGwRuntime) + suffix); - const QFileInfoList &dlls = QDir(binPath).entryInfoList(filters, QDir::Files); - for (const QFileInfo &dllFi : dlls) - result.append(dllFi.absoluteFilePath()); - } - break; -#ifdef Q_OS_WIN - case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages. - QString vcRedistDirName = vcRedistDir(); - if (vcRedistDirName.isEmpty()) - break; - QStringList redistFiles; - QDir vcRedistDir(vcRedistDirName); - const QString machineArchString = getArchString(machineArch); - if (isDebug) { - // Append DLLs from Debug_NonRedist\x??\Microsoft.VC<version>.DebugCRT. - if (vcRedistDir.cd(vcDebugRedistDir()) && vcRedistDir.cd(machineArchString)) { - const QStringList names = vcRedistDir.entryList(QStringList(QStringLiteral("Microsoft.VC*.DebugCRT")), QDir::Dirs); - if (!names.isEmpty() && vcRedistDir.cd(names.first())) { - const QFileInfoList &dlls = vcRedistDir.entryInfoList(QStringList(QLatin1String("*.dll"))); - for (const QFileInfo &dll : dlls) - redistFiles.append(dll.absoluteFilePath()); - } - } - } else { // release: Bundle vcredist<>.exe - QString releaseRedistDir = vcRedistDirName; - const QStringList countryCodes = vcRedistDir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Dirs); - if (!countryCodes.isEmpty()) // Pre MSVC2017 - releaseRedistDir += QLatin1Char('/') + countryCodes.constFirst(); - QFileInfo fi(releaseRedistDir + QLatin1Char('/') + QStringLiteral("vc_redist.") - + machineArchString + QStringLiteral(".exe")); - if (!fi.isFile()) { // Pre MSVC2017/15.5 - fi.setFile(releaseRedistDir + QLatin1Char('/') + QStringLiteral("vcredist_") - + machineArchString + QStringLiteral(".exe")); - } - if (fi.isFile()) - redistFiles.append(fi.absoluteFilePath()); - } - if (redistFiles.isEmpty()) { - std::wcerr << "Warning: Cannot find Visual Studio " << (isDebug ? "debug" : "release") - << " redistributable files in " << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n"; - break; - } - result.append(redistFiles); - } - break; -#endif // Q_OS_WIN - default: - break; - } - return result; -} - -static inline int qtVersion(const QMap<QString, QString> &qmakeVariables) -{ - const QString versionString = qmakeVariables.value(QStringLiteral("QT_VERSION")); - const QChar dot = QLatin1Char('.'); - const int majorVersion = versionString.section(dot, 0, 0).toInt(); - const int minorVersion = versionString.section(dot, 1, 1).toInt(); - const int patchVersion = versionString.section(dot, 2, 2).toInt(); - return (majorVersion << 16) | (minorVersion << 8) | patchVersion; -} - -// Determine the Qt lib infix from the library path of "Qt6Core<qtblibinfix>[d].dll". -static inline QString qtlibInfixFromCoreLibName(const QString &path, bool isDebug, Platform platform) -{ - const int startPos = path.lastIndexOf(QLatin1Char('/')) + 8; - int endPos = path.lastIndexOf(QLatin1Char('.')); - if (isDebug && (platform & WindowsBased)) - endPos--; - return endPos > startPos ? path.mid(startPos, endPos - startPos) : QString(); -} - -// Deploy a library along with its .pdb debug info file (MSVC) should it exist. -static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory, - const Options &options, QString *errorMessage) -{ - if (!updateFile(sourceFileName, targetDirectory, options.updateFileFlags, options.json, errorMessage)) { - if (options.ignoreLibraryErrors) { - std::wcerr << "Warning: Could not update " << sourceFileName << " :" << *errorMessage << '\n'; - errorMessage->clear(); - return true; - } - return false; - } - - if (options.deployPdb) { - const QFileInfo pdb(pdbFileName(sourceFileName)); - if (pdb.isFile()) - return updateFile(pdb.absoluteFilePath(), targetDirectory, options.updateFileFlags, nullptr, errorMessage); - } - return true; -} - -// Find out the ICU version to add the data library icudtXX.dll, which does not -// show as a dependency. -static QString getIcuVersion(const QString &libName) -{ - QString version; - std::copy_if(libName.cbegin(), libName.cend(), std::back_inserter(version), - [](QChar c) { return c.isDigit(); }); - return version; -} - -static DeployResult deploy(const Options &options, - const QMap<QString, QString> &qmakeVariables, - QString *errorMessage) -{ - DeployResult result; - - const QChar slash = QLatin1Char('/'); - - const QString qtBinDir = qmakeVariables.value(QStringLiteral("QT_INSTALL_BINS")); - const QString libraryLocation = options.platform == Unix ? qmakeVariables.value(QStringLiteral("QT_INSTALL_LIBS")) : qtBinDir; - const QString infix = qmakeVariables.value(QLatin1String(qmakeInfixKey)); - const int version = qtVersion(qmakeVariables); - Q_UNUSED(version); - - if (optVerboseLevel > 1) - std::wcout << "Qt binaries in " << QDir::toNativeSeparators(qtBinDir) << '\n'; - - QStringList dependentQtLibs; - bool detectedDebug; - unsigned wordSize; - unsigned short machineArch; - int directDependencyCount = 0; - if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform, errorMessage, &dependentQtLibs, &wordSize, - &detectedDebug, &machineArch, &directDependencyCount)) { - return result; - } - for (int b = 1; b < options.binaries.size(); ++b) { - if (!findDependentQtLibraries(libraryLocation, options.binaries.at(b), options.platform, errorMessage, &dependentQtLibs, - nullptr, nullptr, nullptr)) { - return result; - } - } - - DebugMatchMode debugMatchMode = MatchDebugOrRelease; - result.isDebug = false; - switch (options.debugDetection) { - case Options::DebugDetectionAuto: - // Debug detection is only relevant for Msvc/ClangMsvc which have distinct - // runtimes and binaries. For anything else, use MatchDebugOrRelease - // since also debug cannot be reliably detect for MinGW. - if (options.platform.testFlag(Msvc) || options.platform.testFlag(ClangMsvc)) { - result.isDebug = detectedDebug; - debugMatchMode = result.isDebug ? MatchDebug : MatchRelease; - } - break; - case Options::DebugDetectionForceDebug: - result.isDebug = true; - debugMatchMode = MatchDebug; - break; - case Options::DebugDetectionForceRelease: - debugMatchMode = MatchRelease; - break; - } - - // Determine application type, check Quick2 is used by looking at the - // direct dependencies (do not be fooled by QtWebKit depending on it). - QString qtLibInfix; - for (int m = 0; m < directDependencyCount; ++m) { - const quint64 module = qtModule(dependentQtLibs.at(m), infix); - result.directlyUsedQtLibraries |= module; - if (module == QtCoreModule) - qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform); - } - - const bool usesQml2 = !(options.disabledLibraries & QtQmlModule) - && ((result.directlyUsedQtLibraries & (QtQmlModule | QtQuickModule | Qt3DQuickModule)) - || (options.additionalLibraries & QtQmlModule)); - - if (optVerboseLevel) { - std::wcout << QDir::toNativeSeparators(options.binaries.first()) << ' ' - << wordSize << " bit, " << (result.isDebug ? "debug" : "release") - << " executable"; - if (usesQml2) - std::wcout << " [QML]"; - std::wcout << '\n'; - } - - if (dependentQtLibs.isEmpty()) { - *errorMessage = QDir::toNativeSeparators(options.binaries.first()) + QStringLiteral(" does not seem to be a Qt executable."); - return result; - } - - // Some Windows-specific checks: Qt5Core depends on ICU when configured with "-icu". Other than - // that, Qt5WebKit has a hard dependency on ICU. - if (options.platform.testFlag(WindowsBased)) { - const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral("Qt6Core"), Qt::CaseInsensitive) - + dependentQtLibs.filter(QStringLiteral("Qt5WebKit"), Qt::CaseInsensitive); - for (const QString &qtLib : qtLibs) { - QStringList icuLibs = findDependentLibraries(qtLib, options.platform, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive); - if (!icuLibs.isEmpty()) { - // Find out the ICU version to add the data library icudtXX.dll, which does not show - // as a dependency. - const QString icuVersion = getIcuVersion(icuLibs.constFirst()); - if (!icuVersion.isEmpty()) { - if (optVerboseLevel > 1) - std::wcout << "Adding ICU version " << icuVersion << '\n'; - icuLibs.push_back(QStringLiteral("icudt") + icuVersion + QLatin1String(windowsSharedLibrarySuffix)); - } - for (const QString &icuLib : qAsConst(icuLibs)) { - const QString icuPath = findInPath(icuLib); - if (icuPath.isEmpty()) { - *errorMessage = QStringLiteral("Unable to locate ICU library ") + icuLib; - return result; - } - dependentQtLibs.push_back(icuPath); - } // for each icuLib - break; - } // !icuLibs.isEmpty() - } // Qt6Core/Qt6WebKit - } // Windows - - // Scan Quick2 imports - QmlImportScanResult qmlScanResult; - if (options.quickImports && usesQml2) { - // Custom list of import paths provided by user - QStringList qmlImportPaths = options.qmlImportPaths; - // Qt's own QML modules - qmlImportPaths << qmakeVariables.value(QStringLiteral("QT_INSTALL_QML")); - QStringList qmlDirectories = options.qmlDirectories; - if (qmlDirectories.isEmpty()) { - const QString qmlDirectory = findQmlDirectory(options.platform, options.directory); - if (!qmlDirectory.isEmpty()) - qmlDirectories.append(qmlDirectory); - } - for (const QString &qmlDirectory : qAsConst(qmlDirectories)) { - if (optVerboseLevel >= 1) - std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n"; - const QmlImportScanResult scanResult = - runQmlImportScanner(qmlDirectory, qmlImportPaths, - result.directlyUsedQtLibraries & QtWidgetsModule, - options.platform, debugMatchMode, errorMessage); - if (!scanResult.ok) - return result; - qmlScanResult.append(scanResult); - // Additional dependencies of QML plugins. - for (const QString &plugin : qAsConst(qmlScanResult.plugins)) { - if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &detectedDebug, &machineArch)) - return result; - } - if (optVerboseLevel >= 1) { - std::wcout << "QML imports:\n"; - for (const QmlImportScanResult::Module &mod : qAsConst(qmlScanResult.modules)) { - std::wcout << " '" << mod.name << "' " - << QDir::toNativeSeparators(mod.sourcePath) << '\n'; - } - if (optVerboseLevel >= 2) { - std::wcout << "QML plugins:\n"; - for (const QString &p : qAsConst(qmlScanResult.plugins)) - std::wcout << " " << QDir::toNativeSeparators(p) << '\n'; - } - } - } - } - - QString platformPlugin; - // Sort apart Qt 5 libraries in the ones that are represented by the - // QtModule enumeration (and thus controlled by flags) and others. - QStringList deployedQtLibraries; - for (int i = 0 ; i < dependentQtLibs.size(); ++i) { - if (const quint64 qtm = qtModule(dependentQtLibs.at(i), infix)) - result.usedQtLibraries |= qtm; - else - deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag. - } - result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries; - - const QStringList plugins = - findQtPlugins(&result.deployedQtLibraries, - // For non-QML applications, disable QML to prevent it from being pulled in by the qtaccessiblequick plugin. - options.disabledLibraries | (usesQml2 ? 0 : (QtQmlModule | QtQuickModule)), - options.disabledPlugins, - qmakeVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")), libraryLocation, infix, - debugMatchMode, options.platform, &platformPlugin); - - // Apply options flags and re-add library names. - QString qtGuiLibrary; - for (const auto &qtModule : qtModuleEntries) { - if (result.deployedQtLibraries & qtModule.module) { - const QString library = libraryPath(libraryLocation, qtModule.libraryName, qtLibInfix, options.platform, result.isDebug); - deployedQtLibraries.append(library); - if (qtModule.module == QtGuiModule) - qtGuiLibrary = library; - } - } - - if (optVerboseLevel >= 1) { - std::wcout << "Direct dependencies: " << formatQtModules(result.directlyUsedQtLibraries).constData() - << "\nAll dependencies : " << formatQtModules(result.usedQtLibraries).constData() - << "\nTo be deployed : " << formatQtModules(result.deployedQtLibraries).constData() << '\n'; - } - - if (optVerboseLevel > 1) - std::wcout << "Plugins: " << plugins.join(QLatin1Char(',')) << '\n'; - - if ((result.deployedQtLibraries & QtGuiModule) && platformPlugin.isEmpty()) { - *errorMessage =QStringLiteral("Unable to find the platform plugin."); - return result; - } - - if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) { - const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, options.platform, errorMessage); - const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty(); - if (options.softwareRasterizer && !dependsOnOpenGl) { - const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1String(windowsSharedLibrarySuffix)); - if (softwareRasterizer.isFile()) - deployedQtLibraries.append(softwareRasterizer.absoluteFilePath()); - } - if (options.systemD3dCompiler && machineArch != IMAGE_FILE_MACHINE_ARM64) { - const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir, wordSize); - if (d3dCompiler.isEmpty()) { - std::wcerr << "Warning: Cannot find any version of the d3dcompiler DLL.\n"; - } else { - deployedQtLibraries.push_back(d3dCompiler); - } - } - } // Windows - - // Update libraries - if (options.libraries) { - const QString targetPath = options.libraryDirectory.isEmpty() ? - options.directory : options.libraryDirectory; - QStringList libraries = deployedQtLibraries; - if (options.compilerRunTime) - libraries.append(compilerRunTimeLibs(options.platform, result.isDebug, machineArch)); - for (const QString &qtLib : qAsConst(libraries)) { - if (!updateLibrary(qtLib, targetPath, options, errorMessage)) - return result; - } - - if (options.patchQt && !options.dryRun) { - const QString qt5CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", qtLibInfix, - options.platform, result.isDebug)).fileName(); -#ifndef QT_RELOCATABLE - if (!patchQtCore(targetPath + QLatin1Char('/') + qt6CoreName, errorMessage)) { - std::wcerr << "Warning: " << *errorMessage << '\n'; - errorMessage->clear(); - } -#endif - } - } // optLibraries - - // Update plugins - if (options.plugins) { - const QString targetPath = options.pluginDirectory.isEmpty() ? - options.directory : options.pluginDirectory; - QDir dir(targetPath); - if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) { - *errorMessage = QLatin1String("Cannot create ") + - QDir::toNativeSeparators(dir.absolutePath()) + QLatin1Char('.'); - return result; - } - for (const QString &plugin : plugins) { - const QString targetDirName = plugin.section(slash, -2, -2); - const QString targetPath = dir.absoluteFilePath(targetDirName); - if (!dir.exists(targetDirName)) { - if (optVerboseLevel) - std::wcout << "Creating directory " << targetPath << ".\n"; - if (!(options.updateFileFlags & SkipUpdateFile) && !dir.mkdir(targetDirName)) { - *errorMessage = QStringLiteral("Cannot create ") + targetDirName + QLatin1Char('.'); - return result; - } - } - if (!updateLibrary(plugin, targetPath, options, errorMessage)) - return result; - } - } // optPlugins - - // Update Quick imports - const bool usesQuick1 = result.deployedQtLibraries & QtDeclarativeModule; - // Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports - // for WebKit1-applications. Check direct dependency only. - if (options.quickImports && (usesQuick1 || usesQml2)) { - if (usesQml2) { - for (const QmlImportScanResult::Module &module : qAsConst(qmlScanResult.modules)) { - const QString installPath = module.installPath(options.directory); - if (optVerboseLevel > 1) - std::wcout << "Installing: '" << module.name - << "' from " << module.sourcePath << " to " - << QDir::toNativeSeparators(installPath) << '\n'; - if (installPath != options.directory && !createDirectory(installPath, errorMessage)) - return result; - unsigned updateFileFlags = options.updateFileFlags | SkipQmlDesignerSpecificsDirectories; - unsigned qmlDirectoryFileFlags = 0; - if (options.deployPdb) - qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb; - if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform, debugMatchMode, qmlDirectoryFileFlags), - installPath, updateFileFlags, options.json, errorMessage)) { - return result; - } - } - } // Quick 2 - if (usesQuick1) { - const QString quick1ImportPath = qmakeVariables.value(QStringLiteral("QT_INSTALL_IMPORTS")); - const QmlDirectoryFileEntryFunction qmlFileEntryFunction(options.platform, debugMatchMode, options.deployPdb ? QmlDirectoryFileEntryFunction::DeployPdb : 0); - QStringList quick1Imports(QStringLiteral("Qt")); - if (result.deployedQtLibraries & QtWebKitModule) - quick1Imports << QStringLiteral("QtWebKit"); - for (const QString &quick1Import : qAsConst(quick1Imports)) { - const QString sourceFile = quick1ImportPath + slash + quick1Import; - if (!updateFile(sourceFile, qmlFileEntryFunction, options.directory, options.updateFileFlags, options.json, errorMessage)) - return result; - } - } // Quick 1 - } // optQuickImports - - if (options.translations) { - if (!options.dryRun && !createDirectory(options.translationsDirectory, errorMessage)) - return result; - if (!deployTranslations(qmakeVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS")), - result.deployedQtLibraries, options.translationsDirectory, - options, errorMessage)) { - return result; - } - } - - result.success = true; - return result; -} - -static bool deployWebProcess(const QMap<QString, QString> &qmakeVariables, - const char *binaryName, - const Options &sourceOptions, QString *errorMessage) -{ - // Copy the web process and its dependencies - const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform); - const QString webProcessSource = qmakeVariables.value(QStringLiteral("QT_INSTALL_LIBEXECS")) + - QLatin1Char('/') + webProcess; - if (!updateFile(webProcessSource, sourceOptions.directory, sourceOptions.updateFileFlags, sourceOptions.json, errorMessage)) - return false; - Options options(sourceOptions); - options.binaries.append(options.directory + QLatin1Char('/') + webProcess); - options.quickImports = false; - options.translations = false; - return deploy(options, qmakeVariables, errorMessage); -} - -static bool deployWebEngineCore(const QMap<QString, QString> &qmakeVariables, - const Options &options, bool isDebug, QString *errorMessage) -{ - static const char *installDataFiles[] = {"icudtl.dat", - "qtwebengine_devtools_resources.pak", - "qtwebengine_resources.pak", - "qtwebengine_resources_100p.pak", - "qtwebengine_resources_200p.pak"}; - QByteArray webEngineProcessName(webEngineProcessC); - if (isDebug && platformHasDebugSuffix(options.platform)) - webEngineProcessName.append('d'); - if (optVerboseLevel) - std::wcout << "Deploying: " << webEngineProcessName.constData() << "...\n"; - if (!deployWebProcess(qmakeVariables, webEngineProcessName, options, errorMessage)) - return false; - const QString resourcesSubDir = QStringLiteral("/resources"); - const QString resourcesSourceDir - = qmakeVariables.value(QStringLiteral("QT_INSTALL_DATA")) + resourcesSubDir - + QLatin1Char('/'); - const QString resourcesTargetDir(options.directory + resourcesSubDir); - if (!createDirectory(resourcesTargetDir, errorMessage)) - return false; - for (auto installDataFile : installDataFiles) { - if (!updateFile(resourcesSourceDir + QLatin1String(installDataFile), - resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) { - return false; - } - } - const QFileInfo translations(qmakeVariables.value(QStringLiteral("QT_INSTALL_TRANSLATIONS")) - + QStringLiteral("/qtwebengine_locales")); - if (!translations.isDir()) { - std::wcerr << "Warning: Cannot find the translation files of the QtWebEngine module at " - << QDir::toNativeSeparators(translations.absoluteFilePath()) << ".\n"; - return true; - } - if (options.translations) { - // Copy the whole translations directory. - return createDirectory(options.translationsDirectory, errorMessage) - && updateFile(translations.absoluteFilePath(), options.translationsDirectory, - options.updateFileFlags, options.json, errorMessage); - } - // Translations have been turned off, but QtWebEngine needs at least one. - const QFileInfo enUSpak(translations.filePath() + QStringLiteral("/en-US.pak")); - if (!enUSpak.exists()) { - std::wcerr << "Warning: Cannot find " - << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) << ".\n"; - return true; - } - const QString webEngineTranslationsDir = options.translationsDirectory + QLatin1Char('/') - + translations.fileName(); - if (!createDirectory(webEngineTranslationsDir, errorMessage)) - return false; - return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir, - options.updateFileFlags, options.json, errorMessage); -} - -int main(int argc, char **argv) -{ - QCoreApplication a(argc, argv); - QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); - - const QByteArray qtBinPath = QFile::encodeName(QDir::toNativeSeparators(QCoreApplication::applicationDirPath())); - QByteArray path = qgetenv("PATH"); - if (!path.contains(qtBinPath)) { // QTBUG-39177, ensure Qt is in the path so that qt.conf is taken into account. - path += ';'; - path += qtBinPath; - qputenv("PATH", path); - } - - Options options; - QString errorMessage; - - { // Command line - QCommandLineParser parser; - QString errorMessage; - const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage); - if (result & CommandLineParseError) - std::wcerr << errorMessage << "\n\n"; - if (result & CommandLineParseHelpRequested) - std::fputs(qPrintable(helpText(parser)), stdout); - if (result & CommandLineParseError) - return 1; - if (result & CommandLineParseHelpRequested) - return 0; - } - - const QMap<QString, QString> qmakeVariables = queryQMakeAll(options.qmakePath, &errorMessage); - const QString xSpec = qmakeVariables.value(QStringLiteral("QMAKE_XSPEC")); - options.platform = platformFromMkSpec(xSpec); - if (options.platform == WindowsDesktopMinGW || options.platform == WindowsDesktopMsvc) - options.compilerRunTime = true; - - if (qmakeVariables.isEmpty() || xSpec.isEmpty() || !qmakeVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) { - std::wcerr << "Unable to query qmake: " << errorMessage << '\n'; - return 1; - } - - if (options.platform == UnknownPlatform) { - std::wcerr << "Unsupported platform " << xSpec << '\n'; - return 1; - } - - // Create directories - if (!createDirectory(options.directory, &errorMessage)) { - std::wcerr << errorMessage << '\n'; - return 1; - } - if (!options.libraryDirectory.isEmpty() && options.libraryDirectory != options.directory - && !createDirectory(options.libraryDirectory, &errorMessage)) { - std::wcerr << errorMessage << '\n'; - return 1; - } - - if (optWebKit2 == OptionEnabled) - options.additionalLibraries |= QtWebKitModule; - - - const DeployResult result = deploy(options, qmakeVariables, &errorMessage); - if (!result) { - std::wcerr << errorMessage << '\n'; - return 1; - } - - if ((optWebKit2 != OptionDisabled) - && (optWebKit2 == OptionEnabled - || ((result.deployedQtLibraries & QtWebKitModule) - && (result.directlyUsedQtLibraries & QtQuickModule)))) { - if (optVerboseLevel) - std::wcout << "Deploying: " << webKitProcessC << "...\n"; - if (!deployWebProcess(qmakeVariables, webKitProcessC, options, &errorMessage)) { - std::wcerr << errorMessage << '\n'; - return 1; - } - } - - if (result.deployedQtLibraries & QtWebEngineCoreModule) { - if (!deployWebEngineCore(qmakeVariables, options, result.isDebug, &errorMessage)) { - std::wcerr << errorMessage << '\n'; - return 1; - } - } - - if (options.json) { - if (options.list) - std::fputs(options.json->toList(options.list, options.directory).constData(), stdout); - else - std::fputs(options.json->toJson().constData(), stdout); - delete options.json; - options.json = nullptr; - } - - return 0; -} - -QT_END_NAMESPACE |