diff options
author | Jake Petroules <jake.petroules@qt.io> | 2017-08-12 22:19:07 -0700 |
---|---|---|
committer | Jake Petroules <jake.petroules@qt.io> | 2017-11-30 15:34:17 +0000 |
commit | 84d42028f11290bd38810c5167129e769cf0193b (patch) | |
tree | a50a761759f119839598fd5304d69f4c7ba2fdf4 /src/lib/qtprofilesetup | |
parent | 8567bbe434f643a651f9ff1df492c1be4011f1b6 (diff) |
Turn Qt.core.architecture into Qt.core.architectures
This allows us to properly support the Apple platforms (which are
capable of storing multiple architectures in a single library file) via
multiplexing.
Change-Id: I68702d58d8c3644d923dc1fbfd9a8dad3d69bba6
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src/lib/qtprofilesetup')
-rw-r--r-- | src/lib/qtprofilesetup/qtprofilesetup.cpp | 240 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/QtModule.qbs | 5 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/core.qbs | 5 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/dbus.qbs | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/gui.qbs | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/module.qbs | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/plugin.qbs | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/qml.qbs | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/quick.qbs | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/scxml.qbs | 2 |
10 files changed, 250 insertions, 14 deletions
diff --git a/src/lib/qtprofilesetup/qtprofilesetup.cpp b/src/lib/qtprofilesetup/qtprofilesetup.cpp index c9256dc3d..824b36838 100644 --- a/src/lib/qtprofilesetup/qtprofilesetup.cpp +++ b/src/lib/qtprofilesetup/qtprofilesetup.cpp @@ -52,6 +52,7 @@ #include <QtCore/qdir.h> #include <QtCore/qdiriterator.h> +#include <QtCore/qendian.h> #include <QtCore/qfile.h> #include <QtCore/qfileinfo.h> #include <QtCore/qlibrary.h> @@ -61,6 +62,25 @@ #include <queue> #include <regex> +#ifdef __APPLE__ +#include <ar.h> +#include <mach/machine.h> +#include <mach-o/fat.h> +#include <mach-o/loader.h> +#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101200 +#define FAT_MAGIC_64 0xcafebabf +#define FAT_CIGAM_64 0xbfbafeca +struct fat_arch_64 { + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + uint64_t offset; + uint64_t size; + uint32_t align; + uint32_t reserved; +}; +#endif +#endif + namespace qbs { using namespace Internal; @@ -147,18 +167,232 @@ static QByteArray minVersionJsString(const QString &minVersion) return utf8JSLiteral(minVersion); } -static QString extractQbsArch(const QtEnvironment &qtEnv) +#ifdef __APPLE__ +template <typename T = uint32_t> T readInt(QIODevice *ioDevice, bool *ok, + bool swap, bool peek = false) { + const auto bytes = peek + ? ioDevice->peek(sizeof(T)) + : ioDevice->read(sizeof(T)); + if (bytes.size() != sizeof(T)) { + if (ok) + *ok = false; + return T(); + } + if (ok) + *ok = true; + T n = *reinterpret_cast<const T *>(bytes.constData()); + return swap ? qbswap(n) : n; +} + +static QString archName(cpu_type_t cputype, cpu_subtype_t cpusubtype) +{ + switch (cputype) { + case CPU_TYPE_X86: + switch (cpusubtype) { + case CPU_SUBTYPE_X86_ALL: + return QStringLiteral("i386"); + default: + return QString(); + } + case CPU_TYPE_X86_64: + switch (cpusubtype) { + case CPU_SUBTYPE_X86_64_ALL: + return QStringLiteral("x86_64"); + case CPU_SUBTYPE_X86_64_H: + return QStringLiteral("x86_64h"); + default: + return QString(); + } + case CPU_TYPE_ARM: + switch (cpusubtype) { + case CPU_SUBTYPE_ARM_V7: + return QStringLiteral("armv7a"); + case CPU_SUBTYPE_ARM_V7S: + return QStringLiteral("armv7s"); + case CPU_SUBTYPE_ARM_V7K: + return QStringLiteral("armv7k"); + default: + return QString(); + } + case CPU_TYPE_ARM64: + switch (cpusubtype) { + case CPU_SUBTYPE_ARM64_ALL: + return QStringLiteral("arm64"); + default: + return QString(); + } + default: + return QString(); + } +} + +static QStringList detectMachOArchs(QIODevice *device) { + bool ok; + bool foundMachO = false; + qint64 pos = device->pos(); + + char ar_header[SARMAG]; + if (device->read(ar_header, SARMAG) == SARMAG) { + if (strncmp(ar_header, ARMAG, SARMAG) == 0) { + while (!device->atEnd()) { + static_assert(sizeof(ar_hdr) == 60, "sizeof(ar_hdr) != 60"); + ar_hdr header; + if (device->read(reinterpret_cast<char *>(&header), + sizeof(ar_hdr)) != sizeof(ar_hdr)) + return { }; + + // If the file name is stored in the "extended format" manner, + // the real filename is prepended to the data section, so skip that many bytes + int filenameLength = 0; + if (strncmp(header.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0) { + char arName[sizeof(header.ar_name)] = { 0 }; + memcpy(arName, header.ar_name + sizeof(AR_EFMT1) - 1, + sizeof(header.ar_name) - (sizeof(AR_EFMT1) - 1) - 1); + filenameLength = strtoul(arName, nullptr, 10); + if (device->read(filenameLength).size() != filenameLength) + return { }; + } + + switch (readInt(device, nullptr, false, true)) { + case MH_CIGAM: + case MH_CIGAM_64: + case MH_MAGIC: + case MH_MAGIC_64: + foundMachO = true; + break; + default: { + // Skip the data and go to the next archive member... + char szBuf[sizeof(header.ar_size) + 1] = { 0 }; + memcpy(szBuf, header.ar_size, sizeof(header.ar_size)); + int sz = static_cast<int>(strtoul(szBuf, nullptr, 10)); + if (sz % 2 != 0) + ++sz; + sz -= filenameLength; + const auto data = device->read(sz); + if (data.size() != sz) + return { }; + } + } + + if (foundMachO) + break; + } + } + } + + // Wasn't an archive file, so try a fat file + if (!foundMachO && !device->seek(pos)) + return QStringList(); + + pos = device->pos(); + + fat_header fatheader; + fatheader.magic = readInt(device, nullptr, false); + if (fatheader.magic == FAT_MAGIC || fatheader.magic == FAT_CIGAM || + fatheader.magic == FAT_MAGIC_64 || fatheader.magic == FAT_CIGAM_64) { + const bool swap = fatheader.magic == FAT_CIGAM || fatheader.magic == FAT_CIGAM_64; + const bool is64bit = fatheader.magic == FAT_MAGIC_64 || fatheader.magic == FAT_CIGAM_64; + fatheader.nfat_arch = readInt(device, &ok, swap); + if (!ok) + return QStringList(); + + QStringList archs; + + for (uint32_t n = 0; n < fatheader.nfat_arch; ++n) { + fat_arch_64 fatarch; + static_assert(sizeof(fat_arch_64) == 32, "sizeof(fat_arch_64) != 32"); + static_assert(sizeof(fat_arch) == 20, "sizeof(fat_arch) != 20"); + const qint64 expectedBytes = is64bit ? sizeof(fat_arch_64) : sizeof(fat_arch); + if (device->read(reinterpret_cast<char *>(&fatarch), expectedBytes) != expectedBytes) + return QStringList(); + + if (swap) { + fatarch.cputype = qbswap(fatarch.cputype); + fatarch.cpusubtype = qbswap(fatarch.cpusubtype); + } + + const QString name = archName(fatarch.cputype, fatarch.cpusubtype); + if (name.isEmpty()) { + qWarning("Unknown cputype %d and cpusubtype %d", + fatarch.cputype, fatarch.cpusubtype); + return QStringList(); + } + archs.push_back(name); + } + + std::sort(archs.begin(), archs.end()); + return archs; + } + + // Wasn't a fat file, so we just read a thin Mach-O from the original offset + if (!device->seek(pos)) + return QStringList(); + + bool swap = false; + mach_header header; + header.magic = readInt(device, nullptr, swap); + switch (header.magic) { + case MH_CIGAM: + case MH_CIGAM_64: + swap = true; + break; + case MH_MAGIC: + case MH_MAGIC_64: + break; + default: + return QStringList(); + } + + header.cputype = static_cast<cpu_type_t>(readInt(device, &ok, swap)); + if (!ok) + return QStringList(); + + header.cpusubtype = static_cast<cpu_subtype_t>(readInt(device, &ok, swap)); + if (!ok) + return QStringList(); + + const QString name = archName(header.cputype, header.cpusubtype); + if (name.isEmpty()) { + qWarning("Unknown cputype %d and cpusubtype %d", + header.cputype, header.cpusubtype); + return { }; + } + return { name }; +} +#endif + +static QStringList extractQbsArchs(const QtModuleInfo &module, const QtEnvironment &qtEnv) +{ +#ifdef __APPLE__ + if (qtEnv.mkspecName.startsWith(QLatin1String("macx-"))) { + QStringList archs; + if (!module.libFilePathRelease.isEmpty()) { + QFile file(module.libFilePathRelease); + if (file.open(QIODevice::ReadOnly)) + archs = detectMachOArchs(&file); + else + qWarning("Failed to open %s for reading", + qUtf8Printable(module.libFilePathRelease)); + if (archs.isEmpty()) + qWarning("Could not detect architectures for module %s in Qt build (%s)", + qPrintable(module.name), qUtf8Printable(qtEnv.mkspecName)); + } + return archs; + } +#else + Q_UNUSED(module); +#endif QString qbsArch = canonicalArchitecture(qtEnv.architecture); if (qbsArch == QLatin1String("arm") && qtEnv.mkspecPath.contains(QLatin1String("android"))) qbsArch = QLatin1String("armv7a"); - return qbsArch; + return QStringList { qbsArch }; } static void replaceSpecialValues(QByteArray *content, const Profile &profile, const QtModuleInfo &module, const QtEnvironment &qtEnvironment) { - content->replace("@arch@", utf8JSLiteral(extractQbsArch(qtEnvironment))); + content->replace("@archs@", utf8JSLiteral(extractQbsArchs(module, qtEnvironment))); content->replace("@targetPlatform@", utf8JSLiteral(qbsTargetPlatformFromQtMkspec( qtEnvironment.mkspecName))); content->replace("@config@", utf8JSLiteral(qtEnvironment.configItems)); diff --git a/src/lib/qtprofilesetup/templates/QtModule.qbs b/src/lib/qtprofilesetup/templates/QtModule.qbs index 62bbc8649..cd7f57cba 100644 --- a/src/lib/qtprofilesetup/templates/QtModule.qbs +++ b/src/lib/qtprofilesetup/templates/QtModule.qbs @@ -4,9 +4,10 @@ import qbs.FileInfo Module { condition: (qbs.targetPlatform === targetPlatform || isCombinedUIKitBuild) && (!qbs.architecture - || architecture === qbs.architecture) + || architectures.contains(qbs.architecture) || !hasLibrary) readonly property bool isCombinedUIKitBuild: ["ios", "tvos", "watchos"].contains(targetPlatform) + && ["x86", "x86_64"].contains(qbs.architecture) && qbs.targetPlatform === targetPlatform + "-simulator" Depends { name: "cpp" } @@ -30,7 +31,7 @@ Module { property bool isStaticLibrary: false property bool isPlugin: false - property string architecture + property stringList architectures property string targetPlatform property stringList staticLibsDebug property stringList staticLibsRelease diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/src/lib/qtprofilesetup/templates/core.qbs index 5ebe86599..5a2225123 100644 --- a/src/lib/qtprofilesetup/templates/core.qbs +++ b/src/lib/qtprofilesetup/templates/core.qbs @@ -8,10 +8,11 @@ import "moc.js" as Moc import "qdoc.js" as Qdoc Module { - condition: (!qbs.architecture || architecture === qbs.architecture) && + condition: (!qbs.architecture || architectures.contains(qbs.architecture)) && (qbs.targetPlatform === targetPlatform || isCombinedUIKitBuild) readonly property bool isCombinedUIKitBuild: ["ios", "tvos", "watchos"].contains(targetPlatform) + && ["x86", "x86_64"].contains(qbs.architecture) && qbs.targetPlatform === targetPlatform + "-simulator" id: qtcore @@ -19,7 +20,7 @@ Module { Depends { name: "cpp" } version: @version@ - property string architecture: @arch@ + property stringList architectures: @archs@ property string targetPlatform: @targetPlatform@ property string libInfix: @libInfix@ property stringList config: @config@ diff --git a/src/lib/qtprofilesetup/templates/dbus.qbs b/src/lib/qtprofilesetup/templates/dbus.qbs index 3ef944cae..5cace7f4f 100644 --- a/src/lib/qtprofilesetup/templates/dbus.qbs +++ b/src/lib/qtprofilesetup/templates/dbus.qbs @@ -47,7 +47,7 @@ QtModule { } } - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ diff --git a/src/lib/qtprofilesetup/templates/gui.qbs b/src/lib/qtprofilesetup/templates/gui.qbs index df43a4b02..1653601ec 100644 --- a/src/lib/qtprofilesetup/templates/gui.qbs +++ b/src/lib/qtprofilesetup/templates/gui.qbs @@ -33,7 +33,7 @@ QtModule { } property string defaultQpaPlugin: @defaultQpaPlugin@ - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ diff --git a/src/lib/qtprofilesetup/templates/module.qbs b/src/lib/qtprofilesetup/templates/module.qbs index 9eaeeaaa8..4740e5d52 100644 --- a/src/lib/qtprofilesetup/templates/module.qbs +++ b/src/lib/qtprofilesetup/templates/module.qbs @@ -5,7 +5,7 @@ QtModule { qtModuleName: @name@ Depends { name: "Qt"; submodules: @dependencies@} - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ hasLibrary: @has_library@ staticLibsDebug: @staticLibsDebug@ diff --git a/src/lib/qtprofilesetup/templates/plugin.qbs b/src/lib/qtprofilesetup/templates/plugin.qbs index e67c7794c..ca9803b1b 100644 --- a/src/lib/qtprofilesetup/templates/plugin.qbs +++ b/src/lib/qtprofilesetup/templates/plugin.qbs @@ -6,7 +6,7 @@ QtPlugin { Depends { name: "Qt"; submodules: @dependencies@} className: @className@ - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ diff --git a/src/lib/qtprofilesetup/templates/qml.qbs b/src/lib/qtprofilesetup/templates/qml.qbs index 1f175dbf9..0ebc016f2 100644 --- a/src/lib/qtprofilesetup/templates/qml.qbs +++ b/src/lib/qtprofilesetup/templates/qml.qbs @@ -23,7 +23,7 @@ QtModule { readonly property string pluginListFilePathRelease: product.buildDirectory + "/plugins.list" hasLibrary: @has_library@ - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: (isStaticLibrary ? ['@' + pluginListFilePathDebug] : []).concat(@staticLibsDebug@) staticLibsRelease: (isStaticLibrary ? ['@' + pluginListFilePathRelease] : []).concat(@staticLibsRelease@) diff --git a/src/lib/qtprofilesetup/templates/quick.qbs b/src/lib/qtprofilesetup/templates/quick.qbs index 13951a883..539fbfee6 100644 --- a/src/lib/qtprofilesetup/templates/quick.qbs +++ b/src/lib/qtprofilesetup/templates/quick.qbs @@ -40,7 +40,7 @@ QtModule { Depends { name: "Qt"; submodules: @dependencies@.concat("qml-private") } hasLibrary: @has_library@ - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ diff --git a/src/lib/qtprofilesetup/templates/scxml.qbs b/src/lib/qtprofilesetup/templates/scxml.qbs index e64b4dc9b..98c3bd30f 100644 --- a/src/lib/qtprofilesetup/templates/scxml.qbs +++ b/src/lib/qtprofilesetup/templates/scxml.qbs @@ -45,7 +45,7 @@ QtModule { } } - architecture: @arch@ + architectures: @archs@ targetPlatform: @targetPlatform@ staticLibsDebug: @staticLibsDebug@ staticLibsRelease: @staticLibsRelease@ |