summaryrefslogtreecommitdiffstats
path: root/src/tools/windeployqt
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/windeployqt')
-rw-r--r--src/tools/windeployqt/CMakeLists.txt3
-rw-r--r--src/tools/windeployqt/elfreader.cpp417
-rw-r--r--src/tools/windeployqt/elfreader.h151
-rw-r--r--src/tools/windeployqt/main.cpp642
-rw-r--r--src/tools/windeployqt/qmlutils.cpp3
-rw-r--r--src/tools/windeployqt/qtmoduleinfo.cpp12
-rw-r--r--src/tools/windeployqt/qtplugininfo.cpp100
-rw-r--r--src/tools/windeployqt/qtplugininfo.h48
-rw-r--r--src/tools/windeployqt/utils.cpp169
-rw-r--r--src/tools/windeployqt/utils.h29
10 files changed, 750 insertions, 824 deletions
diff --git a/src/tools/windeployqt/CMakeLists.txt b/src/tools/windeployqt/CMakeLists.txt
index 715c008831..2e50116484 100644
--- a/src/tools/windeployqt/CMakeLists.txt
+++ b/src/tools/windeployqt/CMakeLists.txt
@@ -12,15 +12,16 @@ qt_internal_add_tool(${target_name}
INSTALL_VERSIONED_LINK
TARGET_DESCRIPTION "Qt Windows Deployment Tool"
SOURCES
- elfreader.cpp elfreader.h
qmlutils.cpp qmlutils.h
qtmoduleinfo.cpp qtmoduleinfo.h
+ qtplugininfo.cpp qtplugininfo.h
utils.cpp utils.h
main.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
QT_NO_FOREACH
+ QT_NO_QPAIR
LIBRARIES
Qt::CorePrivate
)
diff --git a/src/tools/windeployqt/elfreader.cpp b/src/tools/windeployqt/elfreader.cpp
deleted file mode 100644
index 9ef3b6bfa4..0000000000
--- a/src/tools/windeployqt/elfreader.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "elfreader.h"
-
-#include <QDir>
-
-QT_BEGIN_NAMESPACE
-
-using namespace Qt::StringLiterals;
-
-/* 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("wrong cpu architecture"_L1);
- // 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("shstrtab section header seems to be at %1"_L1)
-// .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/tools/windeployqt/elfreader.h b/src/tools/windeployqt/elfreader.h
deleted file mode 100644
index bea53c2ee4..0000000000
--- a/src/tools/windeployqt/elfreader.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#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 symbols 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/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp
index bb661f6fcd..dca9132e15 100644
--- a/src/tools/windeployqt/main.cpp
+++ b/src/tools/windeployqt/main.cpp
@@ -4,6 +4,7 @@
#include "utils.h"
#include "qmlutils.h"
#include "qtmoduleinfo.h"
+#include "qtplugininfo.h"
#include <QtCore/QCommandLineOption>
#include <QtCore/QCommandLineParser>
@@ -79,10 +80,6 @@ static void assignKnownModuleIds()
#undef DECLARE_KNOWN_MODULE
#undef DEFINE_KNOWN_MODULE
-enum QtPlugin {
- QtVirtualKeyboardPlugin = 0x1
-};
-
static const char webEngineProcessC[] = "QtWebEngineProcess";
static inline QString webProcessBinary(const char *binaryName, Platform p)
@@ -111,6 +108,23 @@ static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
result.append(option
? moduleNameToOptionName(qtModule.name).toUtf8()
: qtModule.name.toUtf8());
+ if (qtModule.internal)
+ result.append("Internal");
+ }
+ }
+ return result;
+}
+
+static QString formatQtPlugins(const PluginInformation &pluginInfo)
+{
+ QString result(u'\n');
+ for (const auto &pair : pluginInfo.typeMap()) {
+ result += pair.first;
+ result += u": \n";
+ for (const QString &plugin : pair.second) {
+ result += u" ";
+ result += plugin;
+ result += u'\n';
}
}
return result;
@@ -118,14 +132,17 @@ static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
static Platform platformFromMkSpec(const QString &xSpec)
{
- if (xSpec == "linux-g++"_L1)
- return Unix;
if (xSpec.startsWith("win32-"_L1)) {
if (xSpec.contains("clang-g++"_L1))
return WindowsDesktopClangMinGW;
if (xSpec.contains("clang-msvc++"_L1))
return WindowsDesktopClangMsvc;
- return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvc;
+ if (xSpec.contains("arm"_L1))
+ return WindowsDesktopMsvcArm;
+ if (xSpec.contains("G++"_L1))
+ return WindowsDesktopMinGW;
+
+ return WindowsDesktopMsvc;
}
return UnknownPlatform;
}
@@ -166,10 +183,12 @@ struct Options {
bool quickImports = true;
bool translations = true;
bool systemD3dCompiler = true;
+ bool systemDxc = true;
bool compilerRunTime = false;
- unsigned disabledPlugins = 0;
bool softwareRasterizer = true;
- Platform platform = WindowsDesktopMsvc;
+ bool ffmpeg = true;
+ PluginSelections pluginSelections;
+ Platform platform = WindowsDesktopMsvcIntel;
ModuleBitset additionalLibraries;
ModuleBitset disabledLibraries;
unsigned updateFileFlags = 0;
@@ -181,6 +200,7 @@ struct Options {
QStringList languages;
QString libraryDirectory;
QString pluginDirectory;
+ QString openSslRootDirectory;
QString qmlDirectory;
QStringList binaries;
JsonOutput *json = nullptr;
@@ -190,6 +210,8 @@ struct Options {
bool dryRun = false;
bool patchQt = true;
bool ignoreLibraryErrors = false;
+ bool deployInsightTrackerPlugin = false;
+ bool forceOpenSslPlugin = false;
};
// Return binary to be deployed from folder, ignore pre-existing web engine process.
@@ -215,7 +237,8 @@ static QString msgFileDoesNotExist(const QString & file)
enum CommandLineParseFlag {
CommandLineParseError = 0x1,
- CommandLineParseHelpRequested = 0x2
+ CommandLineParseHelpRequested = 0x2,
+ CommandLineVersionRequested = 0x4
};
static QCommandLineOption createQMakeOption()
@@ -269,7 +292,7 @@ static int parseEarlyArguments(const QStringList &arguments, Options *options,
}
if (parser.isSet(qmakeOption) && optVerboseLevel >= 1)
- std::wcerr << "Warning: -qmake option is deprecated. Use -qpaths instead.\n";
+ std::wcerr << "Warning: -qmake option is deprecated. Use -qtpaths instead.\n";
if (parser.isSet(qtpathsOption) || parser.isSet(qmakeOption)) {
const QString qtpathsArg = parser.isSet(qtpathsOption) ? parser.value(qtpathsOption)
@@ -316,7 +339,7 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
"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>"_s);
const QCommandLineOption helpOption = parser->addHelpOption();
- parser->addVersionOption();
+ const QCommandLineOption versionOption = parser->addVersionOption();
QCommandLineOption dirOption(QStringLiteral("dir"),
QStringLiteral("Use directory instead of binary directory."),
@@ -383,6 +406,30 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Skip plugin deployment."));
parser->addOption(noPluginsOption);
+ QCommandLineOption includeSoftPluginsOption(QStringLiteral("include-soft-plugins"),
+ QStringLiteral("Include in the deployment all relevant plugins by taking into account all soft dependencies."));
+ parser->addOption(includeSoftPluginsOption);
+
+ QCommandLineOption skipPluginTypesOption(QStringLiteral("skip-plugin-types"),
+ QStringLiteral("A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
+ QStringLiteral("plugin types"));
+ parser->addOption(skipPluginTypesOption);
+
+ QCommandLineOption addPluginTypesOption(QStringLiteral("add-plugin-types"),
+ QStringLiteral("A comma-separated list of plugin types that will be added to deployment (imageformats,iconengines)"),
+ QStringLiteral("plugin types"));
+ parser->addOption(addPluginTypesOption);
+
+ QCommandLineOption includePluginsOption(QStringLiteral("include-plugins"),
+ QStringLiteral("A comma-separated list of individual plugins that will be added to deployment (scene2d,qjpeg)"),
+ QStringLiteral("plugins"));
+ parser->addOption(includePluginsOption);
+
+ QCommandLineOption excludePluginsOption(QStringLiteral("exclude-plugins"),
+ QStringLiteral("A comma-separated list of individual plugins that will not be deployed (qsvg,qpdf)"),
+ QStringLiteral("plugins"));
+ parser->addOption(excludePluginsOption);
+
QCommandLineOption noLibraryOption(QStringLiteral("no-libraries"),
QStringLiteral("Skip library deployment."));
parser->addOption(noLibraryOption);
@@ -415,15 +462,15 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Skip deployment of the system D3D compiler."));
parser->addOption(noSystemD3DCompilerOption);
+ QCommandLineOption noSystemDxcOption(QStringLiteral("no-system-dxc-compiler"),
+ QStringLiteral("Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
+ parser->addOption(noSystemDxcOption);
+
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);
@@ -436,6 +483,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Do not deploy the software rasterizer library."));
parser->addOption(suppressSoftwareRasterizerOption);
+ QCommandLineOption noFFmpegOption(QStringLiteral("no-ffmpeg"),
+ QStringLiteral("Do not deploy the FFmpeg libraries."));
+ parser->addOption(noFFmpegOption);
+
+ QCommandLineOption forceOpenSslOption(QStringLiteral("force-openssl"),
+ QStringLiteral("Deploy openssl plugin but ignore openssl library dependency"));
+ parser->addOption(forceOpenSslOption);
+
+ QCommandLineOption openSslRootOption(QStringLiteral("openssl-root"),
+ QStringLiteral("Directory containing openSSL libraries."),
+ QStringLiteral("directory"));
+ parser->addOption(openSslRootOption);
+
+
QCommandLineOption listOption(QStringLiteral("list"),
"Print only the names of the files copied.\n"
"Available options:\n"
@@ -455,6 +516,11 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
parser->addPositionalArgument(QStringLiteral("[files]"),
QStringLiteral("Binaries or directory containing the binary."));
+ QCommandLineOption deployInsightTrackerOption(QStringLiteral("deploy-insighttracker"),
+ QStringLiteral("Deploy insight tracker plugin."));
+ // The option will be added to the parser if the module is available (see block below)
+ bool insightTrackerModuleAvailable = false;
+
OptionPtrVector enabledModuleOptions;
OptionPtrVector disabledModuleOptions;
const size_t qtModulesCount = qtModuleEntries.size();
@@ -463,6 +529,10 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (const QtModule &module : qtModuleEntries) {
const QString option = moduleNameToOptionName(module.name);
const QString name = module.name;
+ if (name == u"InsightTracker") {
+ parser->addOption(deployInsightTrackerOption);
+ insightTrackerModuleAvailable = true;
+ }
const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module.");
CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription));
parser->addOption(*enabledOption.data());
@@ -477,6 +547,8 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
const bool success = parser->parse(arguments);
if (parser->isSet(helpOption))
return CommandLineParseHelpRequested;
+ if (parser->isSet(versionOption))
+ return CommandLineVersionRequested;
if (!success) {
*errorMessage = parser->errorText();
return CommandLineParseError;
@@ -492,22 +564,35 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(translationOption))
options->languages = parser->value(translationOption).split(u',');
options->systemD3dCompiler = !parser->isSet(noSystemD3DCompilerOption);
+ options->systemDxc = !parser->isSet(noSystemDxcOption);
options->quickImports = !parser->isSet(noQuickImportOption);
// default to deployment of compiler runtime for windows desktop configurations
- if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc
+ if (options->platform == WindowsDesktopMinGW || options->platform.testFlags(WindowsDesktopMsvc)
|| parser->isSet(compilerRunTimeOption))
options->compilerRunTime = true;
if (parser->isSet(noCompilerRunTimeOption))
options->compilerRunTime = false;
- if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) {
+ if (options->compilerRunTime && options->platform != WindowsDesktopMinGW
+ && !options->platform.testFlags(WindowsDesktopMsvc)) {
*errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
return CommandLineParseError;
}
- if (parser->isSet(noVirtualKeyboardOption))
- options->disabledPlugins |= QtVirtualKeyboardPlugin;
+ options->pluginSelections.includeSoftPlugins = parser->isSet(includeSoftPluginsOption);
+
+ if (parser->isSet(skipPluginTypesOption))
+ options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
+
+ if (parser->isSet(addPluginTypesOption))
+ options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
+
+ if (parser->isSet(includePluginsOption))
+ options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
+
+ if (parser->isSet(excludePluginsOption))
+ options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
if (parser->isSet(releaseWithDebugInfoOption))
std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete.";
@@ -533,6 +618,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(suppressSoftwareRasterizerOption))
options->softwareRasterizer = false;
+ if (parser->isSet(noFFmpegOption))
+ options->ffmpeg = false;
+
+ if (parser->isSet(forceOpenSslOption))
+ options->forceOpenSslPlugin = true;
+
+ if (parser->isSet(openSslRootOption))
+ options->openSslRootDirectory = parser->value(openSslRootOption);
+
+ if (options->forceOpenSslPlugin && !options->openSslRootDirectory.isEmpty()) {
+ *errorMessage = QStringLiteral("force-openssl and openssl-root are mutually exclusive");
+ return CommandLineParseError;
+ }
+
if (parser->isSet(forceOption))
options->updateFileFlags |= ForceUpdateFile;
if (parser->isSet(dryRunOption)) {
@@ -542,6 +641,8 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
options->patchQt = !parser->isSet(noPatchQtOption);
options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
+ if (insightTrackerModuleAvailable)
+ options->deployInsightTrackerPlugin = parser->isSet(deployInsightTrackerOption);
for (const QtModule &module : qtModuleEntries) {
if (parser->isSet(*enabledModuleOptions.at(module.id)))
@@ -633,13 +734,15 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (const QString &library : libraries)
options->binaries.append(path + u'/' + library);
} else {
- if (fi.absolutePath() != options->directory)
+ if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
multipleDirs = true;
options->binaries.append(path);
}
}
- if (multipleDirs)
- std::wcerr << "Warning: using binaries from different directories\n";
+ if (multipleDirs) {
+ std::wcerr << "Warning: using binaries from different directories, deploying to following path: "
+ << options->directory << '\n' << "To disable this warning, use the --dir option\n";
+ }
if (options->translationsDirectory.isEmpty())
options->translationsDirectory = options->directory + "/translations"_L1;
return 0;
@@ -658,7 +761,7 @@ static inline QString lineBreak(QString s)
return s;
}
-static inline QString helpText(const QCommandLineParser &p)
+static inline QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
{
QString result = p.helpText();
// Replace the default-generated text which is too long by a short summary
@@ -677,7 +780,18 @@ static inline QString helpText(const QCommandLineParser &p)
"the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
ModuleBitset mask;
moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
- moduleHelp += u'\n';
+ moduleHelp += u"\n\n";
+ moduleHelp +=
+ u"Qt plugins can be included or excluded individually or by type.\n"
+ u"To deploy or block plugins individually, use the --include-plugins\n"
+ u"and --exclude-plugins options (--include-plugins qjpeg,qsvgicon)\n"
+ u"You can also use the --skip-plugin-types or --add-plugin-types to\n"
+ u"achieve similar results with entire plugin groups, like imageformats, e.g.\n"
+ u"(--add-plugin-types imageformats,iconengines). Exclusion always takes\n"
+ u"precedence over inclusion, and types take precedence over specific plugins.\n"
+ u"For example, including qjpeg, but skipping imageformats, will NOT deploy qjpeg.\n"
+ u"\nDetected available plugins:\n";
+ moduleHelp += formatQtPlugins(pluginInfo);
result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp);
return result;
}
@@ -701,7 +815,8 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin
QStringList dependentLibs;
if (directDependencyCount)
*directDependencyCount = 0;
- if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug, machineArch)) {
+ if (!readPeExecutable(binary, errorMessage, &dependentLibs, wordSize, isDebug,
+ platform == WindowsDesktopMinGW, machineArch)) {
errorMessage->prepend("Unable to find dependent libraries of "_L1 +
QDir::toNativeSeparators(binary) + " :"_L1);
return false;
@@ -766,13 +881,19 @@ public:
SkipSources = 0x2
};
- explicit QmlDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
+ explicit QmlDirectoryFileEntryFunction(
+ const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
: m_flags(flags), m_qmlNameFilter(QmlDirectoryFileEntryFunction::qmlNameFilters(flags))
- , m_dllFilter(platform, debugMatchMode)
+ , m_dllFilter(platform, debugMatchMode), m_moduleSourcePath(moduleSourcePath)
{}
QStringList operator()(const QDir &dir) const
{
+ if (moduleSourceDir(dir).canonicalPath() != m_moduleSourcePath) {
+ // If we're in a different module, return nothing.
+ return {};
+ }
+
QStringList result;
const QStringList &libraries = m_dllFilter(dir);
for (const QString &library : libraries) {
@@ -788,6 +909,17 @@ public:
}
private:
+ static QDir moduleSourceDir(const QDir &dir)
+ {
+ QDir moduleSourceDir = dir;
+ while (!moduleSourceDir.exists(QStringLiteral("qmldir"))) {
+ if (!moduleSourceDir.cdUp()) {
+ return {};
+ }
+ }
+ return moduleSourceDir;
+ }
+
static inline QStringList qmlNameFilters(unsigned flags)
{
QStringList result;
@@ -804,9 +936,10 @@ private:
const unsigned m_flags;
NameFilterFileEntryFunction m_qmlNameFilter;
DllDirectoryFileEntryFunction m_dllFilter;
+ QString m_moduleSourcePath;
};
-static quint64 qtModule(QString module, const QString &infix)
+static qint64 qtModule(QString module, const QString &infix)
{
// Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0'
const qsizetype lastSlashPos = module.lastIndexOf(u'/');
@@ -827,73 +960,124 @@ static quint64 qtModule(QString module, const QString &infix)
return qtModule.id;
}
}
- return 0;
+ std::wcerr << "Warning: module " << qPrintable(module) << " could not be found\n";
+ return -1;
}
// Return the path if a plugin is to be deployed
-static QString deployPlugin(const QString &plugin, const QDir &subDir,
- ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
- unsigned disabledPlugins,
- const QString &libraryLocation, const QString &infix,
- Platform platform)
+static QString deployPlugin(const QString &plugin, const QDir &subDir, const bool dueToModule,
+ const DebugMatchMode &debugMatchMode, ModuleBitset *pluginNeededQtModules,
+ const ModuleBitset &disabledQtModules,
+ const PluginSelections &pluginSelections, const QString &libraryLocation,
+ const QString &infix, Platform platform,
+ bool deployInsightTrackerPlugin, bool deployOpenSslPlugin)
{
+ const QString subDirName = subDir.dirName();
// Filter out disabled plugins
- if ((disabledPlugins & QtVirtualKeyboardPlugin)
- && plugin.startsWith("qtvirtualkeyboardplugin"_L1)) {
+ if (optVerboseLevel && pluginSelections.disabledPluginTypes.contains(subDirName)) {
+ std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n';
+ return {};
+ }
+ if (optVerboseLevel && subDirName == u"generic" && plugin.contains(u"qinsighttracker")
+ && !deployInsightTrackerPlugin) {
+ std::wcout << "Skipping plugin " << plugin
+ << ". Use -deploy-insighttracker if you want to use it.\n";
+ return {};
+ }
+ if (optVerboseLevel && subDirName == u"tls" && plugin.contains(u"qopensslbackend")
+ && !deployOpenSslPlugin) {
+ std::wcout << "Skipping plugin " << plugin
+ << ". Use -force_openssl or specify -openssl-root if you want to use it.\n";
+ return {};
+ }
+
+ const int dotIndex = plugin.lastIndexOf(u'.');
+ // Strip the .dll from the name, and an additional 'd' if it's a debug library with the 'd'
+ // suffix
+ const int stripIndex = debugMatchMode == MatchDebug && platformHasDebugSuffix(platform)
+ ? dotIndex - 1
+ : dotIndex;
+ const QString pluginName = plugin.first(stripIndex);
+
+ if (optVerboseLevel && pluginSelections.excludedPlugins.contains(pluginName)) {
+ std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n';
+ return {};
+ }
+
+ // By default, only deploy qwindows.dll
+ if (subDirName == u"platforms"
+ && !(pluginSelections.includedPlugins.contains(pluginName)
+ || (pluginSelections.enabledPluginTypes.contains(subDirName)))
+ && !pluginName.startsWith(u"qwindows")) {
return {};
}
const QString pluginPath = subDir.absoluteFilePath(plugin);
+
+ // If dueToModule is false, check if the user included the plugin or the entire type. In the
+ // former's case, only deploy said plugin and not all plugins of that type.
+ const bool requiresPlugin = pluginSelections.includedPlugins.contains(pluginName)
+ || pluginSelections.enabledPluginTypes.contains(subDirName);
+ if (!dueToModule && !requiresPlugin)
+ return {};
+
// Deploy QUiTools plugins as is without further dependency checking.
// The user needs to ensure all required libraries are present (would
// otherwise pull QtWebEngine for its plugin).
- if (subDir.dirName() == u"designer")
+ if (subDirName == u"designer")
return pluginPath;
QStringList dependentQtLibs;
- ModuleBitset neededModules;
QString errorMessage;
if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
&errorMessage, &dependentQtLibs)) {
- for (int d = 0; d < dependentQtLibs.size(); ++ d)
- neededModules[qtModule(dependentQtLibs.at(d), infix)] = 1;
+ for (int d = 0; d < dependentQtLibs.size(); ++d) {
+ const qint64 module = qtModule(dependentQtLibs.at(d), infix);
+ if (module >= 0)
+ (*pluginNeededQtModules)[module] = 1;
+ }
} else {
std::wcerr << "Warning: Cannot determine dependencies of "
<< QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
}
- ModuleBitset missingModules;
- missingModules = neededModules & disabledQtModules;
- if (missingModules.any()) {
+ ModuleBitset disabledNeededQtModules;
+ disabledNeededQtModules = *pluginNeededQtModules & disabledQtModules;
+ if (disabledNeededQtModules.any()) {
if (optVerboseLevel) {
std::wcout << "Skipping plugin " << plugin
<< " due to disabled dependencies ("
- << formatQtModules(missingModules).constData() << ").\n";
+ << formatQtModules(disabledNeededQtModules).constData() << ").\n";
}
return {};
}
- missingModules = (neededModules & ~*usedQtModules);
- if (missingModules.any()) {
- *usedQtModules |= missingModules;
- if (optVerboseLevel) {
- std::wcout << "Adding " << formatQtModules(missingModules).constData()
- << " for " << plugin << '\n';
- }
- }
return pluginPath;
}
+static bool needsPluginType(const QString &subDirName, const PluginInformation &pluginInfo,
+ const PluginSelections &pluginSelections)
+{
+ bool needsTypeForPlugin = false;
+ for (const QString &plugin: pluginSelections.includedPlugins) {
+ if (pluginInfo.isTypeForPlugin(subDirName, plugin))
+ needsTypeForPlugin = true;
+ }
+ return (pluginSelections.enabledPluginTypes.contains(subDirName) || needsTypeForPlugin);
+}
+
QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
- unsigned disabledPlugins,
+ const PluginInformation &pluginInfo, const PluginSelections &pluginSelections,
const QString &qtPluginsDirName, const QString &libraryLocation,
- const QString &infix,
- DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin)
+ const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform,
+ QString *platformPlugin, bool deployInsightTrackerPlugin,
+ bool deployOpenSslPlugin)
{
if (qtPluginsDirName.isEmpty())
return QStringList();
QDir pluginsDir(qtPluginsDirName);
QStringList result;
+ bool missingQtModulesAdded = false;
const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &subDirFi : pluginDirs) {
const QString subDirName = subDirFi.fileName();
@@ -904,49 +1088,55 @@ QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disab
}
continue;
}
- if (usedQtModules->test(module)) {
+ const bool dueToModule = usedQtModules->test(module);
+ if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
? 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 == "virtualkeyboard"_L1)
- continue;
- if (disabledQtModules.test(QtQmlToolingModuleId) && subDirName == "qmltooling"_L1)
- continue;
- // Filter for platform or any.
- QString filter;
+ if (optVerboseLevel)
+ std::wcout << "Adding in plugin type " << subDirFi.baseName() << " for module: " << qtModuleEntries.moduleById(module).name << '\n';
+
const bool isPlatformPlugin = subDirName == "platforms"_L1;
- if (isPlatformPlugin) {
- switch (platform) {
- case WindowsDesktopMsvc:
- case WindowsDesktopMinGW:
- filter = QStringLiteral("qwindows");
- if (!infix.isEmpty())
- filter += infix;
- break;
- case Unix:
- filter = QStringLiteral("libqxcb");
- break;
- case UnknownPlatform:
- break;
- }
- } else {
- filter = u"*"_s;
- }
- const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter);
+ const QStringList plugins =
+ findSharedLibraries(subDir, platform, debugMatchMode, QString());
for (const QString &plugin : plugins) {
+ ModuleBitset pluginNeededQtModules;
const QString pluginPath =
- deployPlugin(plugin, subDir, usedQtModules, disabledQtModules,
- disabledPlugins, libraryLocation, infix, platform);
+ deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
+ disabledQtModules, pluginSelections, libraryLocation, infix,
+ platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
if (!pluginPath.isEmpty()) {
- if (isPlatformPlugin)
+ if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
*platformPlugin = subDir.absoluteFilePath(plugin);
result.append(pluginPath);
+
+ const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
+ if (missingModules.any()) {
+ *usedQtModules |= missingModules;
+ missingQtModulesAdded = true;
+ if (optVerboseLevel) {
+ std::wcout << "Adding " << formatQtModules(missingModules).constData()
+ << " for " << plugin << " from plugin type: " << subDirName << '\n';
+ }
+ }
}
} // for filter
} // type matches
} // for plugin folder
+
+ // If missing Qt modules were added during plugin deployment make additional pass, because we may need
+ // additional plugins.
+ if (pluginSelections.includeSoftPlugins && missingQtModulesAdded) {
+ if (optVerboseLevel) {
+ std::wcout << "Performing additional pass of finding Qt plugins due to updated Qt module list: "
+ << formatQtModules(*usedQtModules).constData() << "\n";
+ }
+ return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
+ libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
+ deployInsightTrackerPlugin, deployOpenSslPlugin);
+ }
+
return result;
}
@@ -995,7 +1185,12 @@ static bool deployTranslations(const QString &sourcePath, const ModuleBitset &us
if (options.json)
options.json->addFile(sourcePath + u'/' + targetFile, absoluteTarget);
arguments.append(QDir::toNativeSeparators(targetFilePath));
- const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationNameFilters(usedQtModules, prefix));
+ const QStringList translationFilters = translationNameFilters(usedQtModules, prefix);
+ if (translationFilters.isEmpty()){
+ std::wcerr << "Warning: translation catalogs are all empty, skipping translation deployment\n";
+ return true;
+ }
+ const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationFilters);
for (const QFileInfo &langQmFileFi : langQmFiles) {
if (options.json) {
options.json->addFile(langQmFileFi.absoluteFilePath(),
@@ -1015,6 +1210,62 @@ static bool deployTranslations(const QString &sourcePath, const ModuleBitset &us
return true;
}
+static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
+{
+ const std::vector<QLatin1StringView> ffmpegHints = { "avcodec"_L1, "avformat"_L1, "avutil"_L1,
+ "swresample"_L1, "swscale"_L1 };
+ const QStringList bundledLibs =
+ findSharedLibraries(qtBinDir, platform, MatchDebugOrRelease, {});
+
+ QStringList ffmpegLibs;
+ for (const QLatin1StringView &libHint : ffmpegHints) {
+ const QStringList ffmpegLib = bundledLibs.filter(libHint, Qt::CaseInsensitive);
+
+ if (ffmpegLib.empty()) {
+ std::wcerr << "Warning: Cannot find FFmpeg libraries. Multimedia features will not work as expected.\n";
+ return {};
+ } else if (ffmpegLib.size() != 1u) {
+ std::wcerr << "Warning: Multiple versions of FFmpeg libraries found. Multimedia features will not work as expected.\n";
+ return {};
+ }
+
+ const QChar slash(u'/');
+ QFileInfo ffmpegLibPath{ qtBinDir + slash + ffmpegLib.front() };
+ ffmpegLibs.append(ffmpegLibPath.absoluteFilePath());
+ }
+
+ return ffmpegLibs;
+}
+
+// Find the openssl libraries Qt executables depend on.
+static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
+{
+ const std::vector<QLatin1StringView> libHints = { "libcrypto"_L1, "libssl"_L1 };
+ const QChar slash(u'/');
+ const QString openSslBinDir = openSslRootDir + slash + "bin"_L1;
+ const QStringList openSslRootLibs =
+ findSharedLibraries(openSslBinDir, platform, MatchDebugOrRelease, {});
+
+ QStringList result;
+ for (const QLatin1StringView &libHint : libHints) {
+ const QStringList lib = openSslRootLibs.filter(libHint, Qt::CaseInsensitive);
+
+ if (lib.empty()) {
+ std::wcerr << "Warning: Cannot find openssl libraries.\n";
+ return {};
+ } else if (lib.size() != 1u) {
+ std::wcerr << "Warning: Multiple versions of openssl libraries found.\n";
+ return {};
+ }
+
+ QFileInfo libPath{ openSslBinDir + slash + lib.front() };
+ result.append(libPath.absoluteFilePath());
+ }
+
+ return result;
+}
+
+
struct DeployResult
{
operator bool() const { return success; }
@@ -1027,20 +1278,14 @@ struct DeployResult
};
static QString libraryPath(const QString &libraryLocation, const char *name,
- const QString &qtLibInfix, Platform platform, bool debug)
+ const QString &infix, Platform platform, bool debug)
{
QString result = libraryLocation + u'/';
- if (platform & WindowsBased) {
- result += QLatin1StringView(name);
- result += qtLibInfix;
- if (debug && platformHasDebugSuffix(platform))
- result += u'd';
- } else if (platform.testFlag(UnixBased)) {
- result += QStringLiteral("lib");
- result += QLatin1StringView(name);
- result += qtLibInfix;
- }
- result += sharedLibrarySuffix(platform);
+ result += QLatin1StringView(name);
+ result += infix;
+ if (debug && platformHasDebugSuffix(platform))
+ result += u'd';
+ result += sharedLibrarySuffix();
return result;
}
@@ -1081,29 +1326,51 @@ static QString vcRedistDir()
return QString();
}
-static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned short machineArch)
+static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
{
+ //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found.
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 bool isClang = platform == WindowsDesktopClangMinGW;
+ QStringList filters;
+ const QString suffix = u'*' + sharedLibrarySuffix();
+ for (const auto &minGWRuntime : runtimeFilters)
+ filters.append(minGWRuntime + suffix);
+
+ QFileInfoList dlls = QDir(qtBinDir).entryInfoList(filters, QDir::Files);
+ if (dlls.isEmpty()) {
+ std::wcerr << "Warning: Runtime libraries not found in Qt binary folder, defaulting to looking in path\n";
+ const QString binaryPath = isClang ? findInPath("clang++.exe"_L1) : findInPath("g++.exe"_L1);
+ if (binaryPath.isEmpty()) {
+ std::wcerr << "Warning: Cannot find " << (isClang ? "Clang" : "GCC") << " installation directory, " << (isClang ? "clang++" : "g++") << ".exe must be in the path\n";
+ return {};
}
- const QString binPath = QFileInfo(gcc).absolutePath();
- QStringList filters;
- const QString suffix = u'*' + sharedLibrarySuffix(platform);
- for (auto minGwRuntime : minGwRuntimes)
- filters.append(QLatin1StringView(minGwRuntime) + suffix);
- const QFileInfoList &dlls = QDir(binPath).entryInfoList(filters, QDir::Files);
- for (const QFileInfo &dllFi : dlls)
- result.append(dllFi.absoluteFilePath());
+ const QString binaryFolder = QFileInfo(binaryPath).absolutePath();
+ dlls = QDir(binaryFolder).entryInfoList(filters, QDir::Files);
}
+
+ for (const QFileInfo &dllFi : dlls)
+ result.append(dllFi.absoluteFilePath());
+
+ return result;
+}
+
+static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
+{
+ QStringList result;
+ switch (platform) {
+ case WindowsDesktopMinGW: {
+ const QStringList minGWRuntimes = { "*gcc_"_L1, "*stdc++"_L1, "*winpthread"_L1 };
+ result.append(findMinGWRuntimePaths(qtBinDir, platform, minGWRuntimes));
+ break;
+ }
+ case WindowsDesktopClangMinGW: {
+ const QStringList clangMinGWRuntimes = { "*unwind"_L1, "*c++"_L1 };
+ result.append(findMinGWRuntimePaths(qtBinDir, platform, clangMinGWRuntimes));
break;
+ }
#ifdef Q_OS_WIN
- case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages.
+ case WindowsDesktopMsvcIntel:
+ case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages.
QString vcRedistDirName = vcRedistDir();
if (vcRedistDirName.isEmpty())
break;
@@ -1159,16 +1426,6 @@ static inline int qtVersion(const QMap<QString, QString> &qtpathsVariables)
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 qsizetype startPos = path.lastIndexOf(u'/') + 8;
- qsizetype endPos = path.lastIndexOf(u'.');
- 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)
@@ -1201,16 +1458,14 @@ static QString getIcuVersion(const QString &libName)
}
static DeployResult deploy(const Options &options, const QMap<QString, QString> &qtpathsVariables,
- QString *errorMessage)
+ const PluginInformation &pluginInfo, QString *errorMessage)
{
DeployResult result;
const QChar slash = u'/';
const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
- const QString libraryLocation = options.platform == Unix
- ? qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBS"))
- : qtBinDir;
+ const QString libraryLocation = qtBinDir;
const QString infix = qtpathsVariables.value(QLatin1StringView(qmakeInfixKey));
const int version = qtVersion(qtpathsVariables);
Q_UNUSED(version);
@@ -1257,12 +1512,10 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// 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 < dependentQtLibs.size(); ++m) {
- const quint64 module = qtModule(dependentQtLibs.at(m), infix);
- result.directlyUsedQtLibraries[module] = 1;
- if (module == QtCoreModuleId)
- qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform);
+ const qint64 module = qtModule(dependentQtLibs.at(m), infix);
+ if (module >= 0)
+ result.directlyUsedQtLibraries[module] = 1;
}
const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
@@ -1291,7 +1544,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
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);
+ QStringList icuLibs = findDependentLibraries(qtLib, 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.
@@ -1300,7 +1553,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
if (optVerboseLevel > 1)
std::wcout << "Adding ICU version " << icuVersion << '\n';
QString icuLib = QStringLiteral("icudt") + icuVersion
- + QLatin1StringView(windowsSharedLibrarySuffix);;
+ + QLatin1StringView(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) {
@@ -1373,8 +1626,9 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// 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] = 1;
+ const qint64 module = qtModule(dependentQtLibs.at(i), infix);
+ if (module >= 0)
+ result.usedQtLibraries[module] = 1;
else
deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
}
@@ -1385,19 +1639,34 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
disabled[QtQmlModuleId] = 1;
disabled[QtQuickModuleId] = 1;
}
+
+ QStringList openSslLibs;
+ if (!options.openSslRootDirectory.isEmpty()) {
+ openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
+ if (openSslLibs.isEmpty()) {
+ *errorMessage = QStringLiteral("Unable to find openSSL libraries in ")
+ + options.openSslRootDirectory;
+ return result;
+ }
+
+ deployedQtLibraries.append(openSslLibs);
+ }
+ const bool deployOpenSslPlugin = options.forceOpenSslPlugin || !openSslLibs.isEmpty();
+
const QStringList plugins = findQtPlugins(
&result.deployedQtLibraries,
// For non-QML applications, disable QML to prevent it from being pulled in by the
// qtaccessiblequick plugin.
- disabled,
- options.disabledPlugins, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
- libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin);
+ disabled, pluginInfo,
+ options.pluginSelections, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
+ libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
+ options.deployInsightTrackerPlugin, deployOpenSslPlugin);
// Apply options flags and re-add library names.
QString qtGuiLibrary;
for (const auto &qtModule : qtModuleEntries) {
if (result.deployedQtLibraries.test(qtModule.id)) {
- const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), qtLibInfix,
+ const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
options.platform, result.isDebug);
deployedQtLibraries.append(library);
if (qtModule.id == QtGuiModuleId)
@@ -1420,7 +1689,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
}
if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) {
- const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, options.platform, errorMessage);
+ const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty();
if (options.softwareRasterizer && !dependsOnOpenGl) {
const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1StringView(windowsSharedLibrarySuffix));
@@ -1435,15 +1704,28 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
deployedQtLibraries.push_back(d3dCompiler);
}
}
+ if (options.systemDxc) {
+ const QStringList dxcLibs = findDxc(options.platform, qtBinDir, wordSize);
+ if (!dxcLibs.isEmpty())
+ deployedQtLibraries.append(dxcLibs);
+ else
+ std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
+ }
} // Windows
+ // Add FFmpeg if we deploy the FFmpeg backend
+ if (options.ffmpeg
+ && !plugins.filter(QStringLiteral("ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
+ deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
+ }
+
// 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));
+ libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug, machineArch));
for (const QString &qtLib : std::as_const(libraries)) {
if (!updateLibrary(qtLib, targetPath, options, errorMessage))
return result;
@@ -1451,7 +1733,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
#if !QT_CONFIG(relocatable)
if (options.patchQt && !options.dryRun) {
- const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", qtLibInfix,
+ const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", infix,
options.platform, result.isDebug)).fileName();
if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
std::wcerr << "Warning: " << *errorMessage << '\n';
@@ -1509,7 +1791,8 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
unsigned qmlDirectoryFileFlags = 0;
if (options.deployPdb)
qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
- if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform,
+ if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
+ options.platform,
debugMatchMode,
qmlDirectoryFileFlags),
installPath, updateFileFlags, options.json, errorMessage)) {
@@ -1533,7 +1816,8 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
}
static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, const char *binaryName,
- const Options &sourceOptions, QString *errorMessage)
+ const PluginInformation &pluginInfo, const Options &sourceOptions,
+ QString *errorMessage)
{
// Copy the web process and its dependencies
const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform);
@@ -1545,23 +1829,26 @@ static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, con
options.binaries.append(options.directory + u'/' + webProcess);
options.quickImports = false;
options.translations = false;
- return deploy(options, qtpathsVariables, errorMessage);
+ return deploy(options, qtpathsVariables, pluginInfo, errorMessage);
}
static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
- const Options &options, bool isDebug, QString *errorMessage)
+ const PluginInformation &pluginInfo, 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"};
+ static const char *installDataFiles[] = { "icudtl.dat",
+ "qtwebengine_devtools_resources.pak",
+ "qtwebengine_resources.pak",
+ "qtwebengine_resources_100p.pak",
+ "qtwebengine_resources_200p.pak",
+ isDebug ? "v8_context_snapshot.debug.bin"
+ : "v8_context_snapshot.bin" };
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))
+ if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
return false;
const QString resourcesSubDir = QStringLiteral("/resources");
const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_DATA"))
@@ -1636,18 +1923,36 @@ int main(int argc, char **argv)
const QMap<QString, QString> qtpathsVariables =
queryQtPaths(options.qtpathsBinary, &errorMessage);
const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
- options.platform = platformFromMkSpec(xSpec);
- if (options.platform == UnknownPlatform) {
- std::wcerr << "Unsupported platform " << xSpec << '\n';
- return 1;
- }
-
if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
|| !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
std::wcerr << "Unable to query qtpaths: " << errorMessage << '\n';
return 1;
}
+ options.platform = platformFromMkSpec(xSpec);
+ // We are on MSVC and not crosscompiling. We need the host arch
+ if (options.platform == WindowsDesktopMsvc) {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ switch (si.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ case PROCESSOR_ARCHITECTURE_IA64:
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ options.platform |= IntelBased;
+ break;
+ case PROCESSOR_ARCHITECTURE_ARM:
+ case PROCESSOR_ARCHITECTURE_ARM64:
+ options.platform |= ArmBased;
+ break;
+ default:
+ options.platform = UnknownPlatform;
+ }
+ }
+ if (options.platform == UnknownPlatform) {
+ std::wcerr << "Unsupported platform " << xSpec << '\n';
+ return 1;
+ }
+
// Read the Qt module information from the Qt installation directory.
const QString modulesDir
= qtpathsVariables.value(QLatin1String("QT_INSTALL_ARCHDATA"))
@@ -1661,6 +1966,10 @@ int main(int argc, char **argv)
}
assignKnownModuleIds();
+ // Read the Qt plugin types information from the Qt installation directory.
+ PluginInformation pluginInfo{};
+ pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
+
// Parse the full command line.
{
QCommandLineParser parser;
@@ -1668,8 +1977,12 @@ int main(int argc, char **argv)
const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
if (result & CommandLineParseError)
std::wcerr << errorMessage << "\n\n";
+ if (result & CommandLineVersionRequested) {
+ std::fputs(QT_VERSION_STR "\n", stdout);
+ return 0;
+ }
if (result & CommandLineParseHelpRequested)
- std::fputs(qPrintable(helpText(parser)), stdout);
+ std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
if (result & CommandLineParseError)
return 1;
if (result & CommandLineParseHelpRequested)
@@ -1687,14 +2000,15 @@ int main(int argc, char **argv)
return 1;
}
- const DeployResult result = deploy(options, qtpathsVariables, &errorMessage);
+ const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
if (!result) {
std::wcerr << errorMessage << '\n';
return 1;
}
if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
- if (!deployWebEngineCore(qtpathsVariables, options, result.isDebug, &errorMessage)) {
+ if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
+ &errorMessage)) {
std::wcerr << errorMessage << '\n';
return 1;
}
diff --git a/src/tools/windeployqt/qmlutils.cpp b/src/tools/windeployqt/qmlutils.cpp
index 5104af0194..a7e63e7470 100644
--- a/src/tools/windeployqt/qmlutils.cpp
+++ b/src/tools/windeployqt/qmlutils.cpp
@@ -67,7 +67,8 @@ static void findFileRecursion(const QDir &directory, Platform platform,
const QFileInfoList &subDirs = directory.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
for (const QFileInfo &subDirFi : subDirs) {
QDir subDirectory(subDirFi.absoluteFilePath());
- if (subDirectory.isReadable())
+ // Don't enter other QML modules when recursing!
+ if (subDirectory.isReadable() && !subDirectory.exists(QStringLiteral("qmldir")))
findFileRecursion(subDirectory, platform, debugMatchMode, matches);
}
}
diff --git a/src/tools/windeployqt/qtmoduleinfo.cpp b/src/tools/windeployqt/qtmoduleinfo.cpp
index 57aa8e54a0..b928a64478 100644
--- a/src/tools/windeployqt/qtmoduleinfo.cpp
+++ b/src/tools/windeployqt/qtmoduleinfo.cpp
@@ -4,7 +4,7 @@
#include "qtmoduleinfo.h"
#include "utils.h"
-#include <QDirIterator>
+#include <QDirListing>
#include <QJsonDocument>
#include <QJsonArray>
#include <QDebug>
@@ -134,14 +134,12 @@ bool QtModuleInfoStore::populate(const QString &modulesDir, const QString &trans
}
// Read modules, and assign a bit as ID.
- QDirIterator dit(modulesDir, { QLatin1String("*.json") }, QDir::Files);
- while (dit.hasNext()) {
- QString filePath = dit.next();
- QtModule module = moduleFromJsonFile(filePath, errorString);
+ for (const auto &dirEntry : QDirListing(modulesDir, {u"*.json"_s}, QDir::Files)) {
+ QtModule module = moduleFromJsonFile(dirEntry.filePath(), errorString);
if (!errorString->isEmpty())
return false;
- if (module.internal)
- continue;
+ if (module.internal && module.name.endsWith(QStringLiteral("Private")))
+ module.name.chop(7);
module.id = modules.size();
if (module.id == QtModule::InvalidId) {
*errorString = "Internal Error: too many modules for ModuleBitset to hold."_L1;
diff --git a/src/tools/windeployqt/qtplugininfo.cpp b/src/tools/windeployqt/qtplugininfo.cpp
new file mode 100644
index 0000000000..1deaa35f35
--- /dev/null
+++ b/src/tools/windeployqt/qtplugininfo.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtplugininfo.h"
+
+#include <QDir>
+
+static PluginDetection determinePluginLibrary(const QDir &platformPluginDir, const QString &infix)
+{
+ // Use the platform plugin to determine which dlls are there (release/debug/both)
+ QString platformReleaseFilter(QStringLiteral("qwindows"));
+ if (!infix.isEmpty())
+ platformReleaseFilter += infix;
+ QString platformFilter = platformReleaseFilter + u'*';
+ platformFilter += sharedLibrarySuffix();
+
+ const QFileInfoList &dlls =
+ platformPluginDir.entryInfoList(QStringList(platformFilter), QDir::Files);
+ if (dlls.size() == 1) {
+ const QFileInfo dllFi = dlls.first();
+ const bool hasDebugDlls =
+ dllFi.fileName() == QString(platformReleaseFilter + sharedLibrarySuffix()) ? false
+ : true;
+ return (hasDebugDlls ? PluginDetection::DebugOnly : PluginDetection::ReleaseOnly);
+ } else {
+ return PluginDetection::DebugAndRelease;
+ }
+}
+
+static QStringList findPluginNames(const QDir &pluginDir, const PluginDetection libraryType,
+ const Platform &platform)
+{
+ QString errorMessage{};
+ QStringList result{};
+ QString filter{};
+ filter += u"*";
+ filter += sharedLibrarySuffix();
+
+ const QFileInfoList &dlls =
+ pluginDir.entryInfoList(QStringList(filter), QDir::Files, QDir::Name);
+
+ for (const QFileInfo &dllFi : dlls) {
+ QString plugin = dllFi.fileName();
+ const int dotIndex = plugin.lastIndexOf(u'.');
+ // We don't need the .dll for the name
+ plugin = plugin.first(dotIndex);
+
+ if (libraryType == PluginDetection::DebugAndRelease) {
+ bool isDebugDll{};
+ if (!readPeExecutable(dllFi.absoluteFilePath(), &errorMessage, 0, 0, &isDebugDll,
+ (platform == WindowsDesktopMinGW))) {
+ std::wcerr << "Warning: Unable to read "
+ << QDir::toNativeSeparators(dllFi.absoluteFilePath()) << ": "
+ << errorMessage;
+ }
+ if (isDebugDll && platformHasDebugSuffix(platform))
+ plugin.removeLast();
+ }
+ else if (libraryType == PluginDetection::DebugOnly)
+ plugin.removeLast();
+
+ if (!result.contains(plugin))
+ result.append(plugin);
+ }
+ return result;
+}
+
+bool PluginInformation::isTypeForPlugin(const QString &type, const QString &plugin) const
+{
+ return m_pluginMap.at(plugin) == type;
+}
+
+void PluginInformation::populatePluginToType(const QDir &pluginDir, const QStringList &plugins)
+{
+ for (const QString &plugin : plugins)
+ m_pluginMap.insert({ plugin, pluginDir.dirName() });
+}
+
+void PluginInformation::generateAvailablePlugins(const QMap<QString, QString> &qtPathsVariables,
+ const Platform &platform)
+{
+ const QDir pluginTypesDir(qtPathsVariables.value(QLatin1String("QT_INSTALL_PLUGINS")));
+ const QDir platformPluginDir(pluginTypesDir.absolutePath() + QStringLiteral("/platforms"));
+ const QString infix(qtPathsVariables.value(QLatin1String(qmakeInfixKey)));
+ const PluginDetection debugDetection = determinePluginLibrary(platformPluginDir, infix);
+
+ const QFileInfoList &pluginTypes =
+ pluginTypesDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ for (const QFileInfo &pluginType : pluginTypes) {
+ const QString pluginTypeName = pluginType.baseName();
+ m_typeMap.insert({ pluginTypeName, QStringList{} });
+ const QStringList plugins =
+ findPluginNames(pluginType.absoluteFilePath(), debugDetection, platform);
+ m_typeMap.at(pluginTypeName) = plugins;
+ populatePluginToType(pluginTypeName, plugins);
+ }
+ if (!m_typeMap.size() || !m_pluginMap.size())
+ std::wcerr << "Warning: could not parse available plugins properly, plugin "
+ "inclusion/exclusion options will not work\n";
+}
diff --git a/src/tools/windeployqt/qtplugininfo.h b/src/tools/windeployqt/qtplugininfo.h
new file mode 100644
index 0000000000..420b2b5e1a
--- /dev/null
+++ b/src/tools/windeployqt/qtplugininfo.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTPLUGININFO_H
+#define QTPLUGININFO_H
+
+#include "utils.h"
+
+#include <QString>
+#include <QStringList>
+
+#include <unordered_map>
+
+enum class PluginDetection
+{
+ DebugOnly,
+ ReleaseOnly,
+ DebugAndRelease
+};
+
+struct PluginSelections
+{
+ QStringList disabledPluginTypes;
+ QStringList enabledPluginTypes;
+ QStringList excludedPlugins;
+ QStringList includedPlugins;
+ bool includeSoftPlugins = false;
+};
+
+class PluginInformation
+{
+public:
+ PluginInformation() = default;
+
+ bool isTypeForPlugin(const QString &type, const QString &plugin) const;
+
+ void generateAvailablePlugins(const QMap<QString, QString> &qtPathsVariables,
+ const Platform &platform);
+ void populatePluginToType(const QDir &pluginDir, const QStringList &plugins);
+
+ const std::unordered_map<QString, QStringList> &typeMap() const { return m_typeMap; }
+
+private:
+ std::unordered_map<QString, QStringList> m_typeMap;
+ std::unordered_map<QString, QString> m_pluginMap;
+};
+
+#endif
diff --git a/src/tools/windeployqt/utils.cpp b/src/tools/windeployqt/utils.cpp
index d54d075894..5141119254 100644
--- a/src/tools/windeployqt/utils.cpp
+++ b/src/tools/windeployqt/utils.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "utils.h"
-#include "elfreader.h"
#include <QtCore/QString>
#include <QtCore/QDebug>
@@ -95,7 +94,7 @@ QStringList findSharedLibraries(const QDir &directory, Platform platform,
nameFilter += u'*';
if (debugMatchMode == MatchDebug && platformHasDebugSuffix(platform))
nameFilter += u'd';
- nameFilter += sharedLibrarySuffix(platform);
+ nameFilter += sharedLibrarySuffix();
QStringList result;
QString errorMessage;
const QFileInfoList &dlls = directory.entryInfoList(QStringList(nameFilter), QDir::Files);
@@ -424,14 +423,18 @@ const char *qmakeInfixKey = "QT_INFIX";
QMap<QString, QString> queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
{
const QString binary = !qtpathsBinary.isEmpty() ? qtpathsBinary : QStringLiteral("qtpaths");
+ const QString colonSpace = QStringLiteral(": ");
QByteArray stdOut;
QByteArray stdErr;
unsigned long exitCode = 0;
- if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut, &stdErr, errorMessage))
+ if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut,
+ &stdErr, errorMessage)) {
+ *errorMessage = QStringLiteral("Error running binary ") + binary + colonSpace + *errorMessage;
return QMap<QString, QString>();
+ }
if (exitCode) {
*errorMessage = binary + QStringLiteral(" returns ") + QString::number(exitCode)
- + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr);
+ + colonSpace + QString::fromLocal8Bit(stdErr);
return QMap<QString, QString>();
}
const QString output = QString::fromLocal8Bit(stdOut).trimmed().remove(u'\r');
@@ -467,7 +470,7 @@ QMap<QString, QString> queryQtPaths(const QString &qtpathsBinary, QString *error
}
} else {
std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(qconfigPriFile.fileName())
- << ": " << qconfigPriFile.errorString()<< '\n';
+ << colonSpace << qconfigPriFile.errorString()<< '\n';
}
return result;
}
@@ -553,37 +556,6 @@ bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
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)
@@ -705,13 +677,23 @@ static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &de
qsizetype pos = 0;
if (lib.startsWith("MSVCR"_L1, Qt::CaseInsensitive)
|| lib.startsWith("MSVCP"_L1, Qt::CaseInsensitive)
- || lib.startsWith("VCRUNTIME"_L1, Qt::CaseInsensitive)) {
+ || lib.startsWith("VCRUNTIME"_L1, Qt::CaseInsensitive)
+ || lib.startsWith("VCCORLIB"_L1, Qt::CaseInsensitive)
+ || lib.startsWith("CONCRT"_L1, Qt::CaseInsensitive)
+ || lib.startsWith("UCRTBASE"_L1, Qt::CaseInsensitive)) {
qsizetype lastDotPos = lib.lastIndexOf(u'.');
pos = -1 == lastDotPos ? 0 : lastDotPos - 1;
}
- if (pos > 0 && lib.contains("_app"_L1, Qt::CaseInsensitive))
- pos -= 4;
+ if (pos > 0) {
+ const auto removeExtraSuffix = [&lib, &pos](const QString &suffix) -> void {
+ if (lib.contains(suffix, Qt::CaseInsensitive))
+ pos -= suffix.size();
+ };
+ removeExtraSuffix("_app"_L1);
+ removeExtraSuffix("_atomic_wait"_L1);
+ removeExtraSuffix("_codecvt_ids"_L1);
+ }
if (pos)
return lib.at(pos).toLower() == u'd' ? MsvcDebugRuntime : MsvcReleaseRuntime;
@@ -720,32 +702,43 @@ static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &de
}
template <class ImageNtHeader>
+inline QStringList determineDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
+ QString *errorMessage)
+{
+ return readImportSections(nth, fileMemory, errorMessage);
+}
+
+template <class ImageNtHeader>
+inline bool determineDebug(const ImageNtHeader *nth, const void *fileMemory,
+ QStringList *dependentLibrariesIn, QString *errorMessage)
+{
+ if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
+ return false;
+
+ const QStringList dependentLibraries = dependentLibrariesIn != nullptr ?
+ *dependentLibrariesIn :
+ determineDependentLibs(nth, fileMemory, errorMessage);
+
+ const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+ // When an MSVC debug entry is present, check whether the debug runtime
+ // is actually used to detect -release / -force-debug-info builds.
+ const MsvcDebugRuntimeResult msvcrt = checkMsvcDebugRuntime(dependentLibraries);
+ if (msvcrt == NoMsvcRuntime)
+ return hasDebugEntry;
+ else
+ return hasDebugEntry && msvcrt == MsvcDebugRuntime;
+}
+
+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.
- const MsvcDebugRuntimeResult msvcrt = checkMsvcDebugRuntime(dependentLibraries);
- if (msvcrt == NoMsvcRuntime)
- *isDebugIn = hasDebugEntry;
- else
- *isDebugIn = hasDebugEntry && msvcrt == MsvcDebugRuntime;
- }
- }
+ *dependentLibrariesIn = determineDependentLibs(nth, fileMemory, errorMessage);
+
+ if (isDebugIn)
+ *isDebugIn = determineDebug(nth, fileMemory, dependentLibrariesIn, errorMessage);
}
// Read a PE executable and determine dependent libraries, word size
@@ -799,10 +792,10 @@ bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage
*wordSizeIn = wordSize;
if (wordSize == 32) {
determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders),
- fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
+ fileMemory, dependentLibrariesIn, isDebugIn, errorMessage);
} else {
determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders),
- fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
+ fileMemory, dependentLibrariesIn, isDebugIn, errorMessage);
}
if (machineArchIn)
@@ -885,6 +878,53 @@ QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wor
return QString();
}
+QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
+{
+ QStringList results;
+ const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
+ const QString suffix = QLatin1StringView(windowsSharedLibrarySuffix);
+ for (QString prefix : { QStringLiteral("dxcompiler"), QStringLiteral("dxil") }) {
+ QString name = prefix + suffix;
+ if (!kitDir.isEmpty()) {
+ QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
+ if (platform.testFlag(ArmBased)) {
+ redistDirPath += wordSize == 32 ? QStringLiteral("arm") : QStringLiteral("arm64");
+ } else {
+ redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
+ }
+ QDir redistDir(redistDirPath);
+ if (redistDir.exists()) {
+ const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + u'*' + suffix), QDir::Files);
+ if (!files.isEmpty()) {
+ results.append(files.front().absoluteFilePath());
+ continue;
+ }
+ }
+ }
+ // Check the bin directory of the Qt SDK (in case it is shadowed by the
+ // Windows system directory in PATH).
+ const QFileInfo fi(qtBinDir + u'/' + name);
+ if (fi.isFile()) {
+ results.append(fi.absoluteFilePath());
+ continue;
+ }
+ // Try to find it in the PATH (e.g. the Vulkan SDK ships these, even if Windows itself doesn't).
+ if (platform.testFlag(IntelBased)) {
+ QString errorMessage;
+ unsigned detectedWordSize;
+ const QString dll = findInPath(name);
+ if (!dll.isEmpty()
+ && readPeExecutable(dll, &errorMessage, 0, &detectedWordSize, 0)
+ && detectedWordSize == wordSize)
+ {
+ results.append(dll);
+ continue;
+ }
+ }
+ }
+ return results;
+}
+
#else // Q_OS_WIN
bool readPeExecutable(const QString &, QString *errorMessage,
@@ -899,6 +939,11 @@ QString findD3dCompiler(Platform, const QString &, unsigned)
return QString();
}
+QStringList findDxc(Platform, const QString &, unsigned)
+{
+ return QStringList();
+}
+
#endif // !Q_OS_WIN
// Search for "qt_prfxpath=xxxx" in \a path, and replace it with "qt_prfxpath=."
diff --git a/src/tools/windeployqt/utils.h b/src/tools/windeployqt/utils.h
index 5bf2cde111..fb3ba0b40b 100644
--- a/src/tools/windeployqt/utils.h
+++ b/src/tools/windeployqt/utils.h
@@ -20,7 +20,6 @@ QT_BEGIN_NAMESPACE
enum PlatformFlag {
// OS
WindowsBased = 0x00001,
- UnixBased = 0x00002,
// CPU
IntelBased = 0x00010,
ArmBased = 0x00020,
@@ -30,11 +29,12 @@ enum PlatformFlag {
ClangMsvc = 0x00400,
ClangMinGW = 0x00800,
// Platforms
- WindowsDesktopMsvc = WindowsBased + IntelBased + Msvc,
+ WindowsDesktopMsvc = WindowsBased + Msvc,
+ WindowsDesktopMsvcIntel = WindowsDesktopMsvc + IntelBased,
+ WindowsDesktopMsvcArm = WindowsDesktopMsvc + ArmBased,
WindowsDesktopMinGW = WindowsBased + IntelBased + MinGW,
WindowsDesktopClangMsvc = WindowsBased + IntelBased + ClangMsvc,
WindowsDesktopClangMinGW = WindowsBased + IntelBased + ClangMinGW,
- Unix = UnixBased,
UnknownPlatform
};
@@ -68,7 +68,7 @@ inline std::wostream &operator<<(std::wostream &str, const QString &s)
// Container class for JSON output
class JsonOutput
{
- using SourceTargetMapping = QPair<QString, QString>;
+ using SourceTargetMapping = std::pair<QString, QString>;
using SourceTargetMappings = QList<SourceTargetMapping>;
public:
@@ -137,9 +137,8 @@ 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 QLatin1StringView((platform & WindowsBased) ? windowsSharedLibrarySuffix : unixSharedLibrarySuffix); }
+inline QString sharedLibrarySuffix() { return QLatin1StringView(windowsSharedLibrarySuffix); }
bool isBuildDirectory(Platform platform, const QString &dirName);
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage);
@@ -170,19 +169,6 @@ bool runProcess(const QString &binary, const QStringList &args,
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)
@@ -193,14 +179,15 @@ QString getArchString (unsigned short machineArch);
// Return dependent modules of executable files.
-inline QStringList findDependentLibraries(const QString &executableFileName, Platform platform, QString *errorMessage)
+inline QStringList findDependentLibraries(const QString &executableFileName, QString *errorMessage)
{
QStringList result;
- readExecutable(executableFileName, platform, errorMessage, &result);
+ readPeExecutable(executableFileName, errorMessage, &result);
return result;
}
QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize);
+QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize);
bool patchQtCore(const QString &path, QString *errorMessage);