summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@qt.io>2021-11-18 14:58:02 +0100
committerJoerg Bornemann <joerg.bornemann@qt.io>2021-11-26 18:10:44 +0100
commit4d8ca0d6c3c15ab0b92cbc4b8913a0f092fd8bdd (patch)
treeedaee42b4dfdd13d345fa6b64c6a19bb726c2769
parentb6c369549425a660a51a3dc06c19f55f9a72076f (diff)
Remove macdeployqt and windeployqt
These tools have been moved to qtbase. Change-Id: Idaf799d44be399040f9058252675c0ee3eecc39b Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Iikka Eklund <iikka.eklund@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r--conanfile.py4
-rw-r--r--configure.cmake14
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/macdeployqt/CMakeLists.txt6
-rw-r--r--src/macdeployqt/macdeployqt/CMakeLists.txt13
-rw-r--r--src/macdeployqt/macdeployqt/main.cpp278
-rw-r--r--src/macdeployqt/shared/shared.cpp1603
-rw-r--r--src/macdeployqt/shared/shared.h141
-rw-r--r--src/shared/winutils/elfreader.cpp440
-rw-r--r--src/shared/winutils/elfreader.h176
-rw-r--r--src/shared/winutils/qmlutils.cpp160
-rw-r--r--src/shared/winutils/qmlutils.h65
-rw-r--r--src/shared/winutils/utils.cpp1006
-rw-r--r--src/shared/winutils/utils.h404
-rw-r--r--src/windeployqt/CMakeLists.txt46
-rw-r--r--src/windeployqt/main.cpp1723
-rw-r--r--tests/auto/CMakeLists.txt6
-rw-r--r--tests/auto/macdeployqt/CMakeLists.txt10
-rw-r--r--tests/auto/macdeployqt/source_basicapp/basicapp.pro1
-rw-r--r--tests/auto/macdeployqt/source_basicapp/main.cpp44
-rw-r--r--tests/auto/macdeployqt/source_plugin_sqlite/main.cpp36
-rw-r--r--tests/auto/macdeployqt/source_plugin_sqlite/plugin_sqlite.pro2
-rw-r--r--tests/auto/macdeployqt/source_plugin_tls/main.cpp35
-rw-r--r--tests/auto/macdeployqt/source_plugin_tls/plugin_tls.pro2
-rw-r--r--tests/auto/macdeployqt/tst_macdeployqt.cpp316
-rw-r--r--tests/auto/windeployqt/CMakeLists.txt4
-rw-r--r--tests/auto/windeployqt/test/CMakeLists.txt11
-rw-r--r--tests/auto/windeployqt/testapp/CMakeLists.txt21
-rw-r--r--tests/auto/windeployqt/testapp/main.cpp46
-rw-r--r--tests/auto/windeployqt/tst_windeployqt.cpp181
30 files changed, 1 insertions, 6799 deletions
diff --git a/conanfile.py b/conanfile.py
index a244b2507..26be27021 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -37,14 +37,12 @@ _qttools_features = [
"distancefieldgenerator",
"kmap2qmap",
"linguist",
- "macdeployqt",
"pixeltool",
"qdbus",
"qev",
"qtattributionsscanner",
"qtdiag",
"qtplugininfo",
- "windeployqt",
]
@@ -67,7 +65,7 @@ class QtTools(ConanFile):
"Qt Tools run on all the supported development platforms and facilitate "
"the development and design of applications."
)
- topics = "qt", "qt6", "qttools", "assistant", "designer", "qdoc", "macdeployqt", "windeployqt"
+ topics = "qt", "qt6", "qttools", "assistant", "designer", "qdoc",
settings = "os", "compiler", "arch", "build_type"
# for referencing the version number and prerelease tag and dependencies info
exports = ".cmake.conf", "dependencies.yaml"
diff --git a/configure.cmake b/configure.cmake
index 67dfa0193..04e717f44 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -1,5 +1,3 @@
-
-
#### Inputs
@@ -69,11 +67,6 @@ qt_feature("linguist" PRIVATE
LABEL "Qt Linguist"
PURPOSE "Qt Linguist can be used by translator to translate text in Qt applications."
)
-qt_feature("macdeployqt" PRIVATE
- LABEL "Mac Deployment Tool"
- PURPOSE "The Mac deployment tool automates the process of creating a deployable application bundle that contains the Qt libraries as private frameworks."
- CONDITION MACOS
-)
qt_feature("pixeltool" PRIVATE
LABEL "pixeltool"
PURPOSE "The Qt Pixel Zooming Tool is a graphical application that magnifies the screen around the mouse pointer so you can look more closely at individual pixels."
@@ -103,11 +96,6 @@ qt_feature("qtplugininfo" PRIVATE
PURPOSE "qtplugininfo dumps metadata about Qt plugins in JSON format."
CONDITION QT_FEATURE_commandlineparser AND QT_FEATURE_library AND (android_app OR NOT ANDROID)
)
-qt_feature("windeployqt" PRIVATE
- LABEL "Windows deployment tool"
- PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package."
- CONDITION WIN32
-)
qt_configure_add_summary_section(NAME "Qt Tools")
qt_configure_add_summary_entry(ARGS "assistant")
qt_configure_add_summary_entry(ARGS "clang")
@@ -116,14 +104,12 @@ qt_configure_add_summary_entry(ARGS "designer")
qt_configure_add_summary_entry(ARGS "distancefieldgenerator")
#qt_configure_add_summary_entry(ARGS "kmap2qmap")
qt_configure_add_summary_entry(ARGS "linguist")
-qt_configure_add_summary_entry(ARGS "macdeployqt")
qt_configure_add_summary_entry(ARGS "pixeltool")
qt_configure_add_summary_entry(ARGS "qdbus")
#qt_configure_add_summary_entry(ARGS "qev")
qt_configure_add_summary_entry(ARGS "qtattributionsscanner")
qt_configure_add_summary_entry(ARGS "qtdiag")
qt_configure_add_summary_entry(ARGS "qtplugininfo")
-qt_configure_add_summary_entry(ARGS "windeployqt")
qt_configure_end_summary_section() # end of "Qt Tools" section
qt_configure_add_report_entry(
TYPE WARNING
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ef50f7905..cb0c21a70 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -47,15 +47,9 @@ endif()
if(QT_FEATURE_clang AND QT_FEATURE_commandlineparser AND QT_FEATURE_thread)
add_subdirectory(qdoc)
endif()
-if(QT_FEATURE_macdeployqt)
- add_subdirectory(macdeployqt)
-endif()
if(QT_FEATURE_qdbus)
add_subdirectory(qdbus)
endif()
-if(QT_FEATURE_windeployqt) # special case
- add_subdirectory(windeployqt)
-endif()
if(QT_FEATURE_qtdiag)
add_subdirectory(qtdiag)
endif()
diff --git a/src/macdeployqt/CMakeLists.txt b/src/macdeployqt/CMakeLists.txt
deleted file mode 100644
index cbce4e4ca..000000000
--- a/src/macdeployqt/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-# Generated from macdeployqt.pro.
-
-if(NOT QT_FEATURE_macdeployqt)
- return()
-endif()
-add_subdirectory(macdeployqt)
diff --git a/src/macdeployqt/macdeployqt/CMakeLists.txt b/src/macdeployqt/macdeployqt/CMakeLists.txt
deleted file mode 100644
index 0c63a877f..000000000
--- a/src/macdeployqt/macdeployqt/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# Generated from macdeployqt.pro.
-
-#####################################################################
-## macdeployqt App:
-#####################################################################
-
-qt_internal_add_app(macdeployqt
- SOURCES
- ../shared/shared.cpp
- main.cpp
- PUBLIC_LIBRARIES
- ${FWCoreFoundation}
-)
diff --git a/src/macdeployqt/macdeployqt/main.cpp b/src/macdeployqt/macdeployqt/main.cpp
deleted file mode 100644
index 145ee854a..000000000
--- a/src/macdeployqt/macdeployqt/main.cpp
+++ /dev/null
@@ -1,278 +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 <QCoreApplication>
-#include <QDir>
-#include <QLibraryInfo>
-
-#include "../shared/shared.h"
-
-int main(int argc, char **argv)
-{
- QCoreApplication app(argc, argv);
-
- QString appBundlePath;
- if (argc > 1)
- appBundlePath = QString::fromLocal8Bit(argv[1]);
-
- if (argc < 2 || appBundlePath.startsWith("-")) {
- qDebug() << "Usage: macdeployqt app-bundle [options]";
- qDebug() << "";
- qDebug() << "Options:";
- qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug";
- qDebug() << " -no-plugins : Skip plugin deployment";
- qDebug() << " -dmg : Create a .dmg disk image";
- qDebug() << " -no-strip : Don't run 'strip' on the binaries";
- qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)";
- qDebug() << " -executable=<path> : Let the given executable use the deployed frameworks too";
- qDebug() << " -qmldir=<path> : Scan for QML imports in the given path";
- qDebug() << " -qmlimport=<path> : Add the given path to the QML module search locations";
- qDebug() << " -always-overwrite : Copy files even if the target file exists";
- qDebug() << " -codesign=<ident> : Run codesign with the given identity on all executables";
- qDebug() << " -hardened-runtime : Enable Hardened Runtime when code signing";
- qDebug() << " -timestamp : Include a secure timestamp when code signing (requires internet connection)";
- qDebug() << " -sign-for-notarization=<ident>: Activate the necessary options for notarization (requires internet connection)";
- qDebug() << " -appstore-compliant : Skip deployment of components that use private API";
- qDebug() << " -libpath=<path> : Add the given path to the library search path";
- qDebug() << " -fs=<filesystem> : Set the filesystem used for the .dmg disk image (defaults to HFS+)";
- qDebug() << "";
- qDebug() << "macdeployqt takes an application bundle as input and makes it";
- qDebug() << "self-contained by copying in the Qt frameworks and plugins that";
- qDebug() << "the application uses.";
- qDebug() << "";
- qDebug() << "Plugins related to a framework are copied in with the";
- qDebug() << "framework. The accessibility, image formats, and text codec";
- qDebug() << "plugins are always copied, unless \"-no-plugins\" is specified.";
- qDebug() << "";
- qDebug() << "Qt plugins may use private API and will cause the app to be";
- qDebug() << "rejected from the Mac App store. MacDeployQt will print a warning";
- qDebug() << "when known incompatible plugins are deployed. Use -appstore-compliant ";
- qDebug() << "to skip these plugins. Currently two SQL plugins are known to";
- qDebug() << "be incompatible: qsqlodbc and qsqlpsql.";
- qDebug() << "";
- qDebug() << "See the \"Deploying Applications on OS X\" topic in the";
- qDebug() << "documentation for more information about deployment on OS X.";
-
- return 1;
- }
-
- appBundlePath = QDir::cleanPath(appBundlePath);
-
- if (!QDir(appBundlePath).exists()) {
- qDebug() << "Error: Could not find app bundle" << appBundlePath;
- return 1;
- }
-
- bool plugins = true;
- bool dmg = false;
- QByteArray filesystem("HFS+");
- bool useDebugLibs = false;
- extern bool runStripEnabled;
- extern bool alwaysOwerwriteEnabled;
- extern QStringList librarySearchPath;
- QStringList additionalExecutables;
- bool qmldirArgumentUsed = false;
- QStringList qmlDirs;
- QStringList qmlImportPaths;
- extern bool runCodesign;
- extern QString codesignIdentiy;
- extern bool hardenedRuntime;
- extern bool appstoreCompliant;
- extern bool deployFramework;
- extern bool secureTimestamp;
-
- for (int i = 2; i < argc; ++i) {
- QByteArray argument = QByteArray(argv[i]);
- if (argument == QByteArray("-no-plugins")) {
- LogDebug() << "Argument found:" << argument;
- plugins = false;
- } else if (argument == QByteArray("-dmg")) {
- LogDebug() << "Argument found:" << argument;
- dmg = true;
- } else if (argument == QByteArray("-no-strip")) {
- LogDebug() << "Argument found:" << argument;
- runStripEnabled = false;
- } else if (argument == QByteArray("-use-debug-libs")) {
- LogDebug() << "Argument found:" << argument;
- useDebugLibs = true;
- runStripEnabled = false;
- } else if (argument.startsWith(QByteArray("-verbose"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf("=");
- bool ok = false;
- int number = argument.mid(index+1).toInt(&ok);
- if (!ok)
- LogError() << "Could not parse verbose level";
- else
- logLevel = number;
- } else if (argument.startsWith(QByteArray("-executable"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf('=');
- if (index == -1)
- LogError() << "Missing executable path";
- else
- additionalExecutables << argument.mid(index+1);
- } else if (argument.startsWith(QByteArray("-qmldir"))) {
- LogDebug() << "Argument found:" << argument;
- qmldirArgumentUsed = true;
- int index = argument.indexOf('=');
- if (index == -1)
- LogError() << "Missing qml directory path";
- else
- qmlDirs << argument.mid(index+1);
- } else if (argument.startsWith(QByteArray("-qmlimport"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf('=');
- if (index == -1)
- LogError() << "Missing qml import path";
- else
- qmlImportPaths << argument.mid(index+1);
- } else if (argument.startsWith(QByteArray("-libpath"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf('=');
- if (index == -1)
- LogError() << "Missing library search path";
- else
- librarySearchPath << argument.mid(index+1);
- } else if (argument == QByteArray("-always-overwrite")) {
- LogDebug() << "Argument found:" << argument;
- alwaysOwerwriteEnabled = true;
- } else if (argument.startsWith(QByteArray("-codesign"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf("=");
- if (index < 0 || index >= argument.size()) {
- LogError() << "Missing code signing identity";
- } else {
- runCodesign = true;
- codesignIdentiy = argument.mid(index+1);
- }
- } else if (argument.startsWith(QByteArray("-sign-for-notarization"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf("=");
- if (index < 0 || index >= argument.size()) {
- LogError() << "Missing code signing identity";
- } else {
- runCodesign = true;
- hardenedRuntime = true;
- secureTimestamp = true;
- codesignIdentiy = argument.mid(index+1);
- }
- } else if (argument.startsWith(QByteArray("-hardened-runtime"))) {
- LogDebug() << "Argument found:" << argument;
- hardenedRuntime = true;
- } else if (argument.startsWith(QByteArray("-timestamp"))) {
- LogDebug() << "Argument found:" << argument;
- secureTimestamp = true;
- } else if (argument == QByteArray("-appstore-compliant")) {
- LogDebug() << "Argument found:" << argument;
- appstoreCompliant = true;
-
- // Undocumented option, may not work as intended
- } else if (argument == QByteArray("-deploy-framework")) {
- LogDebug() << "Argument found:" << argument;
- deployFramework = true;
-
- } else if (argument.startsWith(QByteArray("-fs"))) {
- LogDebug() << "Argument found:" << argument;
- int index = argument.indexOf('=');
- if (index == -1)
- LogError() << "Missing filesystem type";
- else
- filesystem = argument.mid(index+1);
- } else if (argument.startsWith("-")) {
- LogError() << "Unknown argument" << argument << "\n";
- return 1;
- }
- }
-
- DeploymentInfo deploymentInfo = deployQtFrameworks(appBundlePath, additionalExecutables, useDebugLibs);
-
- if (deploymentInfo.isDebug)
- useDebugLibs = true;
-
- if (deployFramework && deploymentInfo.isFramework)
- fixupFramework(appBundlePath);
-
- // Convenience: Look for .qml files in the current directory if no -qmldir specified.
- if (qmlDirs.isEmpty()) {
- QDir dir;
- if (!dir.entryList(QStringList() << QStringLiteral("*.qml")).isEmpty()) {
- qmlDirs += QStringLiteral(".");
- }
- }
-
- if (!qmlDirs.isEmpty()) {
- bool ok = deployQmlImports(appBundlePath, deploymentInfo, qmlDirs, qmlImportPaths);
- if (!ok && qmldirArgumentUsed)
- return 1; // exit if the user explicitly asked for qml import deployment
-
- // Update deploymentInfo.deployedFrameworks - the QML imports
- // may have brought in extra frameworks as dependencies.
- deploymentInfo.deployedFrameworks += findAppFrameworkNames(appBundlePath);
- deploymentInfo.deployedFrameworks =
- QSet<QString>(deploymentInfo.deployedFrameworks.begin(),
- deploymentInfo.deployedFrameworks.end()).values();
- }
-
- // Handle plugins
- if (plugins) {
- // Set the plugins search directory
- deploymentInfo.pluginPath = QLibraryInfo::path(QLibraryInfo::PluginsPath);
-
- // Sanity checks
- if (deploymentInfo.pluginPath.isEmpty()) {
- LogError() << "Missing Qt plugins path\n";
- return 1;
- }
-
- if (!QDir(deploymentInfo.pluginPath).exists()) {
- LogError() << "Plugins path does not exist" << deploymentInfo.pluginPath << "\n";
- return 1;
- }
-
- // Deploy plugins
- Q_ASSERT(!deploymentInfo.pluginPath.isEmpty());
- if (!deploymentInfo.pluginPath.isEmpty()) {
- LogNormal();
- deployPlugins(appBundlePath, deploymentInfo, useDebugLibs);
- createQtConf(appBundlePath);
- }
- }
-
- if (runStripEnabled)
- stripAppBinary(appBundlePath);
-
- if (runCodesign)
- codesign(codesignIdentiy, appBundlePath);
-
- if (dmg) {
- LogNormal();
- createDiskImage(appBundlePath, filesystem);
- }
-
- return 0;
-}
diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp
deleted file mode 100644
index 16608f72e..000000000
--- a/src/macdeployqt/shared/shared.cpp
+++ /dev/null
@@ -1,1603 +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 <QCoreApplication>
-#include <QString>
-#include <QStringList>
-#include <QDebug>
-#include <iostream>
-#include <utility>
-#include <QProcess>
-#include <QDir>
-#include <QSet>
-#include <QStack>
-#include <QDirIterator>
-#include <QLibraryInfo>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QJsonValue>
-#include <QRegularExpression>
-#include "shared.h"
-
-#ifdef Q_OS_DARWIN
-#include <CoreFoundation/CoreFoundation.h>
-#endif
-
-bool runStripEnabled = true;
-bool alwaysOwerwriteEnabled = false;
-bool runCodesign = false;
-QStringList librarySearchPath;
-QString codesignIdentiy;
-QString extraEntitlements;
-bool hardenedRuntime = false;
-bool secureTimestamp = false;
-bool appstoreCompliant = false;
-int logLevel = 1;
-bool deployFramework = false;
-
-using std::cout;
-using std::endl;
-
-bool operator==(const FrameworkInfo &a, const FrameworkInfo &b)
-{
- return ((a.frameworkPath == b.frameworkPath) && (a.binaryPath == b.binaryPath));
-}
-
-QDebug operator<<(QDebug debug, const FrameworkInfo &info)
-{
- debug << "Framework name" << info.frameworkName << "\n";
- debug << "Framework directory" << info.frameworkDirectory << "\n";
- debug << "Framework path" << info.frameworkPath << "\n";
- debug << "Binary directory" << info.binaryDirectory << "\n";
- debug << "Binary name" << info.binaryName << "\n";
- debug << "Binary path" << info.binaryPath << "\n";
- debug << "Version" << info.version << "\n";
- debug << "Install name" << info.installName << "\n";
- debug << "Deployed install name" << info.deployedInstallName << "\n";
- debug << "Source file Path" << info.sourceFilePath << "\n";
- debug << "Framework Destination Directory (relative to bundle)" << info.frameworkDestinationDirectory << "\n";
- debug << "Binary Destination Directory (relative to bundle)" << info.binaryDestinationDirectory << "\n";
-
- return debug;
-}
-
-const QString bundleFrameworkDirectory = "Contents/Frameworks";
-
-inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info)
-{
- debug << "Application bundle path" << info.path << "\n";
- debug << "Binary path" << info.binaryPath << "\n";
- debug << "Additional libraries" << info.libraryPaths << "\n";
- return debug;
-}
-
-bool copyFilePrintStatus(const QString &from, const QString &to)
-{
- if (QFile::exists(to)) {
- if (alwaysOwerwriteEnabled) {
- QFile(to).remove();
- } else {
- qDebug() << "File exists, skip copy:" << to;
- return false;
- }
- }
-
- if (QFile::copy(from, to)) {
- QFile dest(to);
- dest.setPermissions(dest.permissions() | QFile::WriteOwner | QFile::WriteUser);
- LogNormal() << " copied:" << from;
- LogNormal() << " to" << to;
-
- // The source file might not have write permissions set. Set the
- // write permission on the target file to make sure we can use
- // install_name_tool on it later.
- QFile toFile(to);
- if (toFile.permissions() & QFile::WriteOwner)
- return true;
-
- if (!toFile.setPermissions(toFile.permissions() | QFile::WriteOwner)) {
- LogError() << "Failed to set u+w permissions on target file: " << to;
- return false;
- }
-
- return true;
- } else {
- LogError() << "file copy failed from" << from;
- LogError() << " to" << to;
- return false;
- }
-}
-
-bool linkFilePrintStatus(const QString &file, const QString &link)
-{
- if (QFile::exists(link)) {
- if (QFile(link).symLinkTarget().isEmpty())
- LogError() << link << "exists but it's a file.";
- else
- LogNormal() << "Symlink exists, skipping:" << link;
- return false;
- } else if (QFile::link(file, link)) {
- LogNormal() << " symlink" << link;
- LogNormal() << " points to" << file;
- return true;
- } else {
- LogError() << "failed to symlink" << link;
- LogError() << " to" << file;
- return false;
- }
-}
-
-void patch_debugInInfoPlist(const QString &infoPlistPath)
-{
- // Older versions of qmake may have the "_debug" binary as
- // the value for CFBundleExecutable. Remove it.
- QFile infoPlist(infoPlistPath);
- infoPlist.open(QIODevice::ReadOnly);
- QByteArray contents = infoPlist.readAll();
- infoPlist.close();
- infoPlist.open(QIODevice::WriteOnly | QIODevice::Truncate);
- contents.replace("_debug", ""); // surely there are no legit uses of "_debug" in an Info.plist
- infoPlist.write(contents);
-}
-
-OtoolInfo findDependencyInfo(const QString &binaryPath)
-{
- OtoolInfo info;
- info.binaryPath = binaryPath;
-
- LogDebug() << "Using otool:";
- LogDebug() << " inspecting" << binaryPath;
- QProcess otool;
- otool.start("otool", QStringList() << "-L" << binaryPath);
- otool.waitForFinished();
-
- if (otool.exitStatus() != QProcess::NormalExit || otool.exitCode() != 0) {
- LogError() << otool.readAllStandardError();
- return info;
- }
-
- static const QRegularExpression regexp(QStringLiteral(
- "^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), "
- "current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$"));
-
- QString output = otool.readAllStandardOutput();
- QStringList outputLines = output.split("\n", Qt::SkipEmptyParts);
- if (outputLines.size() < 2) {
- LogError() << "Could not parse otool output:" << output;
- return info;
- }
-
- outputLines.removeFirst(); // remove line containing the binary path
- if (binaryPath.contains(".framework/") || binaryPath.endsWith(".dylib")) {
- const auto match = regexp.match(outputLines.first());
- if (match.hasMatch()) {
- QString installname = match.captured(1);
- if (QFileInfo(binaryPath).fileName() == QFileInfo(installname).fileName()) {
- info.installName = installname;
- info.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
- info.currentVersion = QVersionNumber::fromString(match.captured(3));
- outputLines.removeFirst();
- } else {
- info.installName = binaryPath;
- }
- } else {
- LogError() << "Could not parse otool output line:" << outputLines.first();
- outputLines.removeFirst();
- }
- }
-
- for (const QString &outputLine : outputLines) {
- const auto match = regexp.match(outputLine);
- if (match.hasMatch()) {
- DylibInfo dylib;
- dylib.binaryPath = match.captured(1);
- dylib.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
- dylib.currentVersion = QVersionNumber::fromString(match.captured(3));
- info.dependencies << dylib;
- } else {
- LogError() << "Could not parse otool output line:" << outputLine;
- }
- }
-
- return info;
-}
-
-FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
-{
- FrameworkInfo info;
- QString trimmed = line.trimmed();
-
- if (trimmed.isEmpty())
- return info;
-
- // Don't deploy system libraries.
- if (trimmed.startsWith("/System/Library/") ||
- (trimmed.startsWith("/usr/lib/") && trimmed.contains("libQt") == false) // exception for libQtuitools and libQtlucene
- || trimmed.startsWith("@executable_path") || trimmed.startsWith("@loader_path"))
- return info;
-
- // Resolve rpath relative libraries.
- if (trimmed.startsWith("@rpath/")) {
- QString rpathRelativePath = trimmed.mid(QStringLiteral("@rpath/").length());
- bool foundInsideBundle = false;
- for (const QString &rpath : std::as_const(rpaths)) {
- QString path = QDir::cleanPath(rpath + "/" + rpathRelativePath);
- // Skip paths already inside the bundle.
- if (!appBundlePath.isEmpty()) {
- if (QDir::isAbsolutePath(appBundlePath)) {
- if (path.startsWith(QDir::cleanPath(appBundlePath) + "/")) {
- foundInsideBundle = true;
- continue;
- }
- } else {
- if (path.startsWith(QDir::cleanPath(QDir::currentPath() + "/" + appBundlePath) + "/")) {
- foundInsideBundle = true;
- continue;
- }
- }
- }
- // Try again with substituted rpath.
- FrameworkInfo resolvedInfo = parseOtoolLibraryLine(path, appBundlePath, rpaths, useDebugLibs);
- if (!resolvedInfo.frameworkName.isEmpty() && QFile::exists(resolvedInfo.frameworkPath)) {
- resolvedInfo.rpathUsed = rpath;
- resolvedInfo.installName = trimmed;
- return resolvedInfo;
- }
- }
- if (!rpaths.isEmpty() && !foundInsideBundle) {
- LogError() << "Cannot resolve rpath" << trimmed;
- LogError() << " using" << rpaths;
- }
- return info;
- }
-
- enum State {QtPath, FrameworkName, DylibName, Version, FrameworkBinary, End};
- State state = QtPath;
- int part = 0;
- QString name;
- QString qtPath;
- QString suffix = useDebugLibs ? "_debug" : "";
-
- // Split the line into [Qt-path]/lib/qt[Module].framework/Versions/[Version]/
- QStringList parts = trimmed.split("/");
- while (part < parts.count()) {
- const QString currentPart = parts.at(part).simplified();
- ++part;
- if (currentPart == "")
- continue;
-
- if (state == QtPath) {
- // Check for library name part
- if (part < parts.count() && parts.at(part).contains(".dylib")) {
- info.frameworkDirectory += "/" + (qtPath + currentPart + "/").simplified();
- state = DylibName;
- continue;
- } else if (part < parts.count() && parts.at(part).endsWith(".framework")) {
- info.frameworkDirectory += "/" + (qtPath + "lib/").simplified();
- state = FrameworkName;
- continue;
- } else if (trimmed.startsWith("/") == false) { // If the line does not contain a full path, the app is using a binary Qt package.
- QStringList partsCopy = parts;
- partsCopy.removeLast();
- for (QString &path : librarySearchPath) {
- if (!path.endsWith("/"))
- path += '/';
- QString nameInPath = path + parts.join(QLatin1Char('/'));
- if (QFile::exists(nameInPath)) {
- info.frameworkDirectory = path + partsCopy.join(QLatin1Char('/'));
- break;
- }
- }
- if (currentPart.contains(".framework")) {
- if (info.frameworkDirectory.isEmpty())
- info.frameworkDirectory = "/Library/Frameworks/" + partsCopy.join(QLatin1Char('/'));
- if (!info.frameworkDirectory.endsWith("/"))
- info.frameworkDirectory += "/";
- state = FrameworkName;
- --part;
- continue;
- } else if (currentPart.contains(".dylib")) {
- if (info.frameworkDirectory.isEmpty())
- info.frameworkDirectory = "/usr/lib/" + partsCopy.join(QLatin1Char('/'));
- if (!info.frameworkDirectory.endsWith("/"))
- info.frameworkDirectory += "/";
- state = DylibName;
- --part;
- continue;
- }
- }
- qtPath += (currentPart + "/");
-
- } if (state == FrameworkName) {
- // remove ".framework"
- name = currentPart;
- name.chop(QString(".framework").length());
- info.isDylib = false;
- info.frameworkName = currentPart;
- state = Version;
- ++part;
- continue;
- } if (state == DylibName) {
- name = currentPart;
- info.isDylib = true;
- info.frameworkName = name;
- info.binaryName = name.contains(suffix) ? name : name.left(name.indexOf('.')) + suffix + name.mid(name.indexOf('.'));
- info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName;
- info.frameworkPath = info.frameworkDirectory + info.binaryName;
- info.sourceFilePath = info.frameworkPath;
- info.frameworkDestinationDirectory = bundleFrameworkDirectory + "/";
- info.binaryDestinationDirectory = info.frameworkDestinationDirectory;
- info.binaryDirectory = info.frameworkDirectory;
- info.binaryPath = info.frameworkPath;
- state = End;
- ++part;
- continue;
- } else if (state == Version) {
- info.version = currentPart;
- info.binaryDirectory = "Versions/" + info.version;
- info.frameworkPath = info.frameworkDirectory + info.frameworkName;
- info.frameworkDestinationDirectory = bundleFrameworkDirectory + "/" + info.frameworkName;
- info.binaryDestinationDirectory = info.frameworkDestinationDirectory + "/" + info.binaryDirectory;
- state = FrameworkBinary;
- } else if (state == FrameworkBinary) {
- info.binaryName = currentPart.contains(suffix) ? currentPart : currentPart + suffix;
- info.binaryPath = "/" + info.binaryDirectory + "/" + info.binaryName;
- info.deployedInstallName = "@executable_path/../Frameworks/" + info.frameworkName + info.binaryPath;
- info.sourceFilePath = info.frameworkPath + info.binaryPath;
- state = End;
- } else if (state == End) {
- break;
- }
- }
-
- if (!info.sourceFilePath.isEmpty() && QFile::exists(info.sourceFilePath)) {
- info.installName = findDependencyInfo(info.sourceFilePath).installName;
- if (info.installName.startsWith("@rpath/"))
- info.deployedInstallName = info.installName;
- }
-
- return info;
-}
-
-QString findAppBinary(const QString &appBundlePath)
-{
- QString binaryPath;
-
-#ifdef Q_OS_DARWIN
- CFStringRef bundlePath = appBundlePath.toCFString();
- CFURLRef bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundlePath,
- kCFURLPOSIXPathStyle, true);
- CFRelease(bundlePath);
- CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
- if (bundle) {
- CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
- if (executableURL) {
- CFURLRef absoluteExecutableURL = CFURLCopyAbsoluteURL(executableURL);
- if (absoluteExecutableURL) {
- CFStringRef executablePath = CFURLCopyFileSystemPath(absoluteExecutableURL,
- kCFURLPOSIXPathStyle);
- if (executablePath) {
- binaryPath = QString::fromCFString(executablePath);
- CFRelease(executablePath);
- }
- CFRelease(absoluteExecutableURL);
- }
- CFRelease(executableURL);
- }
- CFRelease(bundle);
- }
- CFRelease(bundleURL);
-#endif
-
- if (QFile::exists(binaryPath))
- return binaryPath;
- LogError() << "Could not find bundle binary for" << appBundlePath;
- return QString();
-}
-
-QStringList findAppFrameworkNames(const QString &appBundlePath)
-{
- QStringList frameworks;
-
- // populate the frameworks list with QtFoo.framework etc,
- // as found in /Contents/Frameworks/
- QString searchPath = appBundlePath + "/Contents/Frameworks/";
- QDirIterator iter(searchPath, QStringList() << QString::fromLatin1("*.framework"),
- QDir::Dirs | QDir::NoSymLinks);
- while (iter.hasNext()) {
- iter.next();
- frameworks << iter.fileInfo().fileName();
- }
-
- return frameworks;
-}
-
-QStringList findAppFrameworkPaths(const QString &appBundlePath)
-{
- QStringList frameworks;
- QString searchPath = appBundlePath + "/Contents/Frameworks/";
- QDirIterator iter(searchPath, QStringList() << QString::fromLatin1("*.framework"),
- QDir::Dirs | QDir::NoSymLinks);
- while (iter.hasNext()) {
- iter.next();
- frameworks << iter.fileInfo().filePath();
- }
-
- return frameworks;
-}
-
-QStringList findAppLibraries(const QString &appBundlePath)
-{
- QStringList result;
- // dylibs
- QDirIterator iter(appBundlePath, QStringList() << QString::fromLatin1("*.dylib"),
- QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
- while (iter.hasNext()) {
- iter.next();
- result << iter.fileInfo().filePath();
- }
- return result;
-}
-
-QStringList findAppBundleFiles(const QString &appBundlePath, bool absolutePath = false)
-{
- QStringList result;
-
- QDirIterator iter(appBundlePath, QStringList() << QString::fromLatin1("*"),
- QDir::Files, QDirIterator::Subdirectories);
-
- while (iter.hasNext()) {
- iter.next();
- if (iter.fileInfo().isSymLink())
- continue;
- result << (absolutePath ? iter.fileInfo().absoluteFilePath() : iter.fileInfo().filePath());
- }
-
- return result;
-}
-
-QString findEntitlementsFile(const QString& path)
-{
- QDirIterator iter(path, QStringList() << QString::fromLatin1("*.entitlements"),
- QDir::Files, QDirIterator::Subdirectories);
-
- while (iter.hasNext()) {
- iter.next();
- if (iter.fileInfo().isSymLink())
- continue;
-
- //return the first entitlements file - only one is used for signing anyway
- return iter.fileInfo().absoluteFilePath();
- }
-
- return QString();
-}
-
-QList<FrameworkInfo> getQtFrameworks(const QList<DylibInfo> &dependencies, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
-{
- QList<FrameworkInfo> libraries;
- for (const DylibInfo &dylibInfo : dependencies) {
- FrameworkInfo info = parseOtoolLibraryLine(dylibInfo.binaryPath, appBundlePath, rpaths, useDebugLibs);
- if (info.frameworkName.isEmpty() == false) {
- LogDebug() << "Adding framework:";
- LogDebug() << info;
- libraries.append(info);
- }
- }
- return libraries;
-}
-
-QString resolveDyldPrefix(const QString &path, const QString &loaderPath, const QString &executablePath)
-{
- if (path.startsWith("@")) {
- if (path.startsWith(QStringLiteral("@executable_path/"))) {
- // path relative to bundle executable dir
- if (QDir::isAbsolutePath(executablePath)) {
- return QDir::cleanPath(QFileInfo(executablePath).path() + path.mid(QStringLiteral("@executable_path").length()));
- } else {
- return QDir::cleanPath(QDir::currentPath() + "/" +
- QFileInfo(executablePath).path() + path.mid(QStringLiteral("@executable_path").length()));
- }
- } else if (path.startsWith(QStringLiteral("@loader_path"))) {
- // path relative to loader dir
- if (QDir::isAbsolutePath(loaderPath)) {
- return QDir::cleanPath(QFileInfo(loaderPath).path() + path.mid(QStringLiteral("@loader_path").length()));
- } else {
- return QDir::cleanPath(QDir::currentPath() + "/" +
- QFileInfo(loaderPath).path() + path.mid(QStringLiteral("@loader_path").length()));
- }
- } else {
- LogError() << "Unexpected prefix" << path;
- }
- }
- return path;
-}
-
-QList<QString> getBinaryRPaths(const QString &path, bool resolve = true, QString executablePath = QString())
-{
- QList<QString> rpaths;
-
- QProcess otool;
- otool.start("otool", QStringList() << "-l" << path);
- otool.waitForFinished();
-
- if (otool.exitCode() != 0) {
- LogError() << otool.readAllStandardError();
- }
-
- if (resolve && executablePath.isEmpty()) {
- executablePath = path;
- }
-
- QString output = otool.readAllStandardOutput();
- QStringList outputLines = output.split("\n");
-
- for (auto i = outputLines.cbegin(), end = outputLines.cend(); i != end; ++i) {
- if (i->contains("cmd LC_RPATH") && ++i != end &&
- i->contains("cmdsize") && ++i != end) {
- const QString &rpathCmd = *i;
- int pathStart = rpathCmd.indexOf("path ");
- int pathEnd = rpathCmd.indexOf(" (");
- if (pathStart >= 0 && pathEnd >= 0 && pathStart < pathEnd) {
- QString rpath = rpathCmd.mid(pathStart + 5, pathEnd - pathStart - 5);
- if (resolve) {
- rpaths << resolveDyldPrefix(rpath, path, executablePath);
- } else {
- rpaths << rpath;
- }
- }
- }
- }
-
- return rpaths;
-}
-
-QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
-{
- const OtoolInfo info = findDependencyInfo(path);
- QList<QString> allRPaths = rpaths + getBinaryRPaths(path);
- allRPaths.removeDuplicates();
- return getQtFrameworks(info.dependencies, appBundlePath, allRPaths, useDebugLibs);
-}
-
-QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs)
-{
- QList<FrameworkInfo> result;
- QSet<QString> existing;
- for (const QString &path : paths) {
- for (const FrameworkInfo &info : getQtFrameworks(path, appBundlePath, rpaths, useDebugLibs)) {
- if (!existing.contains(info.frameworkPath)) { // avoid duplicates
- existing.insert(info.frameworkPath);
- result << info;
- }
- }
- }
- return result;
-}
-
-QStringList getBinaryDependencies(const QString executablePath,
- const QString &path,
- const QList<QString> &additionalBinariesContainingRpaths)
-{
- QStringList binaries;
-
- const auto dependencies = findDependencyInfo(path).dependencies;
-
- bool rpathsLoaded = false;
- QList<QString> rpaths;
-
- // return bundle-local dependencies. (those starting with @executable_path)
- for (const DylibInfo &info : dependencies) {
- QString trimmedLine = info.binaryPath;
- if (trimmedLine.startsWith("@executable_path/")) {
- QString binary = QDir::cleanPath(executablePath + trimmedLine.mid(QStringLiteral("@executable_path/").length()));
- if (binary != path)
- binaries.append(binary);
- } else if (trimmedLine.startsWith("@rpath/")) {
- if (!rpathsLoaded) {
- rpaths = getBinaryRPaths(path, true, executablePath);
- foreach (const QString &binaryPath, additionalBinariesContainingRpaths)
- rpaths += getBinaryRPaths(binaryPath, true);
- rpaths.removeDuplicates();
- rpathsLoaded = true;
- }
- bool resolved = false;
- for (const QString &rpath : std::as_const(rpaths)) {
- QString binary = QDir::cleanPath(rpath + "/" + trimmedLine.mid(QStringLiteral("@rpath/").length()));
- LogDebug() << "Checking for" << binary;
- if (QFile::exists(binary)) {
- binaries.append(binary);
- resolved = true;
- break;
- }
- }
- if (!resolved && !rpaths.isEmpty()) {
- LogError() << "Cannot resolve rpath" << trimmedLine;
- LogError() << " using" << rpaths;
- }
- }
- }
-
- return binaries;
-}
-
-// copies everything _inside_ sourcePath to destinationPath
-bool recursiveCopy(const QString &sourcePath, const QString &destinationPath)
-{
- if (!QDir(sourcePath).exists())
- return false;
- QDir().mkpath(destinationPath);
-
- LogNormal() << "copy:" << sourcePath << destinationPath;
-
- QStringList files = QDir(sourcePath).entryList(QStringList() << "*", QDir::Files | QDir::NoDotAndDotDot);
- for (const QString &file : files) {
- const QString fileSourcePath = sourcePath + "/" + file;
- const QString fileDestinationPath = destinationPath + "/" + file;
- copyFilePrintStatus(fileSourcePath, fileDestinationPath);
- }
-
- QStringList subdirs = QDir(sourcePath).entryList(QStringList() << "*", QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QString &dir : subdirs) {
- recursiveCopy(sourcePath + "/" + dir, destinationPath + "/" + dir);
- }
- return true;
-}
-
-void recursiveCopyAndDeploy(const QString &appBundlePath, const QList<QString> &rpaths, const QString &sourcePath, const QString &destinationPath)
-{
- QDir().mkpath(destinationPath);
-
- LogNormal() << "copy:" << sourcePath << destinationPath;
- const bool isDwarfPath = sourcePath.endsWith("DWARF");
-
- QStringList files = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Files | QDir::NoDotAndDotDot);
- for (const QString &file : files) {
- const QString fileSourcePath = sourcePath + QLatin1Char('/') + file;
-
- if (file.endsWith("_debug.dylib")) {
- continue; // Skip debug versions
- } else if (!isDwarfPath && file.endsWith(QStringLiteral(".dylib"))) {
- // App store code signing rules forbids code binaries in Contents/Resources/,
- // which poses a problem for deploying mixed .qml/.dylib Qt Quick imports.
- // Solve this by placing the dylibs in Contents/PlugIns/quick, and then
- // creting a symlink to there from the Qt Quick import in Contents/Resources/.
- //
- // Example:
- // MyApp.app/Contents/Resources/qml/QtQuick/Controls/libqtquickcontrolsplugin.dylib ->
- // ../../../../PlugIns/quick/libqtquickcontrolsplugin.dylib
- //
-
- // The .dylib destination path:
- QString fileDestinationDir = appBundlePath + QStringLiteral("/Contents/PlugIns/quick/");
- QDir().mkpath(fileDestinationDir);
- QString fileDestinationPath = fileDestinationDir + file;
-
- // The .dylib symlink destination path:
- QString linkDestinationPath = destinationPath + QLatin1Char('/') + file;
-
- // The (relative) link; with a correct number of "../"'s.
- QString linkPath = QStringLiteral("PlugIns/quick/") + file;
- int cdupCount = linkDestinationPath.count(QStringLiteral("/")) - appBundlePath.count(QStringLiteral("/"));
- for (int i = 0; i < cdupCount - 2; ++i)
- linkPath.prepend("../");
-
- if (copyFilePrintStatus(fileSourcePath, fileDestinationPath)) {
- linkFilePrintStatus(linkPath, linkDestinationPath);
-
- runStrip(fileDestinationPath);
- bool useDebugLibs = false;
- bool useLoaderPath = false;
- QList<FrameworkInfo> frameworks = getQtFrameworks(fileDestinationPath, appBundlePath, rpaths, useDebugLibs);
- deployQtFrameworks(frameworks, appBundlePath, QStringList(fileDestinationPath), useDebugLibs, useLoaderPath);
- }
- } else {
- QString fileDestinationPath = destinationPath + QLatin1Char('/') + file;
- copyFilePrintStatus(fileSourcePath, fileDestinationPath);
- }
- }
-
- QStringList subdirs = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QString &dir : subdirs) {
- recursiveCopyAndDeploy(appBundlePath, rpaths, sourcePath + QLatin1Char('/') + dir, destinationPath + QLatin1Char('/') + dir);
- }
-}
-
-QString copyDylib(const FrameworkInfo &framework, const QString path)
-{
- if (!QFile::exists(framework.sourceFilePath)) {
- LogError() << "no file at" << framework.sourceFilePath;
- return QString();
- }
-
- // Construct destination paths. The full path typically looks like
- // MyApp.app/Contents/Frameworks/libfoo.dylib
- QString dylibDestinationDirectory = path + QLatin1Char('/') + framework.frameworkDestinationDirectory;
- QString dylibDestinationBinaryPath = dylibDestinationDirectory + QLatin1Char('/') + framework.binaryName;
-
- // Create destination directory
- if (!QDir().mkpath(dylibDestinationDirectory)) {
- LogError() << "could not create destination directory" << dylibDestinationDirectory;
- return QString();
- }
-
- // Return if the dylib has already been deployed
- if (QFileInfo::exists(dylibDestinationBinaryPath) && !alwaysOwerwriteEnabled)
- return dylibDestinationBinaryPath;
-
- // Copy dylib binary
- copyFilePrintStatus(framework.sourceFilePath, dylibDestinationBinaryPath);
- return dylibDestinationBinaryPath;
-}
-
-QString copyFramework(const FrameworkInfo &framework, const QString path)
-{
- if (!QFile::exists(framework.sourceFilePath)) {
- LogError() << "no file at" << framework.sourceFilePath;
- return QString();
- }
-
- // Construct destination paths. The full path typically looks like
- // MyApp.app/Contents/Frameworks/Foo.framework/Versions/5/QtFoo
- QString frameworkDestinationDirectory = path + QLatin1Char('/') + framework.frameworkDestinationDirectory;
- QString frameworkBinaryDestinationDirectory = frameworkDestinationDirectory + QLatin1Char('/') + framework.binaryDirectory;
- QString frameworkDestinationBinaryPath = frameworkBinaryDestinationDirectory + QLatin1Char('/') + framework.binaryName;
-
- // Return if the framework has aleardy been deployed
- if (QDir(frameworkDestinationDirectory).exists() && !alwaysOwerwriteEnabled)
- return QString();
-
- // Create destination directory
- if (!QDir().mkpath(frameworkBinaryDestinationDirectory)) {
- LogError() << "could not create destination directory" << frameworkBinaryDestinationDirectory;
- return QString();
- }
-
- // Now copy the framework. Some parts should be left out (headers/, .prl files).
- // Some parts should be included (Resources/, symlink structure). We want this
- // function to make as few assumptions about the framework as possible while at
- // the same time producing a codesign-compatible framework.
-
- // Copy framework binary
- copyFilePrintStatus(framework.sourceFilePath, frameworkDestinationBinaryPath);
-
- // Copy Resources/, Libraries/ and Helpers/
- const QString resourcesSourcePath = framework.frameworkPath + "/Resources";
- const QString resourcesDestianationPath = frameworkDestinationDirectory + "/Versions/" + framework.version + "/Resources";
- recursiveCopy(resourcesSourcePath, resourcesDestianationPath);
- const QString librariesSourcePath = framework.frameworkPath + "/Libraries";
- const QString librariesDestianationPath = frameworkDestinationDirectory + "/Versions/" + framework.version + "/Libraries";
- bool createdLibraries = recursiveCopy(librariesSourcePath, librariesDestianationPath);
- const QString helpersSourcePath = framework.frameworkPath + "/Helpers";
- const QString helpersDestianationPath = frameworkDestinationDirectory + "/Versions/" + framework.version + "/Helpers";
- bool createdHelpers = recursiveCopy(helpersSourcePath, helpersDestianationPath);
-
- // Create symlink structure. Links at the framework root point to Versions/Current/
- // which again points to the actual version:
- // QtFoo.framework/QtFoo -> Versions/Current/QtFoo
- // QtFoo.framework/Resources -> Versions/Current/Resources
- // QtFoo.framework/Versions/Current -> 5
- linkFilePrintStatus("Versions/Current/" + framework.binaryName, frameworkDestinationDirectory + "/" + framework.binaryName);
- linkFilePrintStatus("Versions/Current/Resources", frameworkDestinationDirectory + "/Resources");
- if (createdLibraries)
- linkFilePrintStatus("Versions/Current/Libraries", frameworkDestinationDirectory + "/Libraries");
- if (createdHelpers)
- linkFilePrintStatus("Versions/Current/Helpers", frameworkDestinationDirectory + "/Helpers");
- linkFilePrintStatus(framework.version, frameworkDestinationDirectory + "/Versions/Current");
-
- // Correct Info.plist location for frameworks produced by older versions of qmake
- // Contents/Info.plist should be Versions/5/Resources/Info.plist
- const QString legacyInfoPlistPath = framework.frameworkPath + "/Contents/Info.plist";
- const QString correctInfoPlistPath = frameworkDestinationDirectory + "/Resources/Info.plist";
- if (QFile::exists(legacyInfoPlistPath)) {
- copyFilePrintStatus(legacyInfoPlistPath, correctInfoPlistPath);
- patch_debugInInfoPlist(correctInfoPlistPath);
- }
- return frameworkDestinationBinaryPath;
-}
-
-void runInstallNameTool(QStringList options)
-{
- QProcess installNametool;
- installNametool.start("install_name_tool", options);
- installNametool.waitForFinished();
- if (installNametool.exitCode() != 0) {
- LogError() << installNametool.readAllStandardError();
- LogError() << installNametool.readAllStandardOutput();
- }
-}
-
-void changeIdentification(const QString &id, const QString &binaryPath)
-{
- LogDebug() << "Using install_name_tool:";
- LogDebug() << " change identification in" << binaryPath;
- LogDebug() << " to" << id;
- runInstallNameTool(QStringList() << "-id" << id << binaryPath);
-}
-
-void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework, const QStringList &binaryPaths, bool useLoaderPath)
-{
- const QString absBundlePath = QFileInfo(bundlePath).absoluteFilePath();
- for (const QString &binary : binaryPaths) {
- QString deployedInstallName;
- if (useLoaderPath) {
- deployedInstallName = QLatin1String("@loader_path/")
- + QFileInfo(binary).absoluteDir().relativeFilePath(absBundlePath + QLatin1Char('/') + framework.binaryDestinationDirectory + QLatin1Char('/') + framework.binaryName);
- } else {
- deployedInstallName = framework.deployedInstallName;
- }
- changeInstallName(framework.installName, deployedInstallName, binary);
- // Workaround for the case when the library ID name is a symlink, while the dependencies
- // specified using the canonical path to the library (QTBUG-56814)
- QString canonicalInstallName = QFileInfo(framework.installName).canonicalFilePath();
- if (!canonicalInstallName.isEmpty() && canonicalInstallName != framework.installName) {
- changeInstallName(canonicalInstallName, deployedInstallName, binary);
- }
- }
-}
-
-void addRPath(const QString &rpath, const QString &binaryPath)
-{
- runInstallNameTool(QStringList() << "-add_rpath" << rpath << binaryPath);
-}
-
-void deployRPaths(const QString &bundlePath, const QList<QString> &rpaths, const QString &binaryPath, bool useLoaderPath)
-{
- const QString absFrameworksPath = QFileInfo(bundlePath).absoluteFilePath()
- + QLatin1String("/Contents/Frameworks");
- const QString relativeFrameworkPath = QFileInfo(binaryPath).absoluteDir().relativeFilePath(absFrameworksPath);
- const QString loaderPathToFrameworks = QLatin1String("@loader_path/") + relativeFrameworkPath;
- bool rpathToFrameworksFound = false;
- QStringList args;
- QList<QString> binaryRPaths = getBinaryRPaths(binaryPath, false);
- for (const QString &rpath : std::as_const(binaryRPaths)) {
- if (rpath == "@executable_path/../Frameworks" ||
- rpath == loaderPathToFrameworks) {
- rpathToFrameworksFound = true;
- continue;
- }
- if (rpaths.contains(resolveDyldPrefix(rpath, binaryPath, binaryPath))) {
- args << "-delete_rpath" << rpath;
- }
- }
- if (!args.length()) {
- return;
- }
- if (!rpathToFrameworksFound) {
- if (!useLoaderPath) {
- args << "-add_rpath" << "@executable_path/../Frameworks";
- } else {
- args << "-add_rpath" << loaderPathToFrameworks;
- }
- }
- LogDebug() << "Using install_name_tool:";
- LogDebug() << " change rpaths in" << binaryPath;
- LogDebug() << " using" << args;
- runInstallNameTool(QStringList() << args << binaryPath);
-}
-
-void deployRPaths(const QString &bundlePath, const QList<QString> &rpaths, const QStringList &binaryPaths, bool useLoaderPath)
-{
- for (const QString &binary : binaryPaths) {
- deployRPaths(bundlePath, rpaths, binary, useLoaderPath);
- }
-}
-
-void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath)
-{
- LogDebug() << "Using install_name_tool:";
- LogDebug() << " in" << binaryPath;
- LogDebug() << " change reference" << oldName;
- LogDebug() << " to" << newName;
- runInstallNameTool(QStringList() << "-change" << oldName << newName << binaryPath);
-}
-
-void runStrip(const QString &binaryPath)
-{
- if (runStripEnabled == false)
- return;
-
- LogDebug() << "Using strip:";
- LogDebug() << " stripped" << binaryPath;
- QProcess strip;
- strip.start("strip", QStringList() << "-x" << binaryPath);
- strip.waitForFinished();
- if (strip.exitCode() != 0) {
- LogError() << strip.readAllStandardError();
- LogError() << strip.readAllStandardOutput();
- }
-}
-
-void stripAppBinary(const QString &bundlePath)
-{
- runStrip(findAppBinary(bundlePath));
-}
-
-bool DeploymentInfo::containsModule(const QString &module, const QString &libInFix) const
-{
- // Check for framework first
- if (deployedFrameworks.contains(QLatin1String("Qt") + module + libInFix +
- QLatin1String(".framework"))) {
- return true;
- }
- // Check for dylib
- const QRegularExpression dylibRegExp(QLatin1String("libQt[0-9]+") + module +
- libInFix + QLatin1String(".[0-9]+.dylib"));
- return deployedFrameworks.filter(dylibRegExp).size() > 0;
-}
-
-/*
- Deploys the the listed frameworks listed into an app bundle.
- The frameworks are searched for dependencies, which are also deployed.
- (deploying Qt3Support will also deploy QtNetwork and QtSql for example.)
- Returns a DeploymentInfo structure containing the Qt path used and a
- a list of actually deployed frameworks.
-*/
-DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
- const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs,
- bool useLoaderPath)
-{
- LogNormal();
- LogNormal() << "Deploying Qt frameworks found inside:" << binaryPaths;
- QStringList copiedFrameworks;
- DeploymentInfo deploymentInfo;
- deploymentInfo.useLoaderPath = useLoaderPath;
- deploymentInfo.isFramework = bundlePath.contains(".framework");
- deploymentInfo.isDebug = false;
- QList<QString> rpathsUsed;
-
- while (frameworks.isEmpty() == false) {
- const FrameworkInfo framework = frameworks.takeFirst();
- copiedFrameworks.append(framework.frameworkName);
-
- // If a single dependency has the _debug suffix, we treat that as
- // the whole deployment being a debug deployment, including deploying
- // the debug version of plugins.
- if (framework.isDebugLibrary())
- deploymentInfo.isDebug = true;
-
- if (deploymentInfo.qtPath.isNull())
- deploymentInfo.qtPath = QLibraryInfo::path(QLibraryInfo::PrefixPath);
-
- if (framework.frameworkDirectory.startsWith(bundlePath)) {
- LogError() << framework.frameworkName << "already deployed, skipping.";
- continue;
- }
-
- if (!framework.rpathUsed.isEmpty() && !rpathsUsed.contains(framework.rpathUsed)) {
- rpathsUsed.append(framework.rpathUsed);
- }
-
- // Copy the framework/dylib to the app bundle.
- const QString deployedBinaryPath = framework.isDylib ? copyDylib(framework, bundlePath)
- : copyFramework(framework, bundlePath);
-
- // Install_name_tool the new id into the binaries
- changeInstallName(bundlePath, framework, binaryPaths, useLoaderPath);
-
- // Skip the rest if already was deployed.
- if (deployedBinaryPath.isNull())
- continue;
-
- runStrip(deployedBinaryPath);
-
- // Install_name_tool it a new id.
- if (!framework.rpathUsed.length()) {
- changeIdentification(framework.deployedInstallName, deployedBinaryPath);
- }
-
- // Check for framework dependencies
- QList<FrameworkInfo> dependencies = getQtFrameworks(deployedBinaryPath, bundlePath, rpathsUsed, useDebugLibs);
-
- for (const FrameworkInfo &dependency : dependencies) {
- if (dependency.rpathUsed.isEmpty()) {
- changeInstallName(bundlePath, dependency, QStringList() << deployedBinaryPath, useLoaderPath);
- } else {
- rpathsUsed.append(dependency.rpathUsed);
- }
-
- // Deploy framework if necessary.
- if (copiedFrameworks.contains(dependency.frameworkName) == false && frameworks.contains(dependency) == false) {
- frameworks.append(dependency);
- }
- }
- }
- deploymentInfo.deployedFrameworks = copiedFrameworks;
- deployRPaths(bundlePath, rpathsUsed, binaryPaths, useLoaderPath);
- deploymentInfo.rpathsUsed += rpathsUsed;
- deploymentInfo.rpathsUsed.removeDuplicates();
- return deploymentInfo;
-}
-
-DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringList &additionalExecutables, bool useDebugLibs)
-{
- ApplicationBundleInfo applicationBundle;
- applicationBundle.path = appBundlePath;
- applicationBundle.binaryPath = findAppBinary(appBundlePath);
- applicationBundle.libraryPaths = findAppLibraries(appBundlePath);
- QStringList allBinaryPaths = QStringList() << applicationBundle.binaryPath << applicationBundle.libraryPaths
- << additionalExecutables;
-
- QList<QString> allLibraryPaths = getBinaryRPaths(applicationBundle.binaryPath, true);
- allLibraryPaths.append(QLibraryInfo::path(QLibraryInfo::LibrariesPath));
- allLibraryPaths.removeDuplicates();
-
- QList<FrameworkInfo> frameworks = getQtFrameworksForPaths(allBinaryPaths, appBundlePath, allLibraryPaths, useDebugLibs);
- if (frameworks.isEmpty() && !alwaysOwerwriteEnabled) {
- LogWarning();
- LogWarning() << "Could not find any external Qt frameworks to deploy in" << appBundlePath;
- LogWarning() << "Perhaps macdeployqt was already used on" << appBundlePath << "?";
- LogWarning() << "If so, you will need to rebuild" << appBundlePath << "before trying again.";
- return DeploymentInfo();
- } else {
- return deployQtFrameworks(frameworks, applicationBundle.path, allBinaryPaths, useDebugLibs, !additionalExecutables.isEmpty());
- }
-}
-
-QString getLibInfix(const QStringList &deployedFrameworks)
-{
- QString libInfix;
- for (const QString &framework : deployedFrameworks) {
- if (framework.startsWith(QStringLiteral("QtCore")) && framework.endsWith(QStringLiteral(".framework")) &&
- !framework.contains(QStringLiteral("5Compat"))) {
- Q_ASSERT(framework.length() >= 16);
- // 16 == "QtCore" + ".framework"
- const int lengthOfLibInfix = framework.length() - 16;
- if (lengthOfLibInfix)
- libInfix = framework.mid(6, lengthOfLibInfix);
- break;
- }
- }
- return libInfix;
-}
-
-void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pluginSourcePath,
- const QString pluginDestinationPath, DeploymentInfo deploymentInfo, bool useDebugLibs)
-{
- LogNormal() << "Deploying plugins from" << pluginSourcePath;
-
- if (!pluginSourcePath.contains(deploymentInfo.pluginPath))
- return;
-
- // Plugin white list:
- QStringList pluginList;
-
- const auto addPlugins = [&pluginSourcePath,&pluginList,useDebugLibs](const QString &subDirectory,
- const std::function<bool(QString)> &predicate = std::function<bool(QString)>()) {
- const QStringList libs = QDir(pluginSourcePath + QLatin1Char('/') + subDirectory)
- .entryList({QStringLiteral("*.dylib")});
- for (const QString &lib : libs) {
- if (lib.endsWith(QStringLiteral("_debug.dylib")) != useDebugLibs)
- continue;
- if (!predicate || predicate(lib))
- pluginList.append(subDirectory + QLatin1Char('/') + lib);
- }
- };
-
- // Platform plugin:
- addPlugins(QStringLiteral("platforms"), [](const QString &lib) {
- // Ignore minimal and offscreen platform plugins
- if (!lib.contains(QStringLiteral("cocoa")))
- return false;
- return true;
- });
-
- // Cocoa print support
- addPlugins(QStringLiteral("printsupport"));
-
- // Styles
- addPlugins(QStringLiteral("styles"));
-
- // Check if Qt was configured with -libinfix
- const QString libInfix = getLibInfix(deploymentInfo.deployedFrameworks);
-
- // Network
- if (deploymentInfo.containsModule("Network", libInfix))
- addPlugins(QStringLiteral("tls"));
-
- // All image formats (svg if QtSvg is used)
- const bool usesSvg = deploymentInfo.containsModule("Svg", libInfix);
- addPlugins(QStringLiteral("imageformats"), [usesSvg](const QString &lib) {
- if (lib.contains(QStringLiteral("qsvg")) && !usesSvg)
- return false;
- return true;
- });
-
- addPlugins(QStringLiteral("iconengines"));
-
- // Platforminputcontext plugins if QtGui is in use
- if (deploymentInfo.containsModule("Gui", libInfix)) {
- addPlugins(QStringLiteral("platforminputcontexts"), [&addPlugins](const QString &lib) {
- // Deploy the virtual keyboard plugins if we have deployed virtualkeyboard
- if (lib.startsWith(QStringLiteral("libqtvirtualkeyboard")))
- addPlugins(QStringLiteral("virtualkeyboard"));
- return true;
- });
- }
-
- // Sql plugins if QtSql is in use
- if (deploymentInfo.containsModule("Sql", libInfix)) {
- addPlugins(QStringLiteral("sqldrivers"), [](const QString &lib) {
- if (lib.startsWith(QStringLiteral("libqsqlodbc")) || lib.startsWith(QStringLiteral("libqsqlpsql"))) {
- LogWarning() << "Plugin" << lib << "uses private API and is not Mac App store compliant.";
- if (appstoreCompliant) {
- LogWarning() << "Skip plugin" << lib;
- return false;
- }
- }
- return true;
- });
- }
-
- // WebView plugins if QtWebView is in use
- if (deploymentInfo.containsModule("WebView", libInfix)) {
- addPlugins(QStringLiteral("webview"), [](const QString &lib) {
- if (lib.startsWith(QStringLiteral("libqtwebview_webengine"))) {
- LogWarning() << "Plugin" << lib << "uses QtWebEngine and is not Mac App store compliant.";
- if (appstoreCompliant) {
- LogWarning() << "Skip plugin" << lib;
- return false;
- }
- }
- return true;
- });
- }
-
- static const std::map<QString, std::vector<QString>> map {
- {QStringLiteral("Multimedia"), {QStringLiteral("mediaservice"), QStringLiteral("audio")}},
- {QStringLiteral("3DRender"), {QStringLiteral("sceneparsers"), QStringLiteral("geometryloaders"), QStringLiteral("renderers")}},
- {QStringLiteral("3DQuickRender"), {QStringLiteral("renderplugins")}},
- {QStringLiteral("Positioning"), {QStringLiteral("position")}},
- {QStringLiteral("Location"), {QStringLiteral("geoservices")}},
- {QStringLiteral("TextToSpeech"), {QStringLiteral("texttospeech")}}
- };
-
- for (const auto &it : map) {
- if (deploymentInfo.containsModule(it.first, libInfix)) {
- for (const auto &pluginType : it.second) {
- addPlugins(pluginType);
- }
- }
- }
-
- for (const QString &plugin : pluginList) {
- QString sourcePath = pluginSourcePath + "/" + plugin;
- const QString destinationPath = pluginDestinationPath + "/" + plugin;
- QDir dir;
- dir.mkpath(QFileInfo(destinationPath).path());
-
- if (copyFilePrintStatus(sourcePath, destinationPath)) {
- runStrip(destinationPath);
- QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
- deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
- }
- }
-}
-
-void createQtConf(const QString &appBundlePath)
-{
- // Set Plugins and imports paths. These are relative to App.app/Contents.
- QByteArray contents = "[Paths]\n"
- "Plugins = PlugIns\n"
- "QmlImports = Resources/qml\n";
-
- QString filePath = appBundlePath + "/Contents/Resources/";
- QString fileName = filePath + "qt.conf";
-
- QDir().mkpath(filePath);
-
- QFile qtconf(fileName);
- if (qtconf.exists() && !alwaysOwerwriteEnabled) {
- LogWarning();
- LogWarning() << fileName << "already exists, will not overwrite.";
- LogWarning() << "To make sure the plugins are loaded from the correct location,";
- LogWarning() << "please make sure qt.conf contains the following lines:";
- LogWarning() << "[Paths]";
- LogWarning() << " Plugins = PlugIns";
- return;
- }
-
- qtconf.open(QIODevice::WriteOnly);
- if (qtconf.write(contents) != -1) {
- LogNormal() << "Created configuration file:" << fileName;
- LogNormal() << "This file sets the plugin search path to" << appBundlePath + "/Contents/PlugIns";
- }
-}
-
-void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs)
-{
- ApplicationBundleInfo applicationBundle;
- applicationBundle.path = appBundlePath;
- applicationBundle.binaryPath = findAppBinary(appBundlePath);
-
- const QString pluginDestinationPath = appBundlePath + "/" + "Contents/PlugIns";
- deployPlugins(applicationBundle, deploymentInfo.pluginPath, pluginDestinationPath, deploymentInfo, useDebugLibs);
-}
-
-void deployQmlImport(const QString &appBundlePath, const QList<QString> &rpaths, const QString &importSourcePath, const QString &importName)
-{
- QString importDestinationPath = appBundlePath + "/Contents/Resources/qml/" + importName;
-
- // Skip already deployed imports. This can happen in cases like "QtQuick.Controls.Styles",
- // where deploying QtQuick.Controls will also deploy the "Styles" sub-import.
- if (QDir().exists(importDestinationPath))
- return;
-
- recursiveCopyAndDeploy(appBundlePath, rpaths, importSourcePath, importDestinationPath);
-}
-
-static bool importLessThan(const QVariant &v1, const QVariant &v2)
-{
- QVariantMap import1 = v1.toMap();
- QVariantMap import2 = v2.toMap();
- QString path1 = import1["path"].toString();
- QString path2 = import2["path"].toString();
- return path1 < path2;
-}
-
-// Scan qml files in qmldirs for import statements, deploy used imports from QmlImportsPath to Contents/Resources/qml.
-bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInfo, QStringList &qmlDirs, QStringList &qmlImportPaths)
-{
- LogNormal() << "";
- LogNormal() << "Deploying QML imports ";
- LogNormal() << "Application QML file path(s) is" << qmlDirs;
- LogNormal() << "QML module search path(s) is" << qmlImportPaths;
-
- // Use qmlimportscanner from QLibraryInfo::LibraryExecutablesPath
- QString qmlImportScannerPath =
- QDir::cleanPath(QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath)
- + "/qmlimportscanner");
-
- // Fallback: Look relative to the macdeployqt binary
- if (!QFile::exists(qmlImportScannerPath))
- qmlImportScannerPath = QCoreApplication::applicationDirPath() + "/qmlimportscanner";
-
- // Verify that we found a qmlimportscanner binary
- if (!QFile::exists(qmlImportScannerPath)) {
- LogError() << "qmlimportscanner not found at" << qmlImportScannerPath;
- LogError() << "Rebuild qtdeclarative/tools/qmlimportscanner";
- return false;
- }
-
- // build argument list for qmlimportsanner: "-rootPath foo/ -rootPath bar/ -importPath path/to/qt/qml"
- // ("rootPath" points to a directory containing app qml, "importPath" is where the Qt imports are installed)
- QStringList argumentList;
- for (const QString &qmlDir : qmlDirs) {
- argumentList.append("-rootPath");
- argumentList.append(qmlDir);
- }
- for (const QString &importPath : qmlImportPaths)
- argumentList << "-importPath" << importPath;
- QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
- argumentList.append( "-importPath");
- argumentList.append(qmlImportsPath);
-
- // run qmlimportscanner
- QProcess qmlImportScanner;
- qmlImportScanner.start(qmlImportScannerPath, argumentList);
- if (!qmlImportScanner.waitForStarted()) {
- LogError() << "Could not start qmlimpoortscanner. Process error is" << qmlImportScanner.errorString();
- return false;
- }
- qmlImportScanner.waitForFinished(-1);
-
- // log qmlimportscanner errors
- qmlImportScanner.setReadChannel(QProcess::StandardError);
- QByteArray errors = qmlImportScanner.readAll();
- if (!errors.isEmpty()) {
- LogWarning() << "QML file parse error (deployment will continue):";
- LogWarning() << errors;
- }
-
- // parse qmlimportscanner json
- qmlImportScanner.setReadChannel(QProcess::StandardOutput);
- QByteArray json = qmlImportScanner.readAll();
- QJsonDocument doc = QJsonDocument::fromJson(json);
- if (!doc.isArray()) {
- LogError() << "qmlimportscanner output error. Expected json array, got:";
- LogError() << json;
- return false;
- }
-
- // sort imports to deploy a module before its sub-modules (otherwise
- // deployQmlImports can consider the module deployed if it has already
- // deployed one of its sub-module)
- QVariantList array = doc.array().toVariantList();
- std::sort(array.begin(), array.end(), importLessThan);
-
- // deploy each import
- for (const QVariant &importValue : array) {
- QVariantMap import = importValue.toMap();
- QString name = import["name"].toString();
- QString path = import["path"].toString();
- QString type = import["type"].toString();
-
- LogNormal() << "Deploying QML import" << name;
-
- // Skip imports with missing info - path will be empty if the import is not found.
- if (name.isEmpty() || path.isEmpty()) {
- LogNormal() << " Skip import: name or path is empty";
- LogNormal() << "";
- continue;
- }
-
- // Deploy module imports only, skip directory (local/remote) and js imports. These
- // should be deployed as a part of the application build.
- if (type != QStringLiteral("module")) {
- LogNormal() << " Skip non-module import";
- LogNormal() << "";
- continue;
- }
-
- // Create the destination path from the name
- // and version (grabbed from the source path)
- // ### let qmlimportscanner provide this.
- name.replace(QLatin1Char('.'), QLatin1Char('/'));
- int secondTolast = path.length() - 2;
- QString version = path.mid(secondTolast);
- if (version.startsWith(QLatin1Char('.')))
- name.append(version);
-
- deployQmlImport(appBundlePath, deploymentInfo.rpathsUsed, path, name);
- LogNormal() << "";
- }
- return true;
-}
-
-void codesignFile(const QString &identity, const QString &filePath)
-{
- if (!runCodesign)
- return;
-
- QString codeSignLogMessage = "codesign";
- if (hardenedRuntime)
- codeSignLogMessage += ", enable hardened runtime";
- if (secureTimestamp)
- codeSignLogMessage += ", include secure timestamp";
- LogNormal() << codeSignLogMessage << filePath;
-
- QStringList codeSignOptions = { "--preserve-metadata=identifier,entitlements", "--force", "-s",
- identity, filePath };
- if (hardenedRuntime)
- codeSignOptions << "-o" << "runtime";
-
- if (secureTimestamp)
- codeSignOptions << "--timestamp";
-
- if (!extraEntitlements.isEmpty())
- codeSignOptions << "--entitlements" << extraEntitlements;
-
- QProcess codesign;
- codesign.start("codesign", codeSignOptions);
- codesign.waitForFinished(-1);
-
- QByteArray err = codesign.readAllStandardError();
- if (codesign.exitCode() > 0) {
- LogError() << "Codesign signing error:";
- LogError() << err;
- } else if (!err.isEmpty()) {
- LogDebug() << err;
- }
-}
-
-QSet<QString> codesignBundle(const QString &identity,
- const QString &appBundlePath,
- QList<QString> additionalBinariesContainingRpaths)
-{
- // Code sign all binaries in the app bundle. This needs to
- // be done inside-out, e.g sign framework dependencies
- // before the main app binary. The codesign tool itself has
- // a "--deep" option to do this, but usage when signing is
- // not recommended: "Signing with --deep is for emergency
- // repairs and temporary adjustments only."
-
- LogNormal() << "";
- LogNormal() << "Signing" << appBundlePath << "with identity" << identity;
-
- QStack<QString> pendingBinaries;
- QSet<QString> pendingBinariesSet;
- QSet<QString> signedBinaries;
-
- // Create the root code-binary set. This set consists of the application
- // executable(s) and the plugins.
- QString appBundleAbsolutePath = QFileInfo(appBundlePath).absoluteFilePath();
- QString rootBinariesPath = appBundleAbsolutePath + "/Contents/MacOS/";
- QStringList foundRootBinaries = QDir(rootBinariesPath).entryList(QStringList() << "*", QDir::Files);
- for (const QString &binary : foundRootBinaries) {
- QString binaryPath = rootBinariesPath + binary;
- pendingBinaries.push(binaryPath);
- pendingBinariesSet.insert(binaryPath);
- additionalBinariesContainingRpaths.append(binaryPath);
- }
-
- bool getAbsoltuePath = true;
- QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/", getAbsoltuePath);
- for (const QString &binary : foundPluginBinaries) {
- pendingBinaries.push(binary);
- pendingBinariesSet.insert(binary);
- }
-
- // Add frameworks for processing.
- QStringList frameworkPaths = findAppFrameworkPaths(appBundlePath);
- for (const QString &frameworkPath : frameworkPaths) {
-
- // Prioritise first to sign any additional inner bundles found in the Helpers folder (e.g
- // used by QtWebEngine).
- QDirIterator helpersIterator(frameworkPath, QStringList() << QString::fromLatin1("Helpers"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories);
- while (helpersIterator.hasNext()) {
- helpersIterator.next();
- QString helpersPath = helpersIterator.filePath();
- QStringList innerBundleNames = QDir(helpersPath).entryList(QStringList() << "*.app", QDir::Dirs);
- for (const QString &innerBundleName : innerBundleNames)
- signedBinaries += codesignBundle(identity,
- helpersPath + "/" + innerBundleName,
- additionalBinariesContainingRpaths);
- }
-
- // Also make sure to sign any libraries that will not be found by otool because they
- // are not linked and won't be seen as a dependency.
- QDirIterator librariesIterator(frameworkPath, QStringList() << QString::fromLatin1("Libraries"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories);
- while (librariesIterator.hasNext()) {
- librariesIterator.next();
- QString librariesPath = librariesIterator.filePath();
- QStringList bundleFiles = findAppBundleFiles(librariesPath, getAbsoltuePath);
- for (const QString &binary : bundleFiles) {
- pendingBinaries.push(binary);
- pendingBinariesSet.insert(binary);
- }
- }
- }
-
- // Sign all binaries; use otool to find and sign dependencies first.
- while (!pendingBinaries.isEmpty()) {
- QString binary = pendingBinaries.pop();
- if (signedBinaries.contains(binary))
- continue;
-
- // Check if there are unsigned dependencies, sign these first.
- QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary,
- additionalBinariesContainingRpaths);
- dependencies = QSet<QString>(dependencies.begin(), dependencies.end())
- .subtract(signedBinaries)
- .subtract(pendingBinariesSet)
- .values();
-
- if (!dependencies.isEmpty()) {
- pendingBinaries.push(binary);
- pendingBinariesSet.insert(binary);
- int dependenciesSkipped = 0;
- for (const QString &dependency : std::as_const(dependencies)) {
- // Skip dependencies that are outside the current app bundle, because this might
- // cause a codesign error if the current bundle is part of the dependency (e.g.
- // a bundle is part of a framework helper, and depends on that framework).
- // The dependencies will be taken care of after the current bundle is signed.
- if (!dependency.startsWith(appBundleAbsolutePath)) {
- ++dependenciesSkipped;
- LogNormal() << "Skipping outside dependency: " << dependency;
- continue;
- }
- pendingBinaries.push(dependency);
- pendingBinariesSet.insert(dependency);
- }
-
- // If all dependencies were skipped, make sure the binary is actually signed, instead
- // of going into an infinite loop.
- if (dependenciesSkipped == dependencies.size()) {
- pendingBinaries.pop();
- } else {
- continue;
- }
- }
-
- // Look for an entitlements file in the bundle to include when signing
- extraEntitlements = findEntitlementsFile(appBundleAbsolutePath + "/Contents/Resources/");
-
- // All dependencies are signed, now sign this binary.
- codesignFile(identity, binary);
- signedBinaries.insert(binary);
- pendingBinariesSet.remove(binary);
- }
-
- LogNormal() << "Finished codesigning " << appBundlePath << "with identity" << identity;
-
- // Verify code signature
- QProcess codesign;
- codesign.start("codesign", QStringList() << "--deep" << "-v" << appBundlePath);
- codesign.waitForFinished(-1);
- QByteArray err = codesign.readAllStandardError();
- if (codesign.exitCode() > 0) {
- LogError() << "codesign verification error:";
- LogError() << err;
- } else if (!err.isEmpty()) {
- LogDebug() << err;
- }
-
- return signedBinaries;
-}
-
-void codesign(const QString &identity, const QString &appBundlePath) {
- codesignBundle(identity, appBundlePath, QList<QString>());
-}
-
-void createDiskImage(const QString &appBundlePath, const QString &filesystemType)
-{
- QString appBaseName = appBundlePath;
- appBaseName.chop(4); // remove ".app" from end
-
- QString dmgName = appBaseName + ".dmg";
-
- QFile dmg(dmgName);
-
- if (dmg.exists() && alwaysOwerwriteEnabled)
- dmg.remove();
-
- if (dmg.exists()) {
- LogNormal() << "Disk image already exists, skipping .dmg creation for" << dmg.fileName();
- } else {
- LogNormal() << "Creating disk image (.dmg) for" << appBundlePath;
- }
-
- LogNormal() << "Image will use" << filesystemType;
-
- // More dmg options can be found in the hdiutil man page.
- QStringList options = QStringList()
- << "create" << dmgName
- << "-srcfolder" << appBundlePath
- << "-format" << "UDZO"
- << "-fs" << filesystemType
- << "-volname" << appBaseName;
-
- QProcess hdutil;
- hdutil.start("hdiutil", options);
- hdutil.waitForFinished(-1);
- if (hdutil.exitCode() != 0) {
- LogError() << "Bundle creation error:" << hdutil.readAllStandardError();
- }
-}
-
-void fixupFramework(const QString &frameworkName)
-{
- // Expected framework name looks like "Foo.framework"
- QStringList parts = frameworkName.split(".");
- if (parts.count() < 2) {
- LogError() << "fixupFramework: Unexpected framework name" << frameworkName;
- return;
- }
-
- // Assume framework binary path is Foo.framework/Foo
- QString frameworkBinary = frameworkName + QStringLiteral("/") + parts[0];
-
- // Xcode expects to find Foo.framework/Versions/A when code
- // signing, while qmake typically generates numeric versions.
- // Create symlink to the actual version in the framework.
- linkFilePrintStatus("Current", frameworkName + "/Versions/A");
-
- // Set up @rpath structure.
- changeIdentification("@rpath/" + frameworkBinary, frameworkBinary);
- addRPath("@loader_path/../../Contents/Frameworks/", frameworkBinary);
-}
diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h
deleted file mode 100644
index 48ea24b11..000000000
--- a/src/macdeployqt/shared/shared.h
+++ /dev/null
@@ -1,141 +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$
-**
-****************************************************************************/
-#ifndef MAC_DEPLOMYMENT_SHARED_H
-#define MAC_DEPLOMYMENT_SHARED_H
-
-#include <QString>
-#include <QStringList>
-#include <QDebug>
-#include <QSet>
-#include <QVersionNumber>
-
-extern int logLevel;
-#define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:"
-#define LogWarning() if (logLevel < 1) {} else qDebug() << "WARNING:"
-#define LogNormal() if (logLevel < 2) {} else qDebug() << "Log:"
-#define LogDebug() if (logLevel < 3) {} else qDebug() << "Log:"
-
-extern bool runStripEnabled;
-
-class FrameworkInfo
-{
-public:
- bool isDylib;
- QString frameworkDirectory;
- QString frameworkName;
- QString frameworkPath;
- QString binaryDirectory;
- QString binaryName;
- QString binaryPath;
- QString rpathUsed;
- QString version;
- QString installName;
- QString deployedInstallName;
- QString sourceFilePath;
- QString frameworkDestinationDirectory;
- QString binaryDestinationDirectory;
-
- bool isDebugLibrary() const
- {
- return binaryName.endsWith(QStringLiteral("_debug"));
- }
-};
-
-class DylibInfo
-{
-public:
- QString binaryPath;
- QVersionNumber currentVersion;
- QVersionNumber compatibilityVersion;
-};
-
-class OtoolInfo
-{
-public:
- QString installName;
- QString binaryPath;
- QVersionNumber currentVersion;
- QVersionNumber compatibilityVersion;
- QList<DylibInfo> dependencies;
-};
-
-bool operator==(const FrameworkInfo &a, const FrameworkInfo &b);
-QDebug operator<<(QDebug debug, const FrameworkInfo &info);
-
-class ApplicationBundleInfo
-{
- public:
- QString path;
- QString binaryPath;
- QStringList libraryPaths;
-};
-
-class DeploymentInfo
-{
-public:
- QString qtPath;
- QString pluginPath;
- QStringList deployedFrameworks;
- QList<QString> rpathsUsed;
- bool useLoaderPath;
- bool isFramework;
- bool isDebug;
-
- bool containsModule(const QString &module, const QString &libInFix) const;
-};
-
-inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info);
-
-OtoolInfo findDependencyInfo(const QString &binaryPath);
-FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
-QString findAppBinary(const QString &appBundlePath);
-QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
-QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
-QString copyFramework(const FrameworkInfo &framework, const QString path);
-DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringList &additionalExecutables, bool useDebugLibs);
-DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs, bool useLoaderPath);
-void createQtConf(const QString &appBundlePath);
-void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs);
-bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInfo, QStringList &qmlDirs, QStringList &qmlImportPaths);
-void changeIdentification(const QString &id, const QString &binaryPath);
-void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath);
-void runStrip(const QString &binaryPath);
-void stripAppBinary(const QString &bundlePath);
-QString findAppBinary(const QString &appBundlePath);
-QStringList findAppFrameworkNames(const QString &appBundlePath);
-QStringList findAppFrameworkPaths(const QString &appBundlePath);
-void codesignFile(const QString &identity, const QString &filePath);
-QSet<QString> codesignBundle(const QString &identity,
- const QString &appBundlePath,
- QList<QString> additionalBinariesContainingRpaths);
-void codesign(const QString &identity, const QString &appBundlePath);
-void createDiskImage(const QString &appBundlePath, const QString &filesystemType);
-void fixupFramework(const QString &appBundlePath);
-
-
-#endif
diff --git a/src/shared/winutils/elfreader.cpp b/src/shared/winutils/elfreader.cpp
deleted file mode 100644
index f375f5841..000000000
--- a/src/shared/winutils/elfreader.cpp
+++ /dev/null
@@ -1,440 +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 "elfreader.h"
-
-#include <QDir>
-
-QT_BEGIN_NAMESPACE
-
-/* This is a copy of the ELF reader contained in Qt Creator (src/libs/utils),
- * extended by the dependencies() function to read out the dependencies of a dynamic executable. */
-
-quint16 getHalfWord(const unsigned char *&s, const ElfData &context)
-{
- quint16 res;
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint16>(s);
- else
- res = qFromLittleEndian<quint16>(s);
- s += 2;
- return res;
-}
-
-quint32 getWord(const unsigned char *&s, const ElfData &context)
-{
- quint32 res;
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint32>(s);
- else
- res = qFromLittleEndian<quint32>(s);
- s += 4;
- return res;
-}
-
-quint64 getAddress(const unsigned char *&s, const ElfData &context)
-{
- quint64 res;
- if (context.elfclass == Elf_ELFCLASS32) {
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint32>(s);
- else
- res = qFromLittleEndian<quint32>(s);
- s += 4;
- } else {
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint64>(s);
- else
- res = qFromLittleEndian<quint64>(s);
- s += 8;
- }
- return res;
-}
-
-quint64 getOffset(const unsigned char *&s, const ElfData &context)
-{
- return getAddress(s, context);
-}
-
-static void parseSectionHeader(const uchar *s, ElfSectionHeader *sh, const ElfData &context)
-{
- sh->index = getWord(s, context);
- sh->type = getWord(s, context);
- sh->flags = quint32(getOffset(s, context));
- sh->addr = getAddress(s, context);
- sh->offset = getOffset(s, context);
- sh->size = getOffset(s, context);
-}
-
-static void parseProgramHeader(const uchar *s, ElfProgramHeader *sh, const ElfData &context)
-{
- sh->type = getWord(s, context);
- sh->offset = getOffset(s, context);
- /* p_vaddr = */ getAddress(s, context);
- /* p_paddr = */ getAddress(s, context);
- sh->filesz = getWord(s, context);
- sh->memsz = getWord(s, context);
-}
-
-class ElfMapper
-{
-public:
- ElfMapper(const ElfReader *reader) : file(reader->m_binary) {}
-
- bool map()
- {
- if (!file.open(QIODevice::ReadOnly))
- return false;
-
- fdlen = quint64(file.size());
- ustart = file.map(0, qint64(fdlen));
- if (ustart == 0) {
- // Try reading the data into memory instead.
- raw = file.readAll();
- start = raw.constData();
- fdlen = quint64(raw.size());
- }
- return true;
- }
-
-public:
- QFile file;
- QByteArray raw;
- union { const char *start; const uchar *ustart; };
- quint64 fdlen;
-};
-
-ElfReader::ElfReader(const QString &binary)
- : m_binary(binary)
-{
-}
-
-ElfData ElfReader::readHeaders()
-{
- readIt();
- return m_elfData;
-}
-
-static inline QString msgInvalidElfObject(const QString &binary, const QString &why)
-{
- return QStringLiteral("'%1' is an invalid ELF object (%2)")
- .arg(QDir::toNativeSeparators(binary), why);
-}
-
-ElfReader::Result ElfReader::readIt()
-{
- if (!m_elfData.sectionHeaders.isEmpty())
- return Ok;
- if (!m_elfData.programHeaders.isEmpty())
- return Ok;
-
- ElfMapper mapper(this);
- if (!mapper.map())
- return Corrupt;
-
- const quint64 fdlen = mapper.fdlen;
-
- if (fdlen < 64) {
- m_errorString = QStringLiteral("'%1' is not an ELF object (file too small)").arg(QDir::toNativeSeparators(m_binary));
- return NotElf;
- }
-
- if (strncmp(mapper.start, "\177ELF", 4) != 0) {
- m_errorString = QStringLiteral("'%1' is not an ELF object").arg(QDir::toNativeSeparators(m_binary));
- return NotElf;
- }
-
- // 32 or 64 bit
- m_elfData.elfclass = ElfClass(mapper.start[4]);
- const bool is64Bit = m_elfData.elfclass == Elf_ELFCLASS64;
- if (m_elfData.elfclass != Elf_ELFCLASS32 && m_elfData.elfclass != Elf_ELFCLASS64) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("odd cpu architecture"));
- return Corrupt;
- }
-
- // int bits = (data[4] << 5);
- // If you remove this check to read ELF objects of a different arch,
- // please make sure you modify the typedefs
- // to match the _plugin_ architecture.
- // if ((sizeof(void*) == 4 && bits != 32)
- // || (sizeof(void*) == 8 && bits != 64)) {
- // if (errorString)
- // *errorString = QLibrary::QStringLiteral("'%1' is an invalid ELF object (%2)")
- // .arg(m_binary).arg(QLatin1String("wrong cpu architecture"));
- // return Corrupt;
- // }
-
- // Read Endianhness.
- m_elfData.endian = ElfEndian(mapper.ustart[5]);
- if (m_elfData.endian != Elf_ELFDATA2LSB && m_elfData.endian != Elf_ELFDATA2MSB) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("odd endianness"));
- return Corrupt;
- }
-
- const uchar *data = mapper.ustart + 16; // e_ident
- m_elfData.elftype = ElfType(getHalfWord(data, m_elfData));
- m_elfData.elfmachine = ElfMachine(getHalfWord(data, m_elfData));
- /* e_version = */ getWord(data, m_elfData);
- m_elfData.entryPoint = getAddress(data, m_elfData);
-
- quint64 e_phoff = getOffset(data, m_elfData);
- quint64 e_shoff = getOffset(data, m_elfData);
- /* e_flags = */ getWord(data, m_elfData);
-
- quint32 e_shsize = getHalfWord(data, m_elfData);
-
- if (e_shsize > fdlen) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("unexpected e_shsize"));
- return Corrupt;
- }
-
- quint32 e_phentsize = getHalfWord(data, m_elfData);
- if (e_phentsize != (is64Bit ? 56 : 32)) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("invalid structure"));
- return ElfReader::Corrupt;
- }
- quint32 e_phnum = getHalfWord(data, m_elfData);
-
- quint32 e_shentsize = getHalfWord(data, m_elfData);
-
- if (e_shentsize % 4) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("unexpected e_shentsize"));
- return Corrupt;
- }
-
- quint32 e_shnum = getHalfWord(data, m_elfData);
- quint32 e_shtrndx = getHalfWord(data, m_elfData);
- if (data != mapper.ustart + (is64Bit ? 64 : 52)) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("unexpected e_phentsize"));
- return ElfReader::Corrupt;
- }
-
- if (quint64(e_shnum) * e_shentsize > fdlen) {
- const QString reason = QStringLiteral("announced %1 sections, each %2 bytes, exceed file size").arg(e_shnum).arg(e_shentsize);
- m_errorString = msgInvalidElfObject(m_binary, reason);
- return Corrupt;
- }
-
- quint64 soff = e_shoff + e_shentsize * e_shtrndx;
-
-// if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
-// m_errorString = QLibrary::QStringLiteral("'%1' is an invalid ELF object (%2)")
-// .arg(m_binary)
-// .arg(QLatin1String("shstrtab section header seems to be at %1"))
-// .arg(QString::number(soff, 16));
-// return Corrupt;
-// }
-
- if (e_shoff) {
- ElfSectionHeader strtab;
- parseSectionHeader(mapper.ustart + soff, &strtab, m_elfData);
- const quint64 stringTableFileOffset = strtab.offset;
- if (quint32(stringTableFileOffset + e_shentsize) >= fdlen
- || stringTableFileOffset == 0) {
- const QString reason = QStringLiteral("string table seems to be at 0x%1").arg(soff, 0, 16);
- m_errorString = msgInvalidElfObject(m_binary, reason);
- return Corrupt;
- }
-
- for (quint32 i = 0; i < e_shnum; ++i) {
- const uchar *s = mapper.ustart + e_shoff + i * e_shentsize;
- ElfSectionHeader sh;
- parseSectionHeader(s, &sh, m_elfData);
-
- if (stringTableFileOffset + sh.index > fdlen) {
- const QString reason = QStringLiteral("section name %1 of %2 behind end of file")
- .arg(i).arg(e_shnum);
- m_errorString = msgInvalidElfObject(m_binary, reason);
- return Corrupt;
- }
-
- sh.name = mapper.start + stringTableFileOffset + sh.index;
- if (sh.name == ".gdb_index") {
- m_elfData.symbolsType = FastSymbols;
- } else if (sh.name == ".debug_info") {
- m_elfData.symbolsType = PlainSymbols;
- } else if (sh.name == ".gnu_debuglink") {
- m_elfData.debugLink = QByteArray(mapper.start + sh.offset);
- m_elfData.symbolsType = LinkedSymbols;
- } else if (sh.name == ".note.gnu.build-id") {
- m_elfData.symbolsType = BuildIdSymbols;
- if (sh.size > 16)
- m_elfData.buildId = QByteArray(mapper.start + sh.offset + 16,
- int(sh.size) - 16).toHex();
- }
- m_elfData.sectionHeaders.append(sh);
- }
- }
-
- if (e_phoff) {
- for (quint32 i = 0; i < e_phnum; ++i) {
- const uchar *s = mapper.ustart + e_phoff + i * e_phentsize;
- ElfProgramHeader ph;
- parseProgramHeader(s, &ph, m_elfData);
- m_elfData.programHeaders.append(ph);
- }
- }
- return Ok;
-}
-
-QByteArray ElfReader::readSection(const QByteArray &name)
-{
- readIt();
- int i = m_elfData.indexOf(name);
- if (i == -1)
- return QByteArray();
-
- ElfMapper mapper(this);
- if (!mapper.map())
- return QByteArray();
-
- const ElfSectionHeader &section = m_elfData.sectionHeaders.at(i);
- return QByteArray(mapper.start + section.offset, int(section.size));
-}
-
-static QByteArray cutout(const char *s)
-{
- QByteArray res(s, 80);
- const int pos = res.indexOf('\0');
- if (pos != -1)
- res.resize(pos - 1);
- return res;
-}
-
-QByteArray ElfReader::readCoreName(bool *isCore)
-{
- *isCore = false;
-
- readIt();
-
- ElfMapper mapper(this);
- if (!mapper.map())
- return QByteArray();
-
- if (m_elfData.elftype != Elf_ET_CORE)
- return QByteArray();
-
- *isCore = true;
-
- for (int i = 0, n = m_elfData.sectionHeaders.size(); i != n; ++i)
- if (m_elfData.sectionHeaders.at(i).type == Elf_SHT_NOTE) {
- const ElfSectionHeader &header = m_elfData.sectionHeaders.at(i);
- return cutout(mapper.start + header.offset + 0x40);
- }
-
- for (int i = 0, n = m_elfData.programHeaders.size(); i != n; ++i)
- if (m_elfData.programHeaders.at(i).type == Elf_PT_NOTE) {
- const ElfProgramHeader &header = m_elfData.programHeaders.at(i);
- return cutout(mapper.start + header.offset + 0xec);
- }
-
- return QByteArray();
-}
-
-int ElfData::indexOf(const QByteArray &name) const
-{
- for (int i = 0, n = sectionHeaders.size(); i != n; ++i)
- if (sectionHeaders.at(i).name == name)
- return i;
- return -1;
-}
-
-/* Helpers for reading out the .dynamic section containing the dependencies.
- * The ".dynamic" section is an array of
- * typedef struct {
- * Elf32_Sword d_tag;
- * union {
- * Elf32_Word d_val;
- * dElf32_Addr d_ptr;
- * } d_un;
- * } Elf32_Dyn
- * with entries where a tag DT_NEEDED indicates that m_val is an offset into
- * the string table ".dynstr". The documentation states that entries with the
- * tag DT_STRTAB contain an offset for the string table to be used, but that
- * has been found not to contain valid entries. */
-
-enum DynamicSectionTags {
- DT_NULL = 0,
- DT_NEEDED = 1,
- DT_STRTAB = 5,
- DT_SONAME = 14,
- DT_RPATH = 15
-};
-
-QList<QByteArray> ElfReader::dependencies()
-{
- QList<QByteArray> result;
-
- ElfMapper mapper(this);
- if (!mapper.map()) {
- m_errorString = QStringLiteral("Mapper failure");
- return result;
- }
- quint64 dynStrOffset = 0;
- quint64 dynamicOffset = 0;
- quint64 dynamicSize = 0;
-
- const QList<ElfSectionHeader> &headers = readHeaders().sectionHeaders;
- for (const ElfSectionHeader &eh : headers) {
- if (eh.name == QByteArrayLiteral(".dynstr")) {
- dynStrOffset = eh.offset;
- } else if (eh.name == QByteArrayLiteral(".dynamic")) {
- dynamicOffset = eh.offset;
- dynamicSize = eh.size;
- }
- if (dynStrOffset && dynamicOffset)
- break;
- }
-
- if (!dynStrOffset || !dynamicOffset) {
- m_errorString = QStringLiteral("Not a dynamically linked executable.");
- return result;
- }
-
- const unsigned char *dynamicData = mapper.ustart + dynamicOffset;
- const unsigned char *dynamicDataEnd = dynamicData + dynamicSize;
- while (dynamicData < dynamicDataEnd) {
- const quint32 tag = getWord(dynamicData, m_elfData);
- if (tag == DT_NULL)
- break;
- if (m_elfData.elfclass == Elf_ELFCLASS64)
- dynamicData += sizeof(quint32); // padding to d_val/d_ptr.
- if (tag == DT_NEEDED) {
- const quint32 offset = getWord(dynamicData, m_elfData);
- if (m_elfData.elfclass == Elf_ELFCLASS64)
- dynamicData += sizeof(quint32); // past d_ptr.
- const char *name = mapper.start + dynStrOffset + offset;
- result.push_back(name);
- } else {
- dynamicData += m_elfData.elfclass == Elf_ELFCLASS64 ? 8 : 4;
- }
- }
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/shared/winutils/elfreader.h b/src/shared/winutils/elfreader.h
deleted file mode 100644
index d84f5a060..000000000
--- a/src/shared/winutils/elfreader.h
+++ /dev/null
@@ -1,176 +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$
-**
-****************************************************************************/
-
-#ifndef ELFREADER_H
-#define ELFREADER_H
-
-#include <QtCore/QList>
-#include <QtCore/QString>
-#include <QtCore/QtEndian>
-
-QT_BEGIN_NAMESPACE
-
-enum ElfProgramHeaderType
-{
- Elf_PT_NULL = 0,
- Elf_PT_LOAD = 1,
- Elf_PT_DYNAMIC = 2,
- Elf_PT_INTERP = 3,
- Elf_PT_NOTE = 4,
- Elf_PT_SHLIB = 5,
- Elf_PT_PHDR = 6,
- Elf_PT_TLS = 7,
- Elf_PT_NUM = 8
-};
-
-enum ElfSectionHeaderType
-{
- Elf_SHT_NULL = 0,
- Elf_SHT_PROGBITS = 1,
- Elf_SHT_SYMTAB = 2,
- Elf_SHT_STRTAB = 3,
- Elf_SHT_RELA = 4,
- Elf_SHT_HASH = 5,
- Elf_SHT_DYNAMIC = 6,
- Elf_SHT_NOTE = 7,
- Elf_SHT_NOBITS = 8,
- Elf_SHT_REL = 9,
- Elf_SHT_SHLIB = 10,
- Elf_SHT_DYNSYM = 11,
- Elf_SHT_INIT_ARRAY = 14,
- Elf_SHT_FINI_ARRAY = 15,
- Elf_SHT_PREINIT_ARRAY = 16,
- Elf_SHT_GROUP = 17,
- Elf_SHT_SYMTAB_SHNDX = 18
-};
-
-enum ElfEndian
-{
- Elf_ELFDATANONE = 0,
- Elf_ELFDATA2LSB = 1,
- Elf_ELFDATA2MSB = 2,
- Elf_ELFDATANUM = 3
-};
-
-enum ElfClass
-{
- Elf_ELFCLASS32 = 1,
- Elf_ELFCLASS64 = 2
-};
-
-enum ElfType
-{
- Elf_ET_NONE = 0,
- Elf_ET_REL = 1,
- Elf_ET_EXEC = 2,
- Elf_ET_DYN = 3,
- Elf_ET_CORE = 4
-};
-
-enum ElfMachine
-{
- Elf_EM_386 = 3,
- Elf_EM_ARM = 40,
- Elf_EM_X86_64 = 62
-};
-
-enum DebugSymbolsType
-{
- UnknownSymbols = 0, // Unknown.
- NoSymbols = 1, // No usable symbols.
- LinkedSymbols = 2, // Link to symols available.
- BuildIdSymbols = 4, // BuildId available.
- PlainSymbols = 8, // Ordinary symbols available.
- FastSymbols = 16 // Dwarf index available.
-};
-
-class ElfSectionHeader
-{
-public:
- QByteArray name;
- quint32 index;
- quint32 type;
- quint32 flags;
- quint64 offset;
- quint64 size;
- quint64 addr;
-};
-
-class ElfProgramHeader
-{
-public:
- quint32 name;
- quint32 type;
- quint64 offset;
- quint64 filesz;
- quint64 memsz;
-};
-
-class ElfData
-{
-public:
- ElfData() : symbolsType(UnknownSymbols) {}
- int indexOf(const QByteArray &name) const;
-
-public:
- ElfEndian endian;
- ElfType elftype;
- ElfMachine elfmachine;
- ElfClass elfclass;
- quint64 entryPoint;
- QByteArray debugLink;
- QByteArray buildId;
- DebugSymbolsType symbolsType;
- QList<ElfSectionHeader> sectionHeaders;
- QList<ElfProgramHeader> programHeaders;
-};
-
-class ElfReader
-{
-public:
- explicit ElfReader(const QString &binary);
- enum Result { Ok, NotElf, Corrupt };
-
- ElfData readHeaders();
- QByteArray readSection(const QByteArray &sectionName);
- QString errorString() const { return m_errorString; }
- QByteArray readCoreName(bool *isCore);
- QList<QByteArray> dependencies();
-
-private:
- friend class ElfMapper;
- Result readIt();
-
- QString m_binary;
- QString m_errorString;
- ElfData m_elfData;
-};
-
-QT_END_NAMESPACE
-
-#endif // ELFREADER_H
diff --git a/src/shared/winutils/qmlutils.cpp b/src/shared/winutils/qmlutils.cpp
deleted file mode 100644
index 6eebf6d86..000000000
--- a/src/shared/winutils/qmlutils.cpp
+++ /dev/null
@@ -1,160 +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 "qmlutils.h"
-#include "utils.h"
-
-#include <QtCore/QDir>
-#include <QtCore/QFileInfo>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QJsonDocument>
-#include <QtCore/QJsonObject>
-#include <QtCore/QJsonArray>
-#include <QtCore/QJsonParseError>
-
-QT_BEGIN_NAMESPACE
-
-bool operator==(const QmlImportScanResult::Module &m1, const QmlImportScanResult::Module &m2)
-{
- return m1.className.isEmpty() ? m1.name == m2.name : m1.className == m2.className;
-}
-
-// Return install path (cp -r semantics)
-QString QmlImportScanResult::Module::installPath(const QString &root) const
-{
- QString result = root;
- const int lastSlashPos = relativePath.lastIndexOf(QLatin1Char('/'));
- if (lastSlashPos != -1) {
- result += QLatin1Char('/');
- result += QStringView{relativePath}.left(lastSlashPos);
- }
- return result;
-}
-
-static QString qmlDirectoryRecursion(Platform platform, const QString &path)
-{
- QDir dir(path);
- if (!dir.entryList(QStringList(QStringLiteral("*.qml")), QDir::Files, QDir::NoSort).isEmpty())
- return dir.path();
- const QFileInfoList &subDirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot, QDir::NoSort);
- for (const QFileInfo &subDirFi : subDirs) {
- if (!isBuildDirectory(platform, subDirFi.fileName())) {
- const QString subPath = qmlDirectoryRecursion(platform, subDirFi.absoluteFilePath());
- if (!subPath.isEmpty())
- return subPath;
- }
- }
- return QString();
-}
-
-// Find a directory containing QML files in the project
-QString findQmlDirectory(Platform platform, const QString &startDirectoryName)
-{
- QDir startDirectory(startDirectoryName);
- if (isBuildDirectory(platform, startDirectory.dirName()))
- startDirectory.cdUp();
- return qmlDirectoryRecursion(platform, startDirectory.path());
-}
-
-static void findFileRecursion(const QDir &directory, Platform platform,
- DebugMatchMode debugMatchMode, QStringList *matches)
-{
- const QStringList &dlls = findSharedLibraries(directory, platform, debugMatchMode);
- for (const QString &dll : dlls)
- matches->append(directory.filePath(dll));
- const QFileInfoList &subDirs = directory.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
- for (const QFileInfo &subDirFi : subDirs) {
- QDir subDirectory(subDirFi.absoluteFilePath());
- if (subDirectory.isReadable())
- findFileRecursion(subDirectory, platform, debugMatchMode, matches);
- }
-}
-
-QmlImportScanResult runQmlImportScanner(const QString &directory, const QStringList &qmlImportPaths,
- bool usesWidgets, int platform, DebugMatchMode debugMatchMode,
- QString *errorMessage)
-{
- Q_UNUSED(usesWidgets);
- QmlImportScanResult result;
- QStringList arguments;
- for (const QString &importPath : qmlImportPaths)
- arguments << QStringLiteral("-importPath") << importPath;
- arguments << QStringLiteral("-rootPath") << directory;
- unsigned long exitCode;
- QByteArray stdOut;
- QByteArray stdErr;
- const QString binary = QStringLiteral("qmlimportscanner");
- if (!runProcess(binary, arguments, QDir::currentPath(), &exitCode, &stdOut, &stdErr, errorMessage))
- return result;
- if (exitCode) {
- *errorMessage = binary + QStringLiteral(" returned ") + QString::number(exitCode)
- + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr);
- return result;
- }
- QJsonParseError jsonParseError{};
- const QJsonDocument data = QJsonDocument::fromJson(stdOut, &jsonParseError);
- if (data.isNull() ) {
- *errorMessage = binary + QStringLiteral(" returned invalid JSON output: ")
- + jsonParseError.errorString() + QStringLiteral(" :\"")
- + QString::fromLocal8Bit(stdOut) + QLatin1Char('"');
- return result;
- }
- const QJsonArray array = data.array();
- const int childCount = array.count();
- for (int c = 0; c < childCount; ++c) {
- const QJsonObject object = array.at(c).toObject();
- if (object.value(QStringLiteral("type")).toString() == QLatin1String("module")) {
- const QString path = object.value(QStringLiteral("path")).toString();
- if (!path.isEmpty()) {
- QmlImportScanResult::Module module;
- module.name = object.value(QStringLiteral("name")).toString();
- module.className = object.value(QStringLiteral("classname")).toString();
- module.sourcePath = path;
- module.relativePath = object.value(QStringLiteral("relativePath")).toString();
- result.modules.append(module);
- findFileRecursion(QDir(path), Platform(platform), debugMatchMode, &result.plugins);
- }
- }
- }
- result.ok = true;
- return result;
-}
-
-void QmlImportScanResult::append(const QmlImportScanResult &other)
-{
- for (const QmlImportScanResult::Module &module : other.modules) {
- if (std::find(modules.cbegin(), modules.cend(), module) == modules.cend())
- modules.append(module);
- }
- for (const QString &plugin : other.plugins) {
- if (!plugins.contains(plugin))
- plugins.append(plugin);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/shared/winutils/qmlutils.h b/src/shared/winutils/qmlutils.h
deleted file mode 100644
index 572be7cab..000000000
--- a/src/shared/winutils/qmlutils.h
+++ /dev/null
@@ -1,65 +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$
-**
-****************************************************************************/
-
-#ifndef QMLUTILS_H
-#define QMLUTILS_H
-
-#include "utils.h"
-
-#include <QStringList>
-
-QT_BEGIN_NAMESPACE
-
-QString findQmlDirectory(Platform platform, const QString &startDirectoryName);
-
-struct QmlImportScanResult {
- struct Module {
- QString installPath(const QString &root) const;
-
- QString name;
- QString className;
- QString sourcePath;
- QString relativePath;
- };
-
- void append(const QmlImportScanResult &other);
-
- bool ok = false;
- QList<Module> modules;
- QStringList plugins;
-};
-
-bool operator==(const QmlImportScanResult::Module &m1, const QmlImportScanResult::Module &m2);
-
-QmlImportScanResult runQmlImportScanner(const QString &directory, const QStringList &qmlImportPaths,
- bool usesWidgets, int platform, DebugMatchMode debugMatchMode,
- QString *errorMessage);
-
-QT_END_NAMESPACE
-
-#endif // QMLUTILS_H
diff --git a/src/shared/winutils/utils.cpp b/src/shared/winutils/utils.cpp
deleted file mode 100644
index bc52de924..000000000
--- a/src/shared/winutils/utils.cpp
+++ /dev/null
@@ -1,1006 +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 "elfreader.h"
-
-#include <QtCore/QString>
-#include <QtCore/QDebug>
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
-#include <QtCore/QTemporaryFile>
-#include <QtCore/QScopedPointer>
-#include <QtCore/QScopedArrayPointer>
-#include <QtCore/QStandardPaths>
-#if defined(Q_OS_WIN)
-# include <QtCore/qt_windows.h>
-# include <shlwapi.h>
-# include <delayimp.h>
-#else // Q_OS_WIN
-# include <sys/wait.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <unistd.h>
-# include <stdlib.h>
-# include <string.h>
-# include <errno.h>
-# include <fcntl.h>
-#endif // !Q_OS_WIN
-
-QT_BEGIN_NAMESPACE
-
-int optVerboseLevel = 1;
-
-bool isBuildDirectory(Platform platform, const QString &dirName)
-{
- return (platform.testFlag(Msvc) || platform.testFlag(ClangMsvc))
- && (dirName == QLatin1String("debug") || dirName == QLatin1String("release"));
-}
-
-// Create a symbolic link by changing to the source directory to make sure the
-// link uses relative paths only (QFile::link() otherwise uses the absolute path).
-bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
-{
- const QString oldDirectory = QDir::currentPath();
- if (!QDir::setCurrent(source.absolutePath())) {
- *errorMessage = QStringLiteral("Unable to change to directory %1.").arg(QDir::toNativeSeparators(source.absolutePath()));
- return false;
- }
- QFile file(source.fileName());
- const bool success = file.link(target);
- QDir::setCurrent(oldDirectory);
- if (!success) {
- *errorMessage = QString::fromLatin1("Failed to create symbolic link %1 -> %2: %3")
- .arg(QDir::toNativeSeparators(source.absoluteFilePath()),
- QDir::toNativeSeparators(target), file.errorString());
- return false;
- }
- return true;
-}
-
-bool createDirectory(const QString &directory, QString *errorMessage)
-{
- const QFileInfo fi(directory);
- if (fi.isDir())
- return true;
- if (fi.exists()) {
- *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.").
- arg(QDir::toNativeSeparators(directory));
- return false;
- }
- if (optVerboseLevel)
- std::wcout << "Creating " << QDir::toNativeSeparators(directory) << "...\n";
- QDir dir;
- if (!dir.mkpath(directory)) {
- *errorMessage = QString::fromLatin1("Could not create directory %1.").
- arg(QDir::toNativeSeparators(directory));
- return false;
- }
- return true;
-}
-
-// Find shared libraries matching debug/Platform in a directory, return relative names.
-QStringList findSharedLibraries(const QDir &directory, Platform platform,
- DebugMatchMode debugMatchMode,
- const QString &prefix)
-{
- QString nameFilter = prefix;
- if (nameFilter.isEmpty())
- nameFilter += QLatin1Char('*');
- if (debugMatchMode == MatchDebug && platformHasDebugSuffix(platform))
- nameFilter += QLatin1Char('d');
- nameFilter += sharedLibrarySuffix(platform);
- QStringList result;
- QString errorMessage;
- const QFileInfoList &dlls = directory.entryInfoList(QStringList(nameFilter), QDir::Files);
- for (const QFileInfo &dllFi : dlls) {
- const QString dllPath = dllFi.absoluteFilePath();
- bool matches = true;
- if (debugMatchMode != MatchDebugOrRelease && (platform & WindowsBased)) {
- bool debugDll;
- if (readPeExecutable(dllPath, &errorMessage, 0, 0, &debugDll,
- (platform == WindowsDesktopMinGW))) {
- matches = debugDll == (debugMatchMode == MatchDebug);
- } else {
- std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(dllPath)
- << ": " << errorMessage;
- }
- } // Windows
- if (matches)
- result += dllFi.fileName();
- } // for
- return result;
-}
-
-#ifdef Q_OS_WIN
-QString winErrorMessage(unsigned long error)
-{
- QString rc = QString::fromLatin1("#%1: ").arg(error);
- char16_t *lpMsgBuf;
-
- const DWORD len = FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, error, 0, reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, NULL);
- if (len) {
- rc = QString::fromUtf16(lpMsgBuf, int(len));
- LocalFree(lpMsgBuf);
- } else {
- rc += QString::fromLatin1("<unknown error>");
- }
- return rc;
-}
-
-// Case-Normalize file name via GetShortPathNameW()/GetLongPathNameW()
-QString normalizeFileName(const QString &name)
-{
- wchar_t shortBuffer[MAX_PATH];
- const QString nativeFileName = QDir::toNativeSeparators(name);
- if (!GetShortPathNameW(reinterpret_cast<LPCWSTR>(nativeFileName.utf16()), shortBuffer, MAX_PATH))
- return name;
- wchar_t result[MAX_PATH];
- if (!GetLongPathNameW(shortBuffer, result, MAX_PATH))
- return name;
- return QDir::fromNativeSeparators(QString::fromWCharArray(result));
-}
-
-// Find a tool binary in the Windows SDK 8
-QString findSdkTool(const QString &tool)
-{
- QStringList paths = QString::fromLocal8Bit(qgetenv("PATH")).split(QLatin1Char(';'));
- const QByteArray sdkDir = qgetenv("WindowsSdkDir");
- if (!sdkDir.isEmpty())
- paths.prepend(QDir::cleanPath(QString::fromLocal8Bit(sdkDir)) + QLatin1String("/Tools/x64"));
- return QStandardPaths::findExecutable(tool, paths);
-}
-
-// runProcess helper: Create a temporary file for stdout/stderr redirection.
-static HANDLE createInheritableTemporaryFile()
-{
- wchar_t path[MAX_PATH];
- if (!GetTempPath(MAX_PATH, path))
- return INVALID_HANDLE_VALUE;
- wchar_t name[MAX_PATH];
- if (!GetTempFileName(path, L"temp", 0, name)) // Creates file.
- return INVALID_HANDLE_VALUE;
- SECURITY_ATTRIBUTES securityAttributes;
- ZeroMemory(&securityAttributes, sizeof(securityAttributes));
- securityAttributes.nLength = sizeof(securityAttributes);
- securityAttributes.bInheritHandle = TRUE;
- return CreateFile(name, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes,
- TRUNCATE_EXISTING,
- FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
-}
-
-// runProcess helper: Rewind and read out a temporary file for stdout/stderr.
-static inline void readTemporaryProcessFile(HANDLE handle, QByteArray *result)
-{
- if (SetFilePointer(handle, 0, 0, FILE_BEGIN) == 0xFFFFFFFF)
- return;
- char buf[1024];
- DWORD bytesRead;
- while (ReadFile(handle, buf, sizeof(buf), &bytesRead, NULL) && bytesRead)
- result->append(buf, int(bytesRead));
- CloseHandle(handle);
-}
-
-static inline void appendToCommandLine(const QString &argument, QString *commandLine)
-{
- const bool needsQuote = argument.contains(QLatin1Char(' '));
- if (!commandLine->isEmpty())
- commandLine->append(QLatin1Char(' '));
- if (needsQuote)
- commandLine->append(QLatin1Char('"'));
- commandLine->append(argument);
- if (needsQuote)
- commandLine->append(QLatin1Char('"'));
-}
-
-// runProcess: Run a command line process (replacement for QProcess which
-// does not exist in the bootstrap library).
-bool runProcess(const QString &binary, const QStringList &args,
- const QString &workingDirectory,
- unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr,
- QString *errorMessage)
-{
- if (exitCode)
- *exitCode = 0;
-
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
-
- STARTUPINFO myInfo;
- GetStartupInfo(&myInfo);
- si.hStdInput = myInfo.hStdInput;
- si.hStdOutput = myInfo.hStdOutput;
- si.hStdError = myInfo.hStdError;
-
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
- const QChar backSlash = QLatin1Char('\\');
- QString nativeWorkingDir = QDir::toNativeSeparators(workingDirectory.isEmpty() ? QDir::currentPath() : workingDirectory);
- if (!nativeWorkingDir.endsWith(backSlash))
- nativeWorkingDir += backSlash;
-
- if (stdOut) {
- si.hStdOutput = createInheritableTemporaryFile();
- if (si.hStdOutput == INVALID_HANDLE_VALUE) {
- if (errorMessage)
- *errorMessage = QStringLiteral("Error creating stdout temporary file");
- return false;
- }
- si.dwFlags |= STARTF_USESTDHANDLES;
- }
-
- if (stdErr) {
- si.hStdError = createInheritableTemporaryFile();
- if (si.hStdError == INVALID_HANDLE_VALUE) {
- if (errorMessage)
- *errorMessage = QStringLiteral("Error creating stderr temporary file");
- return false;
- }
- si.dwFlags |= STARTF_USESTDHANDLES;
- }
-
- // Create a copy of the command line which CreateProcessW can modify.
- QString commandLine;
- appendToCommandLine(binary, &commandLine);
- for (const QString &a : args)
- appendToCommandLine(a, &commandLine);
- if (optVerboseLevel > 1)
- std::wcout << "Running: " << commandLine << '\n';
-
- QScopedArrayPointer<wchar_t> commandLineW(new wchar_t[commandLine.size() + 1]);
- commandLine.toWCharArray(commandLineW.data());
- commandLineW[commandLine.size()] = 0;
- if (!CreateProcessW(0, commandLineW.data(), 0, 0, /* InheritHandles */ TRUE, 0, 0,
- reinterpret_cast<LPCWSTR>(nativeWorkingDir.utf16()), &si, &pi)) {
- if (stdOut)
- CloseHandle(si.hStdOutput);
- if (stdErr)
- CloseHandle(si.hStdError);
- if (errorMessage)
- *errorMessage = QStringLiteral("CreateProcessW failed: ") + winErrorMessage(GetLastError());
- return false;
- }
-
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hThread);
- if (exitCode)
- GetExitCodeProcess(pi.hProcess, exitCode);
- CloseHandle(pi.hProcess);
-
- if (stdOut)
- readTemporaryProcessFile(si.hStdOutput, stdOut);
- if (stdErr)
- readTemporaryProcessFile(si.hStdError, stdErr);
- return true;
-}
-
-#else // Q_OS_WIN
-
-static inline char *encodeFileName(const QString &f)
-{
- const QByteArray encoded = QFile::encodeName(f);
- char *result = new char[encoded.size() + 1];
- strcpy(result, encoded.constData());
- return result;
-}
-
-static inline char *tempFilePattern()
-{
- QString path = QDir::tempPath();
- if (!path.endsWith(QLatin1Char('/')))
- path += QLatin1Char('/');
- path += QStringLiteral("tmpXXXXXX");
- return encodeFileName(path);
-}
-
-static inline QByteArray readOutRedirectFile(int fd)
-{
- enum { bufSize = 256 };
-
- QByteArray result;
- if (!lseek(fd, 0, 0)) {
- char buf[bufSize];
- while (true) {
- const ssize_t rs = read(fd, buf, bufSize);
- if (rs <= 0)
- break;
- result.append(buf, int(rs));
- }
- }
- close(fd);
- return result;
-}
-
-// runProcess: Run a command line process (replacement for QProcess which
-// does not exist in the bootstrap library).
-bool runProcess(const QString &binary, const QStringList &args,
- const QString &workingDirectory,
- unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr,
- QString *errorMessage)
-{
- QScopedArrayPointer<char> stdOutFileName;
- QScopedArrayPointer<char> stdErrFileName;
-
- int stdOutFile = 0;
- if (stdOut) {
- stdOutFileName.reset(tempFilePattern());
- stdOutFile = mkstemp(stdOutFileName.data());
- if (stdOutFile < 0) {
- *errorMessage = QStringLiteral("mkstemp() failed: ") + QString::fromLocal8Bit(strerror(errno));
- return false;
- }
- }
-
- int stdErrFile = 0;
- if (stdErr) {
- stdErrFileName.reset(tempFilePattern());
- stdErrFile = mkstemp(stdErrFileName.data());
- if (stdErrFile < 0) {
- *errorMessage = QStringLiteral("mkstemp() failed: ") + QString::fromLocal8Bit(strerror(errno));
- return false;
- }
- }
-
- const pid_t pID = fork();
-
- if (pID < 0) {
- *errorMessage = QStringLiteral("Fork failed: ") + QString::fromLocal8Bit(strerror(errno));
- return false;
- }
-
- if (!pID) { // Child
- if (stdOut) {
- dup2(stdOutFile, STDOUT_FILENO);
- close(stdOutFile);
- }
- if (stdErr) {
- dup2(stdErrFile, STDERR_FILENO);
- close(stdErrFile);
- }
-
- if (!workingDirectory.isEmpty() && !QDir::setCurrent(workingDirectory)) {
- std::wcerr << "Failed to change working directory to " << workingDirectory << ".\n";
- ::_exit(-1);
- }
-
- char **argv = new char *[args.size() + 2]; // Create argv.
- char **ap = argv;
- *ap++ = encodeFileName(binary);
- for (const QString &a : qAsConst(args))
- *ap++ = encodeFileName(a);
- *ap = 0;
-
- execvp(argv[0], argv);
- ::_exit(-1);
- }
-
- int status;
- pid_t waitResult;
-
- do {
- waitResult = waitpid(pID, &status, 0);
- } while (waitResult == -1 && errno == EINTR);
-
- if (stdOut) {
- *stdOut = readOutRedirectFile(stdOutFile);
- unlink(stdOutFileName.data());
- }
- if (stdErr) {
- *stdErr = readOutRedirectFile(stdErrFile);
- unlink(stdErrFileName.data());
- }
-
- if (waitResult < 0) {
- *errorMessage = QStringLiteral("Wait failed: ") + QString::fromLocal8Bit(strerror(errno));
- return false;
- }
- if (!WIFEXITED(status)) {
- *errorMessage = binary + QStringLiteral(" did not exit cleanly.");
- return false;
- }
- if (exitCode)
- *exitCode = WEXITSTATUS(status);
- return true;
-}
-
-#endif // !Q_OS_WIN
-
-// Find a file in the path using ShellAPI. This can be used to locate DLLs which
-// QStandardPaths cannot do.
-QString findInPath(const QString &file)
-{
-#if defined(Q_OS_WIN)
- if (file.size() < MAX_PATH - 1) {
- wchar_t buffer[MAX_PATH];
- file.toWCharArray(buffer);
- buffer[file.size()] = 0;
- if (PathFindOnPath(buffer, NULL))
- return QDir::cleanPath(QString::fromWCharArray(buffer));
- }
- return QString();
-#else // Q_OS_WIN
- return QStandardPaths::findExecutable(file);
-#endif // !Q_OS_WIN
-}
-
-const char *qmakeInfixKey = "QT_INFIX";
-
-QMap<QString, QString> queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
-{
- const QString binary = !qtpathsBinary.isEmpty() ? qtpathsBinary : QStringLiteral("qtpaths");
- QByteArray stdOut;
- QByteArray stdErr;
- unsigned long exitCode = 0;
- if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut, &stdErr, errorMessage))
- return QMap<QString, QString>();
- if (exitCode) {
- *errorMessage = binary + QStringLiteral(" returns ") + QString::number(exitCode)
- + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr);
- return QMap<QString, QString>();
- }
- const QString output = QString::fromLocal8Bit(stdOut).trimmed().remove(QLatin1Char('\r'));
- QMap<QString, QString> result;
- const int size = output.size();
- for (int pos = 0; pos < size; ) {
- const int colonPos = output.indexOf(QLatin1Char(':'), pos);
- if (colonPos < 0)
- break;
- int endPos = output.indexOf(QLatin1Char('\n'), colonPos + 1);
- if (endPos < 0)
- endPos = size;
- const QString key = output.mid(pos, colonPos - pos);
- const QString value = output.mid(colonPos + 1, endPos - colonPos - 1);
- result.insert(key, value);
- pos = endPos + 1;
- }
- QFile qconfigPriFile(result.value(QStringLiteral("QT_HOST_DATA")) + QStringLiteral("/mkspecs/qconfig.pri"));
- if (qconfigPriFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- while (true) {
- const QByteArray line = qconfigPriFile.readLine();
- if (line.isEmpty())
- break;
- if (line.startsWith("QT_LIBINFIX")) {
- const int pos = line.indexOf('=');
- if (pos >= 0) {
- const QString infix = QString::fromUtf8(line.right(line.size() - pos - 1).trimmed());
- if (!infix.isEmpty())
- result.insert(QLatin1String(qmakeInfixKey), infix);
- }
- break;
- }
- }
- } else {
- std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(qconfigPriFile.fileName())
- << ": " << qconfigPriFile.errorString()<< '\n';
- }
- return result;
-}
-
-// Update a file or directory.
-bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
- const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
-{
- const QFileInfo sourceFileInfo(sourceFileName);
- const QString targetFileName = targetDirectory + QLatin1Char('/') + sourceFileInfo.fileName();
- if (optVerboseLevel > 1)
- std::wcout << "Checking " << sourceFileName << ", " << targetFileName<< '\n';
-
- if (!sourceFileInfo.exists()) {
- *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName));
- return false;
- }
-
- if (sourceFileInfo.isSymLink()) {
- *errorMessage = QString::fromLatin1("Symbolic links are not supported (%1).")
- .arg(QDir::toNativeSeparators(sourceFileName));
- return false;
- }
-
- const QFileInfo targetFileInfo(targetFileName);
-
- if (sourceFileInfo.isDir()) {
- if (targetFileInfo.exists()) {
- if (!targetFileInfo.isDir()) {
- *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.")
- .arg(QDir::toNativeSeparators(targetFileName));
- return false;
- } // Not a directory.
- } else { // exists.
- QDir d(targetDirectory);
- if (optVerboseLevel)
- std::wcout << "Creating " << QDir::toNativeSeparators(targetFileName) << ".\n";
- if (!(flags & SkipUpdateFile) && !d.mkdir(sourceFileInfo.fileName())) {
- *errorMessage = QString::fromLatin1("Cannot create directory %1 under %2.")
- .arg(sourceFileInfo.fileName(), QDir::toNativeSeparators(targetDirectory));
- return false;
- }
- }
- // Recurse into directory
- QDir dir(sourceFileName);
- const QFileInfoList allEntries = dir.entryInfoList(nameFilters, QDir::Files)
- + dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QFileInfo &entryFi : allEntries) {
- if (!updateFile(entryFi.absoluteFilePath(), nameFilters, targetFileName, flags, json, errorMessage))
- return false;
- }
- return true;
- } // Source is directory.
-
- if (targetFileInfo.exists()) {
- if (!(flags & ForceUpdateFile)
- && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
- if (optVerboseLevel)
- std::wcout << sourceFileInfo.fileName() << " is up to date.\n";
- if (json)
- json->addFile(sourceFileName, targetDirectory);
- return true;
- }
- QFile targetFile(targetFileName);
- if (!(flags & SkipUpdateFile) && !targetFile.remove()) {
- *errorMessage = QString::fromLatin1("Cannot remove existing file %1: %2")
- .arg(QDir::toNativeSeparators(targetFileName), targetFile.errorString());
- return false;
- }
- } // target exists
- QFile file(sourceFileName);
- if (optVerboseLevel)
- std::wcout << "Updating " << sourceFileInfo.fileName() << ".\n";
- if (!(flags & SkipUpdateFile) && !file.copy(targetFileName)) {
- *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3")
- .arg(QDir::toNativeSeparators(sourceFileName),
- QDir::toNativeSeparators(targetFileName),
- file.errorString());
- return false;
- }
- if (json)
- json->addFile(sourceFileName, targetDirectory);
- return true;
-}
-
-bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage,
- QStringList *dependentLibraries, unsigned *wordSize,
- bool *isDebug)
-{
- ElfReader elfReader(elfExecutableFileName);
- const ElfData data = elfReader.readHeaders();
- if (data.sectionHeaders.isEmpty()) {
- *errorMessage = QStringLiteral("Unable to read ELF binary \"")
- + QDir::toNativeSeparators(elfExecutableFileName) + QStringLiteral("\": ")
- + elfReader.errorString();
- return false;
- }
- if (wordSize)
- *wordSize = data.elfclass == Elf_ELFCLASS64 ? 64 : 32;
- if (dependentLibraries) {
- dependentLibraries->clear();
- const QList<QByteArray> libs = elfReader.dependencies();
- if (libs.isEmpty()) {
- *errorMessage = QStringLiteral("Unable to read dependenices of ELF binary \"")
- + QDir::toNativeSeparators(elfExecutableFileName) + QStringLiteral("\": ")
- + elfReader.errorString();
- return false;
- }
- for (const QByteArray &l : libs)
- dependentLibraries->push_back(QString::fromLocal8Bit(l));
- }
- if (isDebug)
- *isDebug = data.symbolsType != UnknownSymbols && data.symbolsType != NoSymbols;
- return true;
-}
-
-#ifdef Q_OS_WIN
-
-static inline QString stringFromRvaPtr(const void *rvaPtr)
-{
- return QString::fromLocal8Bit(static_cast<const char *>(rvaPtr));
-}
-
-// Helper for reading out PE executable files: Find a section header for an RVA
-// (IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32).
-template <class ImageNtHeader>
-const IMAGE_SECTION_HEADER *findSectionHeader(DWORD rva, const ImageNtHeader *nTHeader)
-{
- const IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(nTHeader);
- const IMAGE_SECTION_HEADER *sectionEnd = section + nTHeader->FileHeader.NumberOfSections;
- for ( ; section < sectionEnd; ++section)
- if (rva >= section->VirtualAddress && rva < (section->VirtualAddress + section->Misc.VirtualSize))
- return section;
- return 0;
-}
-
-// Helper for reading out PE executable files: convert RVA to pointer (IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32).
-template <class ImageNtHeader>
-inline const void *rvaToPtr(DWORD rva, const ImageNtHeader *nTHeader, const void *imageBase)
-{
- const IMAGE_SECTION_HEADER *sectionHdr = findSectionHeader(rva, nTHeader);
- if (!sectionHdr)
- return 0;
- const DWORD delta = sectionHdr->VirtualAddress - sectionHdr->PointerToRawData;
- return static_cast<const char *>(imageBase) + rva - delta;
-}
-
-// Helper for reading out PE executable files: return word size of a IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32
-template <class ImageNtHeader>
-inline unsigned ntHeaderWordSize(const ImageNtHeader *header)
-{
- // defines IMAGE_NT_OPTIONAL_HDR32_MAGIC, IMAGE_NT_OPTIONAL_HDR64_MAGIC
- enum { imageNtOptionlHeader32Magic = 0x10b, imageNtOptionlHeader64Magic = 0x20b };
- if (header->OptionalHeader.Magic == imageNtOptionlHeader32Magic)
- return 32;
- if (header->OptionalHeader.Magic == imageNtOptionlHeader64Magic)
- return 64;
- return 0;
-}
-
-// Helper for reading out PE executable files: Retrieve the NT image header of an
-// executable via the legacy DOS header.
-static IMAGE_NT_HEADERS *getNtHeader(void *fileMemory, QString *errorMessage)
-{
- IMAGE_DOS_HEADER *dosHeader = static_cast<PIMAGE_DOS_HEADER>(fileMemory);
- // Check DOS header consistency
- if (IsBadReadPtr(dosHeader, sizeof(IMAGE_DOS_HEADER))
- || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
- *errorMessage = QString::fromLatin1("DOS header check failed.");
- return 0;
- }
- // Retrieve NT header
- char *ntHeaderC = static_cast<char *>(fileMemory) + dosHeader->e_lfanew;
- IMAGE_NT_HEADERS *ntHeaders = reinterpret_cast<IMAGE_NT_HEADERS *>(ntHeaderC);
- // check NT header consistency
- if (IsBadReadPtr(ntHeaders, sizeof(ntHeaders->Signature))
- || ntHeaders->Signature != IMAGE_NT_SIGNATURE
- || IsBadReadPtr(&ntHeaders->FileHeader, sizeof(IMAGE_FILE_HEADER))) {
- *errorMessage = QString::fromLatin1("NT header check failed.");
- return 0;
- }
- // Check magic
- if (!ntHeaderWordSize(ntHeaders)) {
- *errorMessage = QString::fromLatin1("NT header check failed; magic %1 is invalid.").
- arg(ntHeaders->OptionalHeader.Magic);
- return 0;
- }
- // Check section headers
- IMAGE_SECTION_HEADER *sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders);
- if (IsBadReadPtr(sectionHeaders, ntHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER))) {
- *errorMessage = QString::fromLatin1("NT header section header check failed.");
- return 0;
- }
- return ntHeaders;
-}
-
-// Helper for reading out PE executable files: Read out import sections from
-// IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32.
-template <class ImageNtHeader>
-inline QStringList readImportSections(const ImageNtHeader *ntHeaders, const void *base, QString *errorMessage)
-{
- // Get import directory entry RVA and read out
- const DWORD importsStartRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
- if (!importsStartRVA) {
- *errorMessage = QString::fromLatin1("Failed to find IMAGE_DIRECTORY_ENTRY_IMPORT entry.");
- return QStringList();
- }
- const IMAGE_IMPORT_DESCRIPTOR *importDesc = static_cast<const IMAGE_IMPORT_DESCRIPTOR *>(rvaToPtr(importsStartRVA, ntHeaders, base));
- if (!importDesc) {
- *errorMessage = QString::fromLatin1("Failed to find IMAGE_IMPORT_DESCRIPTOR entry.");
- return QStringList();
- }
- QStringList result;
- for ( ; importDesc->Name; ++importDesc)
- result.push_back(stringFromRvaPtr(rvaToPtr(importDesc->Name, ntHeaders, base)));
-
- // Read delay-loaded DLLs, see http://msdn.microsoft.com/en-us/magazine/cc301808.aspx .
- // Check on grAttr bit 1 whether this is the format using RVA's > VS 6
- if (const DWORD delayedImportsStartRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress) {
- const ImgDelayDescr *delayedImportDesc = static_cast<const ImgDelayDescr *>(rvaToPtr(delayedImportsStartRVA, ntHeaders, base));
- for ( ; delayedImportDesc->rvaDLLName && (delayedImportDesc->grAttrs & 1); ++delayedImportDesc)
- result.push_back(stringFromRvaPtr(rvaToPtr(delayedImportDesc->rvaDLLName, ntHeaders, base)));
- }
-
- return result;
-}
-
-// Check for MSCV runtime (MSVCP90D.dll/MSVCP90.dll, MSVCP120D.dll/MSVCP120.dll,
-// VCRUNTIME140D.DLL/VCRUNTIME140.DLL (VS2015) or msvcp120d_app.dll/msvcp120_app.dll).
-enum MsvcDebugRuntimeResult { MsvcDebugRuntime, MsvcReleaseRuntime, NoMsvcRuntime };
-
-static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &dependentLibraries)
-{
- for (const QString &lib : dependentLibraries) {
- int pos = 0;
- if (lib.startsWith(QLatin1String("MSVCR"), Qt::CaseInsensitive)
- || lib.startsWith(QLatin1String("MSVCP"), Qt::CaseInsensitive)
- || lib.startsWith(QLatin1String("VCRUNTIME"), Qt::CaseInsensitive)) {
- int lastDotPos = lib.lastIndexOf(QLatin1Char('.'));
- pos = -1 == lastDotPos ? 0 : lastDotPos - 1;
- }
-
- if (pos > 0 && lib.contains(QLatin1String("_app"), Qt::CaseInsensitive))
- pos -= 4;
-
- if (pos) {
- return lib.at(pos).toLower() == QLatin1Char('d')
- ? MsvcDebugRuntime : MsvcReleaseRuntime;
- }
- }
- return NoMsvcRuntime;
-}
-
-template <class ImageNtHeader>
-inline void determineDebugAndDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
- bool isMinGW,
- QStringList *dependentLibrariesIn,
- bool *isDebugIn, QString *errorMessage)
-{
- const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
- QStringList dependentLibraries;
- if (dependentLibrariesIn || (isDebugIn != nullptr && hasDebugEntry && !isMinGW))
- dependentLibraries = readImportSections(nth, fileMemory, errorMessage);
-
- if (dependentLibrariesIn)
- *dependentLibrariesIn = dependentLibraries;
- if (isDebugIn != nullptr) {
- if (isMinGW) {
- // Use logic that's used e.g. in objdump / pfd library
- *isDebugIn = !(nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
- } else {
- // When an MSVC debug entry is present, check whether the debug runtime
- // is actually used to detect -release / -force-debug-info builds.
- *isDebugIn = hasDebugEntry && checkMsvcDebugRuntime(dependentLibraries) != MsvcReleaseRuntime;
- }
- }
-}
-
-// Read a PE executable and determine dependent libraries, word size
-// and debug flags.
-bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
- QStringList *dependentLibrariesIn, unsigned *wordSizeIn,
- bool *isDebugIn, bool isMinGW, unsigned short *machineArchIn)
-{
- bool result = false;
- HANDLE hFile = NULL;
- HANDLE hFileMap = NULL;
- void *fileMemory = 0;
-
- if (dependentLibrariesIn)
- dependentLibrariesIn->clear();
- if (wordSizeIn)
- *wordSizeIn = 0;
- if (isDebugIn)
- *isDebugIn = false;
-
- do {
- // Create a memory mapping of the file
- hFile = CreateFile(reinterpret_cast<const WCHAR*>(peExecutableFileName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) {
- *errorMessage = QString::fromLatin1("Cannot open '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError()));
- break;
- }
-
- hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
- if (hFileMap == NULL) {
- *errorMessage = QString::fromLatin1("Cannot create file mapping of '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError()));
- break;
- }
-
- fileMemory = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
- if (!fileMemory) {
- *errorMessage = QString::fromLatin1("Cannot map '%1': %2").arg(peExecutableFileName, winErrorMessage(GetLastError()));
- break;
- }
-
- const IMAGE_NT_HEADERS *ntHeaders = getNtHeader(fileMemory, errorMessage);
- if (!ntHeaders)
- break;
-
- const unsigned wordSize = ntHeaderWordSize(ntHeaders);
- if (wordSizeIn)
- *wordSizeIn = wordSize;
- if (wordSize == 32) {
- determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders),
- fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
- } else {
- determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders),
- fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
- }
-
- if (machineArchIn)
- *machineArchIn = ntHeaders->FileHeader.Machine;
-
- result = true;
- if (optVerboseLevel > 1) {
- std::wcout << __FUNCTION__ << ": " << QDir::toNativeSeparators(peExecutableFileName)
- << ' ' << wordSize << " bit";
- if (isMinGW)
- std::wcout << ", MinGW";
- if (dependentLibrariesIn) {
- std::wcout << ", dependent libraries: ";
- if (optVerboseLevel > 2)
- std::wcout << dependentLibrariesIn->join(QLatin1Char(' '));
- else
- std::wcout << dependentLibrariesIn->size();
- }
- if (isDebugIn)
- std::wcout << (*isDebugIn ? ", debug" : ", release");
- std::wcout << '\n';
- }
- } while (false);
-
- if (fileMemory)
- UnmapViewOfFile(fileMemory);
-
- if (hFileMap != NULL)
- CloseHandle(hFileMap);
-
- if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
- CloseHandle(hFile);
-
- return result;
-}
-
-QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize)
-{
- const QString prefix = QStringLiteral("D3Dcompiler_");
- const QString suffix = QLatin1String(windowsSharedLibrarySuffix);
- // Get the DLL from Kit 8.0 onwards
- const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
- if (!kitDir.isEmpty()) {
- QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
- if (platform.testFlag(ArmBased)) {
- redistDirPath += QStringLiteral("arm");
- } else {
- redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
- }
- QDir redistDir(redistDirPath);
- if (redistDir.exists()) {
- const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + QLatin1Char('*') + suffix), QDir::Files);
- if (!files.isEmpty())
- return files.front().absoluteFilePath();
- }
- }
- QStringList candidateVersions;
- for (int i = 47 ; i >= 40 ; --i)
- candidateVersions.append(prefix + QString::number(i) + suffix);
- // Check the bin directory of the Qt SDK (in case it is shadowed by the
- // Windows system directory in PATH).
- for (const QString &candidate : qAsConst(candidateVersions)) {
- const QFileInfo fi(qtBinDir + QLatin1Char('/') + candidate);
- if (fi.isFile())
- return fi.absoluteFilePath();
- }
- // Find the latest D3D compiler DLL in path (Windows 8.1 has d3dcompiler_47).
- if (platform.testFlag(IntelBased)) {
- QString errorMessage;
- unsigned detectedWordSize;
- for (const QString &candidate : qAsConst(candidateVersions)) {
- const QString dll = findInPath(candidate);
- if (!dll.isEmpty()
- && readPeExecutable(dll, &errorMessage, 0, &detectedWordSize, 0)
- && detectedWordSize == wordSize) {
- return dll;
- }
- }
- }
- return QString();
-}
-
-#else // Q_OS_WIN
-
-bool readPeExecutable(const QString &, QString *errorMessage,
- QStringList *, unsigned *, bool *, bool, unsigned short *)
-{
- *errorMessage = QStringLiteral("Not implemented.");
- return false;
-}
-
-QString findD3dCompiler(Platform, const QString &, unsigned)
-{
- return QString();
-}
-
-#endif // !Q_OS_WIN
-
-// Search for "qt_prfxpath=xxxx" in \a path, and replace it with "qt_prfxpath=."
-bool patchQtCore(const QString &path, QString *errorMessage)
-{
- if (optVerboseLevel)
- std::wcout << "Patching " << QFileInfo(path).fileName() << "...\n";
-
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly)) {
- *errorMessage = QString::fromLatin1("Unable to patch %1: %2").arg(
- QDir::toNativeSeparators(path), file.errorString());
- return false;
- }
- const QByteArray oldContent = file.readAll();
-
- if (oldContent.isEmpty()) {
- *errorMessage = QString::fromLatin1("Unable to patch %1: Could not read file content").arg(
- QDir::toNativeSeparators(path));
- return false;
- }
- file.close();
-
- QByteArray content = oldContent;
-
- QByteArray prfxpath("qt_prfxpath=");
- int startPos = content.indexOf(prfxpath);
- if (startPos == -1) {
- *errorMessage = QString::fromLatin1(
- "Unable to patch %1: Could not locate pattern \"qt_prfxpath=\"").arg(
- QDir::toNativeSeparators(path));
- return false;
- }
- startPos += prfxpath.length();
- int endPos = content.indexOf(char(0), startPos);
- if (endPos == -1) {
- *errorMessage = QString::fromLatin1("Unable to patch %1: Internal error").arg(
- QDir::toNativeSeparators(path));
- return false;
- }
-
- QByteArray replacement = QByteArray(endPos - startPos, char(0));
- replacement[0] = '.';
- content.replace(startPos, endPos - startPos, replacement);
- if (content == oldContent)
- return true;
-
- if (!file.open(QIODevice::WriteOnly)
- || (file.write(content) != content.size())) {
- *errorMessage = QString::fromLatin1("Unable to patch %1: Could not write to file: %2").arg(
- QDir::toNativeSeparators(path), file.errorString());
- return false;
- }
- return true;
-}
-
-#ifdef Q_OS_WIN
-QString getArchString(unsigned short machineArch)
-{
- switch (machineArch) {
- case IMAGE_FILE_MACHINE_I386:
- return QStringLiteral("x86");
- case IMAGE_FILE_MACHINE_ARM:
- return QStringLiteral("arm");
- case IMAGE_FILE_MACHINE_AMD64:
- return QStringLiteral("x64");
- case IMAGE_FILE_MACHINE_ARM64:
- return QStringLiteral("arm64");
- default:
- break;
- }
- return QString();
-}
-#endif // Q_OS_WIN
-
-QT_END_NAMESPACE
diff --git a/src/shared/winutils/utils.h b/src/shared/winutils/utils.h
deleted file mode 100644
index 0fe3a6948..000000000
--- a/src/shared/winutils/utils.h
+++ /dev/null
@@ -1,404 +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$
-**
-****************************************************************************/
-
-#ifndef UTILS_H
-#define UTILS_H
-
-#include <QStringList>
-#include <QMap>
-#include <QtCore/QFile>
-#include <QtCore/QDir>
-#include <QtCore/QDateTime>
-#include <QtCore/QJsonArray>
-#include <QtCore/QJsonObject>
-#include <QtCore/QJsonDocument>
-
-#include <iostream>
-
-QT_BEGIN_NAMESPACE
-
-enum PlatformFlag {
- // OS
- WindowsBased = 0x00001,
- UnixBased = 0x00002,
- // CPU
- IntelBased = 0x00010,
- ArmBased = 0x00020,
- // Compiler
- Msvc = 0x00100,
- MinGW = 0x00200,
- ClangMsvc = 0x00400,
- ClangMinGW = 0x00800,
- // Platforms
- WindowsDesktopMsvc = WindowsBased + IntelBased + Msvc,
- WindowsDesktopMinGW = WindowsBased + IntelBased + MinGW,
- WindowsDesktopClangMsvc = WindowsBased + IntelBased + ClangMsvc,
- WindowsDesktopClangMinGW = WindowsBased + IntelBased + ClangMinGW,
- Unix = UnixBased,
- UnknownPlatform
-};
-
-Q_DECLARE_FLAGS(Platform, PlatformFlag)
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(Platform)
-
-inline bool platformHasDebugSuffix(Platform p) // Uses 'd' debug suffix
-{
- return p.testFlag(Msvc) || p.testFlag(ClangMsvc);
-}
-
-enum ListOption {
- ListNone = 0,
- ListSource,
- ListTarget,
- ListRelative,
- ListMapping
-};
-
-inline std::wostream &operator<<(std::wostream &str, const QString &s)
-{
-#ifdef Q_OS_WIN
- str << reinterpret_cast<const wchar_t *>(s.utf16());
-#else
- str << s.toStdWString();
-#endif
- return str;
-}
-
-// Container class for JSON output
-class JsonOutput
-{
- using SourceTargetMapping = QPair<QString, QString>;
- using SourceTargetMappings = QList<SourceTargetMapping>;
-
-public:
- void addFile(const QString &source, const QString &target)
- {
- m_files.append(SourceTargetMapping(source, target));
- }
-
- void removeTargetDirectory(const QString &targetDirectory)
- {
- for (int i = m_files.size() - 1; i >= 0; --i) {
- if (m_files.at(i).second == targetDirectory)
- m_files.removeAt(i);
- }
- }
-
- QByteArray toJson() const
- {
- QJsonObject document;
- QJsonArray files;
- for (const SourceTargetMapping &mapping : m_files) {
- QJsonObject object;
- object.insert(QStringLiteral("source"), QDir::toNativeSeparators(mapping.first));
- object.insert(QStringLiteral("target"), QDir::toNativeSeparators(mapping.second));
- files.append(object);
- }
- document.insert(QStringLiteral("files"), files);
- return QJsonDocument(document).toJson();
- }
- QByteArray toList(ListOption option, const QDir &base) const
- {
- QByteArray list;
- for (const SourceTargetMapping &mapping : m_files) {
- const QString source = QDir::toNativeSeparators(mapping.first);
- const QString fileName = QFileInfo(mapping.first).fileName();
- const QString target = QDir::toNativeSeparators(mapping.second) + QDir::separator() + fileName;
- switch (option) {
- case ListNone:
- break;
- case ListSource:
- list += source.toUtf8() + '\n';
- break;
- case ListTarget:
- list += target.toUtf8() + '\n';
- break;
- case ListRelative:
- list += QDir::toNativeSeparators(base.relativeFilePath(target)).toUtf8() + '\n';
- break;
- case ListMapping:
- list += '"' + source.toUtf8() + "\" \"" + QDir::toNativeSeparators(base.relativeFilePath(target)).toUtf8() + "\"\n";
- break;
- }
- }
- return list;
- }
-private:
- SourceTargetMappings m_files;
-};
-
-#ifdef Q_OS_WIN
-QString normalizeFileName(const QString &name);
-QString winErrorMessage(unsigned long error);
-QString findSdkTool(const QString &tool);
-#else // !Q_OS_WIN
-inline QString normalizeFileName(const QString &name) { return name; }
-#endif // !Q_OS_WIN
-
-static const char windowsSharedLibrarySuffix[] = ".dll";
-static const char unixSharedLibrarySuffix[] = ".so";
-
-inline QString sharedLibrarySuffix(Platform platform) { return QLatin1String((platform & WindowsBased) ? windowsSharedLibrarySuffix : unixSharedLibrarySuffix); }
-bool isBuildDirectory(Platform platform, const QString &dirName);
-
-bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage);
-bool createDirectory(const QString &directory, QString *errorMessage);
-QString findInPath(const QString &file);
-
-extern const char *qmakeInfixKey; // Fake key containing the libinfix
-
-QMap<QString, QString> queryQtPaths(const QString &qmakeBinary, QString *errorMessage);
-
-enum DebugMatchMode {
- MatchDebug,
- MatchRelease,
- MatchDebugOrRelease
-};
-
-QStringList findSharedLibraries(const QDir &directory, Platform platform,
- DebugMatchMode debugMatchMode,
- const QString &prefix = QString());
-
-bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
- const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage);
-bool runProcess(const QString &binary, const QStringList &args,
- const QString &workingDirectory = QString(),
- unsigned long *exitCode = 0, QByteArray *stdOut = 0, QByteArray *stdErr = 0,
- QString *errorMessage = 0);
-
-bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
- QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
- bool *isDebug = 0, bool isMinGW = false, unsigned short *machineArch = nullptr);
-bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage,
- QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
- bool *isDebug = 0);
-
-inline bool readExecutable(const QString &executableFileName, Platform platform,
- QString *errorMessage, QStringList *dependentLibraries = 0,
- unsigned *wordSize = 0, bool *isDebug = 0, unsigned short *machineArch = nullptr)
-{
- return platform == Unix ?
- readElfExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug) :
- readPeExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug,
- (platform == WindowsDesktopMinGW), machineArch);
-}
-
-#ifdef Q_OS_WIN
-# if !defined(IMAGE_FILE_MACHINE_ARM64)
-# define IMAGE_FILE_MACHINE_ARM64 0xAA64
-# endif
-QString getArchString (unsigned short machineArch);
-#endif // Q_OS_WIN
-
-// Return dependent modules of executable files.
-
-inline QStringList findDependentLibraries(const QString &executableFileName, Platform platform, QString *errorMessage)
-{
- QStringList result;
- readExecutable(executableFileName, platform, errorMessage, &result);
- return result;
-}
-
-QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize);
-
-bool patchQtCore(const QString &path, QString *errorMessage);
-
-extern int optVerboseLevel;
-
-// Recursively update a file or directory, matching DirectoryFileEntryFunction against the QDir
-// to obtain the files.
-enum UpdateFileFlag {
- ForceUpdateFile = 0x1,
- SkipUpdateFile = 0x2,
- RemoveEmptyQmlDirectories = 0x4,
- SkipQmlDesignerSpecificsDirectories = 0x8
-};
-
-template <class DirectoryFileEntryFunction>
-bool updateFile(const QString &sourceFileName,
- DirectoryFileEntryFunction directoryFileEntryFunction,
- const QString &targetDirectory,
- unsigned flags,
- JsonOutput *json,
- QString *errorMessage)
-{
- const QFileInfo sourceFileInfo(sourceFileName);
- const QString targetFileName = targetDirectory + QLatin1Char('/') + sourceFileInfo.fileName();
- if (optVerboseLevel > 1)
- std::wcout << "Checking " << sourceFileName << ", " << targetFileName << '\n';
-
- if (!sourceFileInfo.exists()) {
- *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName));
- return false;
- }
-
- const QFileInfo targetFileInfo(targetFileName);
-
- if (sourceFileInfo.isSymLink()) {
- const QString sourcePath = sourceFileInfo.symLinkTarget();
- const QString relativeSource = QDir(sourceFileInfo.absolutePath()).relativeFilePath(sourcePath);
- if (relativeSource.contains(QLatin1Char('/'))) {
- *errorMessage = QString::fromLatin1("Symbolic links across directories are not supported (%1).")
- .arg(QDir::toNativeSeparators(sourceFileName));
- return false;
- }
-
- // Update the linked-to file
- if (!updateFile(sourcePath, directoryFileEntryFunction, targetDirectory, flags, json, errorMessage))
- return false;
-
- if (targetFileInfo.exists()) {
- if (!targetFileInfo.isSymLink()) {
- *errorMessage = QString::fromLatin1("%1 already exists and is not a symbolic link.")
- .arg(QDir::toNativeSeparators(targetFileName));
- return false;
- } // Not a symlink
- const QString relativeTarget = QDir(targetFileInfo.absolutePath()).relativeFilePath(targetFileInfo.symLinkTarget());
- if (relativeSource == relativeTarget) // Exists and points to same entry: happy.
- return true;
- QFile existingTargetFile(targetFileName);
- if (!(flags & SkipUpdateFile) && !existingTargetFile.remove()) {
- *errorMessage = QString::fromLatin1("Cannot remove existing symbolic link %1: %2")
- .arg(QDir::toNativeSeparators(targetFileName), existingTargetFile.errorString());
- return false;
- }
- } // target symbolic link exists
- return createSymbolicLink(QFileInfo(targetDirectory + QLatin1Char('/') + relativeSource), sourceFileInfo.fileName(), errorMessage);
- } // Source is symbolic link
-
- if (sourceFileInfo.isDir()) {
- if ((flags & SkipQmlDesignerSpecificsDirectories) && sourceFileInfo.fileName() == QLatin1String("designer")) {
- if (optVerboseLevel)
- std::wcout << "Skipping " << QDir::toNativeSeparators(sourceFileName) << ".\n";
- return true;
- }
- bool created = false;
- if (targetFileInfo.exists()) {
- if (!targetFileInfo.isDir()) {
- *errorMessage = QString::fromLatin1("%1 already exists and is not a directory.")
- .arg(QDir::toNativeSeparators(targetFileName));
- return false;
- } // Not a directory.
- } else { // exists.
- QDir d(targetDirectory);
- if (optVerboseLevel)
- std::wcout << "Creating " << targetFileName << ".\n";
- if (!(flags & SkipUpdateFile)) {
- created = d.mkdir(sourceFileInfo.fileName());
- if (!created) {
- *errorMessage = QString::fromLatin1("Cannot create directory %1 under %2.")
- .arg(sourceFileInfo.fileName(), QDir::toNativeSeparators(targetDirectory));
- return false;
- }
- }
- }
- // Recurse into directory
- QDir dir(sourceFileName);
-
- const QStringList allEntries = directoryFileEntryFunction(dir) + dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QString &entry : allEntries)
- if (!updateFile(sourceFileName + QLatin1Char('/') + entry, directoryFileEntryFunction, targetFileName, flags, json, errorMessage))
- return false;
- // Remove empty directories, for example QML import folders for which the filter did not match.
- if (created && (flags & RemoveEmptyQmlDirectories)) {
- QDir d(targetFileName);
- const QStringList entries = d.entryList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
- if (entries.isEmpty() || (entries.size() == 1 && entries.first() == QLatin1String("qmldir"))) {
- if (!d.removeRecursively()) {
- *errorMessage = QString::fromLatin1("Cannot remove empty directory %1.")
- .arg(QDir::toNativeSeparators(targetFileName));
- return false;
- }
- if (json)
- json->removeTargetDirectory(targetFileName);
- }
- }
- return true;
- } // Source is directory.
-
- if (targetFileInfo.exists()) {
- if (!(flags & ForceUpdateFile)
- && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) {
- if (optVerboseLevel)
- std::wcout << sourceFileInfo.fileName() << " is up to date.\n";
- if (json)
- json->addFile(sourceFileName, targetDirectory);
- return true;
- }
- QFile targetFile(targetFileName);
- if (!(flags & SkipUpdateFile) && !targetFile.remove()) {
- *errorMessage = QString::fromLatin1("Cannot remove existing file %1: %2")
- .arg(QDir::toNativeSeparators(targetFileName), targetFile.errorString());
- return false;
- }
- } // target exists
- QFile file(sourceFileName);
- if (optVerboseLevel)
- std::wcout << "Updating " << sourceFileInfo.fileName() << ".\n";
- if (!(flags & SkipUpdateFile)) {
- if (!file.copy(targetFileName)) {
- *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3")
- .arg(QDir::toNativeSeparators(sourceFileName),
- QDir::toNativeSeparators(targetFileName),
- file.errorString());
- return false;
- }
- if (!(file.permissions() & QFile::WriteUser)) { // QTBUG-40152, clear inherited read-only attribute
- QFile targetFile(targetFileName);
- if (!targetFile.setPermissions(targetFile.permissions() | QFile::WriteUser)) {
- *errorMessage = QString::fromLatin1("Cannot set write permission on %1: %2")
- .arg(QDir::toNativeSeparators(targetFileName), file.errorString());
- return false;
- }
- } // Check permissions
- } // !SkipUpdateFile
- if (json)
- json->addFile(sourceFileName, targetDirectory);
- return true;
-}
-
-// Base class to filter files by name filters functions to be passed to updateFile().
-class NameFilterFileEntryFunction {
-public:
- explicit NameFilterFileEntryFunction(const QStringList &nameFilters) : m_nameFilters(nameFilters) {}
- QStringList operator()(const QDir &dir) const { return dir.entryList(m_nameFilters, QDir::Files); }
-
-private:
- const QStringList m_nameFilters;
-};
-
-// Convenience for all files.
-inline bool updateFile(const QString &sourceFileName, const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage)
-{
- return updateFile(sourceFileName, NameFilterFileEntryFunction(QStringList()), targetDirectory, flags, json, errorMessage);
-}
-
-QT_END_NAMESPACE
-
-#endif // UTILS_H
diff --git a/src/windeployqt/CMakeLists.txt b/src/windeployqt/CMakeLists.txt
deleted file mode 100644
index bc90d20ef..000000000
--- a/src/windeployqt/CMakeLists.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-# Generated from windeployqt.pro.
-
-#####################################################################
-## windeployqt Tool:
-#####################################################################
-
-qt_get_tool_target_name(target_name windeployqt)
-qt_internal_add_tool(${target_name}
- # BOOTSTRAP # special case remove
- TOOLS_TARGET Tools # special case
- TARGET_DESCRIPTION "Qt Windows Deployment Tool"
- SOURCES
- ../shared/winutils/elfreader.cpp ../shared/winutils/elfreader.h
- ../shared/winutils/qmlutils.cpp ../shared/winutils/qmlutils.h
- ../shared/winutils/utils.cpp ../shared/winutils/utils.h
- main.cpp
- DEFINES
- QT_NO_CAST_FROM_ASCII
- QT_NO_CAST_TO_ASCII
- QT_NO_FOREACH
- INCLUDE_DIRECTORIES
- ../shared/winutils
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::Core # special case
-)
-qt_internal_return_unless_building_tools()
-
-#### Keys ignored in scope 1:.:.:windeployqt.pro:<TRUE>:
-# QMAKE_TARGET_DESCRIPTION = "Qt Windows Deployment Tool"
-# QT_FOR_CONFIG = "tools-private"
-# _OPTION = "host_build"
-# _REQUIREMENTS = "qtConfig(windeployqt)"
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(${target_name} CONDITION WIN32
- PUBLIC_LIBRARIES
- shlwapi
-)
-
-qt_internal_extend_target(${target_name} CONDITION QT_FEATURE_relocatable
- DEFINES
- QT_RELOCATABLE
-)
diff --git a/src/windeployqt/main.cpp b/src/windeployqt/main.cpp
deleted file mode 100644
index 27b57ea9a..000000000
--- a/src/windeployqt/main.cpp
+++ /dev/null
@@ -1,1723 +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,
- QtOpenGLWidgetsModule = 0x0000000000004000,
- QtPositioningModule = 0x0000000000008000,
- QtPrintSupportModule = 0x0000000000010000,
- QtQmlModule = 0x0000000000020000,
- QtQuickModule = 0x0000000000040000,
- QtQuickParticlesModule = 0x0000000000080000,
- QtScriptModule = 0x0000000000100000,
- QtScriptToolsModule = 0x0000000000200000,
- QtSensorsModule = 0x0000000000400000,
- QtSerialPortModule = 0x0000000000800000,
- QtSqlModule = 0x0000000001000000,
- QtSvgModule = 0x0000000002000000,
- QtSvgWidgetsModule = 0x0000000004000000,
- QtTestModule = 0x0000000008000000,
- QtWidgetsModule = 0x0000000010000000,
- QtWinExtrasModule = 0x0000000020000000,
- QtXmlModule = 0x0000000040000000,
- QtQuickWidgetsModule = 0x0000000100000000,
- QtWebSocketsModule = 0x0000000200000000,
- 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,
- QtShaderToolsModule = 0x0010000000000000
-};
-
-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 },
- { 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 },
- { QtOpenGLWidgetsModule, "openglwidgets", "Qt6OpenGLWidgets", 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 },
- { QtSvgWidgetsModule, "svgwidgets", "Qt6SvgWidgets", nullptr },
- { QtTestModule, "test", "Qt6Test", "qtbase" },
- { QtWebSocketsModule, "websockets", "Qt6WebSockets", nullptr },
- { QtWidgetsModule, "widgets", "Qt6Widgets", "qtbase" },
- { QtWinExtrasModule, "winextras", "Qt6WinExtras", nullptr },
- { QtXmlModule, "xml", "Qt6Xml", "qtbase" },
- { 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 },
- { QtShaderToolsModule, "shadertools", "Qt6ShaderTools", nullptr }
-};
-
-enum QtPlugin {
- QtVirtualKeyboardPlugin = 0x1
-};
-
-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;
-}
-
-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 qtpathsBinary;
- 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 to be deployed from folder, ignore pre-existing web engine process.
-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(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\n"
- "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. "
- "Deprecated, use qtpaths instead."),
- QStringLiteral("path"));
- parser->addOption(qmakeOption);
-
- QCommandLineOption qtpathsOption(
- QStringLiteral("qtpaths"),
- QStringLiteral("Use specified qtpaths.exe instead of qtpaths.exe from PATH."),
- QStringLiteral("path"));
- parser->addOption(qtpathsOption);
-
- 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 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);
-
- // default to deployment of compiler runtime for windows desktop configurations
- if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc
- || parser->isSet(compilerRunTimeOption))
- options->compilerRunTime = true;
- 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;
-
- 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) && parser->isSet(qtpathsOption)) {
- *errorMessage = QStringLiteral("-qmake and -qtpaths are mutually exclusive.");
- return CommandLineParseError;
- }
-
- if (parser->isSet(qmakeOption) && optVerboseLevel >= 1)
- std::wcerr << "Warning: -qmake option is deprecated. Use -qpaths instead.\n";
-
- if (parser->isSet(qtpathsOption) || parser->isSet(qmakeOption)) {
- const QString qtpathsArg = parser->isSet(qtpathsOption) ? parser->value(qtpathsOption)
- : parser->value(qmakeOption);
-
- const QString qtpathsBinary = QDir::cleanPath(qtpathsArg);
- const QFileInfo fi(qtpathsBinary);
- if (!fi.exists()) {
- *errorMessage = msgFileDoesNotExist(qtpathsBinary);
- return CommandLineParseError;
- }
-
- if (!fi.isExecutable()) {
- *errorMessage = QLatin1Char('"') + QDir::toNativeSeparators(qtpathsBinary)
- + QStringLiteral("\" is not an executable.");
- return CommandLineParseError;
- }
- options->qtpathsBinary = qtpathsBinary;
- }
-
- 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},
-#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
- {"gamepads", QtGamePadModule},
-#endif
- {"accessible", QtGuiModule},
- {"iconengines", QtGuiModule},
- {"imageformats", QtGuiModule},
- {"platforms", QtGuiModule},
- {"platforminputcontexts", QtGuiModule},
- {"virtualkeyboard", QtGuiModule},
- {"geoservices", QtLocationModule},
- {"audio", QtMultimediaModule},
- {"mediaservice", QtMultimediaModule},
- {"playlistformats", QtMultimediaModule},
- {"networkaccess", QtNetworkModule},
- {"networkinformation", QtNetworkModule},
- {"tls", QtNetworkModule},
- {"position", QtPositioningModule},
- {"printsupport", QtPrintSupportModule},
- {"scenegraph", QtQuickModule},
- {"qmltooling", QtQuickModule | QtQmlToolingModule},
- {"sensors", QtSensorsModule},
- {"sensorgestures", QtSensorsModule},
- {"canbus", QtSerialBusModule},
- {"sqldrivers", QtSqlModule},
-#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
- {"texttospeech", QtTextToSpeechModule},
-#endif
- {"qtwebengine", QtWebEngineModule | QtWebEngineCoreModule | QtWebEngineWidgetsModule},
- {"styles", QtWidgetsModule},
- {"sceneparsers", Qt3DRendererModule},
- {"renderers", Qt3DRendererModule | QtShaderToolsModule},
- {"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/MSVC"));
- if (!QFileInfo(vcRedistDirName).isDir()) {
- std::wcerr << "Warning: Cannot find Visual Studio redist directory, "
- << QDir::toNativeSeparators(vcRedistDirName).toStdWString() << ".\n";
- return QString();
- }
- // Look in reverse order for folder containing the debug redist folder
- const QFileInfoList subDirs =
- QDir(vcRedistDirName)
- .entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
- for (const QFileInfo &f : subDirs) {
- QString path = f.absoluteFilePath();
- if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
- return path;
- path += QStringLiteral("/onecore");
- if (QFileInfo(path + slash + vcDebugRedistDir()).isDir())
- return path;
- }
- std::wcerr << "Warning: Cannot find Visual Studio redist directory under "
- << QDir::toNativeSeparators(vcRedistDirName).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> &qtpathsVariables)
-{
- const QString versionString = qtpathsVariables.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> &qtpathsVariables,
- QString *errorMessage)
-{
- DeployResult result;
-
- const QChar slash = QLatin1Char('/');
-
- const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
- const QString libraryLocation = options.platform == Unix
- ? qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBS"))
- : qtBinDir;
- const QString infix = qtpathsVariables.value(QLatin1String(qmakeInfixKey));
- const int version = qtVersion(qtpathsVariables);
- 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';
- QString icuLib = QStringLiteral("icudt") + icuVersion
- + QLatin1String(windowsSharedLibrarySuffix);;
- // Some packages contain debug dlls of ICU libraries even though it's a C
- // library and the official packages do not differentiate (QTBUG-87677)
- if (result.isDebug) {
- const QString icuLibCandidate = QStringLiteral("icudtd") + icuVersion
- + QLatin1String(windowsSharedLibrarySuffix);
- if (!findInPath(icuLibCandidate).isEmpty()) {
- icuLib = icuLibCandidate;
- }
- }
- icuLibs.push_back(icuLib);
- }
- 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 << qtpathsVariables.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, qtpathsVariables.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 qt6CoreName = 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 =
- qtpathsVariables.value(QStringLiteral("QT_INSTALL_IMPORTS"));
- const QmlDirectoryFileEntryFunction qmlFileEntryFunction(options.platform, debugMatchMode, options.deployPdb ? QmlDirectoryFileEntryFunction::DeployPdb : 0);
- QStringList quick1Imports(QStringLiteral("Qt"));
- 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(qtpathsVariables.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> &qtpathsVariables, 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 = qtpathsVariables.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, qtpathsVariables, errorMessage);
-}
-
-static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
- 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(qtpathsVariables, webEngineProcessName, options, errorMessage))
- return false;
- const QString resourcesSubDir = QStringLiteral("/resources");
- const QString resourcesSourceDir = qtpathsVariables.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(qtpathsVariables.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);
-}
-
-QT_END_NAMESPACE
-
-QT_USE_NAMESPACE
-
-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> qtpathsVariables =
- queryQtPaths(options.qtpathsBinary, &errorMessage);
- const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
- options.platform = platformFromMkSpec(xSpec);
-
- if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
- || !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
- std::wcerr << "Unable to query qtpaths: " << 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;
- }
-
- const DeployResult result = deploy(options, qtpathsVariables, &errorMessage);
- if (!result) {
- std::wcerr << errorMessage << '\n';
- return 1;
- }
-
- if (result.deployedQtLibraries & QtWebEngineCoreModule) {
- if (!deployWebEngineCore(qtpathsVariables, 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;
-}
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 10a33b85c..d800c6fe4 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -21,9 +21,3 @@ endif()
# add_subdirectory(cmake/linguist)
# endif()
# special case end
-if(QT_FEATURE_process AND WIN32 AND NOT CMAKE_CROSSCOMPILING)
- add_subdirectory(windeployqt)
-endif()
-if(MACOS AND QT_FEATURE_process)
- add_subdirectory(macdeployqt)
-endif()
diff --git a/tests/auto/macdeployqt/CMakeLists.txt b/tests/auto/macdeployqt/CMakeLists.txt
deleted file mode 100644
index 073c2a9e7..000000000
--- a/tests/auto/macdeployqt/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# Generated from macdeployqt.pro.
-
-#####################################################################
-## tst_macdeployqt Test:
-#####################################################################
-
-qt_internal_add_test(tst_macdeployqt
- SOURCES
- tst_macdeployqt.cpp
-)
diff --git a/tests/auto/macdeployqt/source_basicapp/basicapp.pro b/tests/auto/macdeployqt/source_basicapp/basicapp.pro
deleted file mode 100644
index bba41b9c1..000000000
--- a/tests/auto/macdeployqt/source_basicapp/basicapp.pro
+++ /dev/null
@@ -1 +0,0 @@
-SOURCES = main.cpp
diff --git a/tests/auto/macdeployqt/source_basicapp/main.cpp b/tests/auto/macdeployqt/source_basicapp/main.cpp
deleted file mode 100644
index 093a882f3..000000000
--- a/tests/auto/macdeployqt/source_basicapp/main.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QGuiApplication>
-#include <QRasterWindow>
-#include <QScreen>
-#include <QTimer>
-
-// Simple test application just to verify that it comes up properly
-
-int main(int argc, char ** argv)
-{
- QGuiApplication app(argc, argv);
- QRasterWindow w;
- w.setTitle("macdeployqt test application");
- w.show();
- QTimer::singleShot(200, &w, &QCoreApplication::quit);
- return app.exec();
-}
diff --git a/tests/auto/macdeployqt/source_plugin_sqlite/main.cpp b/tests/auto/macdeployqt/source_plugin_sqlite/main.cpp
deleted file mode 100644
index 31e2e8117..000000000
--- a/tests/auto/macdeployqt/source_plugin_sqlite/main.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QtSql>
-
-int main(int argc, char ** argv)
-{
- QCoreApplication app(argc, argv);
- QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
- return db.isValid() ? 0 : 1;
-}
diff --git a/tests/auto/macdeployqt/source_plugin_sqlite/plugin_sqlite.pro b/tests/auto/macdeployqt/source_plugin_sqlite/plugin_sqlite.pro
deleted file mode 100644
index e8183d3ce..000000000
--- a/tests/auto/macdeployqt/source_plugin_sqlite/plugin_sqlite.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-SOURCES = main.cpp
-QT += sql
diff --git a/tests/auto/macdeployqt/source_plugin_tls/main.cpp b/tests/auto/macdeployqt/source_plugin_tls/main.cpp
deleted file mode 100644
index 7d1070b2c..000000000
--- a/tests/auto/macdeployqt/source_plugin_tls/main.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QtNetwork>
-
-int main(int argc, char ** argv)
-{
- QCoreApplication app(argc, argv);
- return QSslSocket::supportsSsl() ? 0 : 1;
-}
diff --git a/tests/auto/macdeployqt/source_plugin_tls/plugin_tls.pro b/tests/auto/macdeployqt/source_plugin_tls/plugin_tls.pro
deleted file mode 100644
index 23954f594..000000000
--- a/tests/auto/macdeployqt/source_plugin_tls/plugin_tls.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-SOURCES = main.cpp
-QT += network
diff --git a/tests/auto/macdeployqt/tst_macdeployqt.cpp b/tests/auto/macdeployqt/tst_macdeployqt.cpp
deleted file mode 100644
index 892202557..000000000
--- a/tests/auto/macdeployqt/tst_macdeployqt.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QtCore>
-#include <QtTest>
-
-bool g_testDirectoryBuild = false; // toggle to keep build output for debugging.
-QTemporaryDir *g_temporaryDirectory;
-QString g_macdeployqtBinary;
-QString g_qmakeBinary;
-QString g_makeBinary;
-QString g_installNameToolBinary;
-
-#if QT_CONFIG(process)
-
-static const QString msgProcessError(const QProcess &process, const QString &what)
-{
- QString result;
- QTextStream(&result) << what << ": \"" << process.program() << ' '
- << process.arguments().join(QLatin1Char(' ')) << "\": " << process.errorString();
- return result;
-}
-
-static bool runProcess(const QString &binary,
- const QStringList &arguments,
- QString *errorMessage,
- const QString &workingDir = QString(),
- const QProcessEnvironment &env = QProcessEnvironment(),
- int timeOut = 10000,
- QByteArray *stdOut = nullptr, QByteArray *stdErr = nullptr)
-{
- QProcess process;
- if (!env.isEmpty())
- process.setProcessEnvironment(env);
- if (!workingDir.isEmpty())
- process.setWorkingDirectory(workingDir);
- process.start(binary, arguments, QIODevice::ReadOnly);
- if (!process.waitForStarted()) {
- *errorMessage = msgProcessError(process, "Failed to start");
- return false;
- }
- if (!process.waitForFinished(timeOut)) {
- *errorMessage = msgProcessError(process, "Timed out");
- process.terminate();
- if (!process.waitForFinished(300))
- process.kill();
- return false;
- }
- if (stdOut)
- *stdOut = process.readAllStandardOutput();
- if (stdErr)
- *stdErr= process.readAllStandardError();
- if (process.exitStatus() != QProcess::NormalExit) {
- *errorMessage = msgProcessError(process, "Crashed");
- return false;
- }
- if (process.exitCode() != QProcess::NormalExit) {
- *errorMessage = msgProcessError(process, "Exit code " + QString::number(process.exitCode()));
- return false;
- }
- return true;
-}
-
-#else
-
-static bool runProcess(const QString &binary,
- const QStringList &arguments,
- QString *arguments,
- const QString &workingDir = QString(),
- const QProcessEnvironment &env = QProcessEnvironment(),
- int timeOut = 5000,
- QByteArray *stdOut = Q_NULLPTR, QByteArray *stdErr = Q_NULLPTR)
-{
- Q_UNUSED(binary);
- Q_UNUSED(arguments);
- Q_UNUSED(arguments);
- Q_UNUSED(workingDir);
- Q_UNUSED(env);
- Q_UNUSED(timeOut);
- Q_UNUSED(stdOut);
- Q_UNUSED(stdErr);
- return false;
-}
-
-#endif
-
-QString sourcePath(const QString &name)
-{
- return "source_" + name;
-}
-
-QString buildPath(const QString &name)
-{
- if (g_testDirectoryBuild)
- return "build_" + name;
- return g_temporaryDirectory->path() + "/build_" + name;
-}
-
-bool qmake(const QString &source, const QString &destination, QString *errorMessage)
-{
- QStringList args = QStringList() << source;
- return runProcess(g_qmakeBinary, args, errorMessage, destination);
-}
-
-bool make(const QString &destination, QString *errorMessage)
-{
- QStringList args;
- return runProcess(g_makeBinary, args, errorMessage, destination,
- {}, 60000);
-}
-
-void build(const QString &name)
-{
- // Build the app or framework according to the convention used
- // by this test:
- // source_name (source code)
- // build_name (build artifacts)
-
- QString source = sourcePath(name);
- QString build = buildPath(name);
- QString profile = name + ".pro";
-
- QString sourcePath = QFINDTESTDATA(source);
- QVERIFY(!sourcePath.isEmpty());
-
- // Clear/set up build dir
- QString buildPath = build;
- QVERIFY(QDir(buildPath).removeRecursively());
- QVERIFY(QDir().mkdir(buildPath));
- QVERIFY(QDir(buildPath).exists());
-
- // Build application
- QString sourceProFile = QDir(sourcePath).canonicalPath() + '/' + profile;
- QString errorMessage;
- QVERIFY2(qmake(sourceProFile, buildPath, &errorMessage), qPrintable(errorMessage));
- QVERIFY2(make(buildPath, &errorMessage), qPrintable(errorMessage));
-}
-
-bool changeInstallName(const QString &path, const QString &binary, const QString &from, const QString &to)
-{
- QStringList args = QStringList() << binary << "-change" << from << to;
- QString errorMessage;
- return runProcess(g_installNameToolBinary, args, &errorMessage, path);
-}
-
-bool deploy(const QString &name, const QStringList &options, QString *errorMessage)
-{
- QString bundle = name + ".app";
- QString path = buildPath(name);
- QStringList args = QStringList() << bundle << options;
- return runProcess(g_macdeployqtBinary, args, errorMessage, path);
-}
-
-bool debugDeploy(const QString &name, const QStringList &options, QString *errorMessage)
-{
- QString bundle = name + ".app";
- QString path = buildPath(name);
- QStringList args = QStringList() << bundle << options << "-verbose=3";
- QByteArray stdOut;
- QByteArray stdErr;
- bool exitOK = runProcess(g_macdeployqtBinary, args, errorMessage, path, QProcessEnvironment(),
- 10000, &stdOut, &stdErr);
-
- qDebug() << "macdeployqt exit OK" << exitOK;
- qDebug() << qPrintable(stdOut);
- qDebug() << qPrintable(stdErr);
-
- return exitOK;
-}
-
-bool run(const QString &name, QString *errorMessage)
-{
- QString path = buildPath(name);
- QStringList args;
- QString binary = name + ".app/Contents/MacOS/" + name;
- return runProcess(binary, args, errorMessage, path);
-}
-
-bool runPrintLibraries(const QString &name, QString *errorMessage, QByteArray *stdErr)
-{
- QString binary = name + ".app/Contents/MacOS/" + name;
- QString path = buildPath(name);
- QStringList args;
- QProcessEnvironment env = QProcessEnvironment();
- env.insert("DYLD_PRINT_LIBRARIES", "true");
- QByteArray stdOut;
- return runProcess(binary, args, errorMessage, path, env, 5000, &stdOut, stdErr);
-}
-
-void runVerifyDeployment(const QString &name)
-{
- QString errorMessage;
- // Verify that the application runs after deployment and that it loads binaries from
- // the application bundle only.
- QByteArray libraries;
- QVERIFY2(runPrintLibraries(name, &errorMessage, &libraries), qPrintable(errorMessage));
- const QList<QString> parts = QString::fromLocal8Bit(libraries).split("dyld: loaded:");
- const QString qtPath = QLibraryInfo::path(QLibraryInfo::PrefixPath);
- // Let assume Qt is not installed in system
- foreach (QString part, parts) {
- part = part.trimmed();
- if (part.isEmpty())
- continue;
- QVERIFY(!parts.startsWith(qtPath));
- }
-}
-
-class tst_macdeployqt : public QObject
-{
- Q_OBJECT
-private slots:
- void initTestCase();
- void cleanupTestCase();
- void basicapp();
- void plugins_data();
- void plugins();
-};
-
-void tst_macdeployqt::initTestCase()
-{
-#ifdef QT_NO_PROCESS
- QSKIP("This test requires QProcess support");
-#endif
-
- // Set up test-global unique temporary directory
- g_temporaryDirectory = new QTemporaryDir();
- QVERIFY(g_temporaryDirectory->isValid());
-
- // Locate build and deployment tools
- g_macdeployqtBinary = QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/macdeployqt";
- QVERIFY(!g_macdeployqtBinary.isEmpty());
- g_qmakeBinary = QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qmake";
- QVERIFY(!g_qmakeBinary.isEmpty());
- g_makeBinary = QStandardPaths::findExecutable("make");
- QVERIFY(!g_makeBinary.isEmpty());
- g_installNameToolBinary = QStandardPaths::findExecutable("install_name_tool");
- QVERIFY(!g_installNameToolBinary.isEmpty());
-}
-
-void tst_macdeployqt::cleanupTestCase()
-{
- delete g_temporaryDirectory;
-}
-
-// Verify that deployment of a basic Qt Gui application works
-void tst_macdeployqt::basicapp()
-{
-#ifdef QT_NO_PROCESS
- QSKIP("This test requires QProcess support");
-#endif
-
- QString errorMessage;
- QString name = "basicapp";
-
- // Build and verify that the application runs before deployment
- build(name);
- QVERIFY2(run(name, &errorMessage), qPrintable(errorMessage));
-
- // Deploy application
- QVERIFY2(deploy(name, QStringList(), &errorMessage), qPrintable(errorMessage));
-
- // Verify deployment
- runVerifyDeployment(name);
-}
-
-void tst_macdeployqt::plugins_data()
-{
- QTest::addColumn<QString>("name");
- QTest::newRow("sqlite") << "plugin_sqlite";
- QTest::newRow("tls") << "plugin_tls";
-}
-
-void tst_macdeployqt::plugins()
-{
- QFETCH(QString, name);
-
- build(name);
-
- // Verify that the test app runs before deployment.
- QString errorMessage;
- if (!run(name, &errorMessage)) {
- qDebug() << qPrintable(errorMessage);
- QSKIP("Could not run test application before deployment");
- }
-
- QVERIFY2(deploy(name, QStringList(), &errorMessage), qPrintable(errorMessage));
- runVerifyDeployment(name);
-}
-
-QTEST_MAIN(tst_macdeployqt)
-#include "tst_macdeployqt.moc"
diff --git a/tests/auto/windeployqt/CMakeLists.txt b/tests/auto/windeployqt/CMakeLists.txt
deleted file mode 100644
index 5eae1ca16..000000000
--- a/tests/auto/windeployqt/CMakeLists.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# Generated from windeployqt.pro.
-
-add_subdirectory(testapp)
-add_subdirectory(test)
diff --git a/tests/auto/windeployqt/test/CMakeLists.txt b/tests/auto/windeployqt/test/CMakeLists.txt
deleted file mode 100644
index d412249a7..000000000
--- a/tests/auto/windeployqt/test/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# Generated from test.pro.
-
-#####################################################################
-## tst_windeployqt Test:
-#####################################################################
-
-qt_internal_add_test(tst_windeployqt
- OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" # special case
- SOURCES
- ../tst_windeployqt.cpp
-)
diff --git a/tests/auto/windeployqt/testapp/CMakeLists.txt b/tests/auto/windeployqt/testapp/CMakeLists.txt
deleted file mode 100644
index 83851dae6..000000000
--- a/tests/auto/windeployqt/testapp/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated from testapp.pro.
-
-#####################################################################
-## testapp Binary:
-#####################################################################
-
-qt_internal_add_executable(windeploy_testapp # special case
- GUI
- OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
- SOURCES
- main.cpp
- PUBLIC_LIBRARIES
- Qt::Gui
-)
-
-# special case begin
-set_target_properties(windeploy_testapp
- PROPERTIES
- OUTPUT_NAME testapp
-)
-# special case end
diff --git a/tests/auto/windeployqt/testapp/main.cpp b/tests/auto/windeployqt/testapp/main.cpp
deleted file mode 100644
index 4dc03cdad..000000000
--- a/tests/auto/windeployqt/testapp/main.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QGuiApplication>
-#include <QRasterWindow>
-#include <QScreen>
-#include <QTimer>
-
-// Simple test application just to verify that it comes up properly
-
-int main(int argc, char ** argv)
-{
- QGuiApplication app(argc, argv);
- QRasterWindow w;
- w.setTitle("windeployqt test application");
- const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
- w.resize(availableGeometry.size() / 4);
- w.show();
- QTimer::singleShot(200, &w, &QCoreApplication::quit);
- return app.exec();
-}
diff --git a/tests/auto/windeployqt/tst_windeployqt.cpp b/tests/auto/windeployqt/tst_windeployqt.cpp
deleted file mode 100644
index 38403c90f..000000000
--- a/tests/auto/windeployqt/tst_windeployqt.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QtCore/QDebug>
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
-#include <QtCore/QLibraryInfo>
-#include <QtCore/QProcess>
-#include <QtCore/QProcessEnvironment>
-#include <QtCore/QStandardPaths>
-#include <QtCore/QTextStream>
-#include <QtTest/QtTest>
-
-static const QString msgProcessError(const QProcess &process, const QString &what,
- const QByteArray &stdOut = QByteArray(),
- const QByteArray &stdErr = QByteArray())
-{
- QString result;
- QTextStream str(&result);
- str << what << ": \"" << process.program() << ' '
- << process.arguments().join(QLatin1Char(' ')) << "\": " << process.errorString();
- if (!stdOut.isEmpty())
- str << "\nStandard output:\n" << stdOut;
- if (!stdErr.isEmpty())
- str << "\nStandard error:\n" << stdErr;
- return result;
-}
-
-static bool runProcess(const QString &binary,
- const QStringList &arguments,
- QString *errorMessage,
- const QString &workingDir = QString(),
- const QProcessEnvironment &env = QProcessEnvironment(),
- int timeOut = 5000,
- QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr)
-{
- QProcess process;
- if (!env.isEmpty())
- process.setProcessEnvironment(env);
- if (!workingDir.isEmpty())
- process.setWorkingDirectory(workingDir);
- qDebug().noquote().nospace() << "Running: " << QDir::toNativeSeparators(binary)
- << ' ' << arguments.join(QLatin1Char(' '));
- process.start(binary, arguments, QIODevice::ReadOnly);
- if (!process.waitForStarted()) {
- *errorMessage = msgProcessError(process, "Failed to start");
- return false;
- }
- if (!process.waitForFinished(timeOut)) {
- *errorMessage = msgProcessError(process, "Timed out");
- process.terminate();
- if (!process.waitForFinished(300))
- process.kill();
- return false;
- }
- const QByteArray stdOut = process.readAllStandardOutput();
- const QByteArray stdErr = process.readAllStandardError();
- if (stdOutIn)
- *stdOutIn = stdOut;
- if (stdErrIn)
- *stdErrIn = stdErr;
- if (process.exitStatus() != QProcess::NormalExit) {
- *errorMessage = msgProcessError(process, "Crashed", stdOut, stdErr);
- return false;
- }
- if (process.exitCode() != QProcess::NormalExit) {
- *errorMessage = msgProcessError(process, "Exit code " + QString::number(process.exitCode()),
- stdOut, stdErr);
- return false;
- }
- return true;
-}
-
-class tst_windeployqt : public QObject
-{
- Q_OBJECT
-private slots:
- void initTestCase();
- void help();
- void deploy();
-
-private:
- QString m_windeployqtBinary;
- QString m_testApp;
- QString m_testAppBinary;
-};
-
-void tst_windeployqt::initTestCase()
-{
- m_windeployqtBinary = QStandardPaths::findExecutable("windeployqt");
- QVERIFY(!m_windeployqtBinary.isEmpty());
- m_testApp = QFINDTESTDATA("testapp");
- QVERIFY(!m_testApp.isEmpty());
- const QFileInfo testAppBinary(m_testApp + QLatin1String("/testapp.exe"));
- QVERIFY2(testAppBinary.isFile(), qPrintable(testAppBinary.absoluteFilePath()));
- m_testAppBinary = testAppBinary.absoluteFilePath();
-}
-
-void tst_windeployqt::help()
-{
- QString errorMessage;
- QByteArray stdOut;
- QByteArray stdErr;
- QVERIFY2(runProcess(m_windeployqtBinary, QStringList("--help"), &errorMessage,
- QString(), QProcessEnvironment(), 5000, &stdOut, &stdErr),
- qPrintable(errorMessage));
- QVERIFY2(!stdOut.isEmpty(), stdErr);
-}
-
-// deploy(): Deploys the test application and launches it with Qt removed from the environment
-// to verify it runs stand-alone.
-
-void tst_windeployqt::deploy()
-{
- QString errorMessage;
- // Deploy application
- QStringList deployArguments;
- deployArguments << QLatin1String("--no-translations") << QDir::toNativeSeparators(m_testAppBinary);
- QVERIFY2(runProcess(m_windeployqtBinary, deployArguments, &errorMessage, QString(), QProcessEnvironment(), 20000),
- qPrintable(errorMessage));
-
- // Create environment with Qt and all "lib" paths removed.
- const QString qtBinDir = QDir::toNativeSeparators(QLibraryInfo::path(QLibraryInfo::BinariesPath));
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- const QString pathKey = QLatin1String("PATH");
- const QChar pathSeparator(QLatin1Char(';')); // ### fixme: Qt 5.6: QDir::listSeparator()
- const QString origPath = env.value(pathKey);
- QString newPath;
- const QStringList pathElements = origPath.split(pathSeparator, Qt::SkipEmptyParts);
- for (const QString &pathElement : pathElements) {
- if (pathElement.compare(qtBinDir, Qt::CaseInsensitive)
- && !pathElement.contains(QLatin1String("\\lib"), Qt::CaseInsensitive)) {
- if (!newPath.isEmpty())
- newPath.append(pathSeparator);
- newPath.append(pathElement);
- }
- }
- if (newPath == origPath)
- qWarning() << "Unable to remove Qt from PATH";
- env.insert(pathKey, newPath);
-
- // Create qt.conf to enforce usage of local plugins
- QFile qtConf(QFileInfo(m_testAppBinary).absolutePath() + QLatin1String("/qt.conf"));
- QVERIFY2(qtConf.open(QIODevice::WriteOnly | QIODevice::Text),
- qPrintable(qtConf.fileName() + QLatin1String(": ") + qtConf.errorString()));
- QVERIFY(qtConf.write("[Paths]\nPrefix = .\n"));
- qtConf.close();
-
- // Verify that application still runs
- QVERIFY2(runProcess(m_testAppBinary, QStringList(), &errorMessage, QString(), env, 10000),
- qPrintable(errorMessage));
-}
-
-QTEST_MAIN(tst_windeployqt)
-#include "tst_windeployqt.moc"