aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/qtprofilesetup
diff options
context:
space:
mode:
authorJake Petroules <jake.petroules@qt.io>2017-08-12 22:19:07 -0700
committerJake Petroules <jake.petroules@qt.io>2017-11-30 15:34:17 +0000
commit84d42028f11290bd38810c5167129e769cf0193b (patch)
treea50a761759f119839598fd5304d69f4c7ba2fdf4 /src/lib/qtprofilesetup
parent8567bbe434f643a651f9ff1df492c1be4011f1b6 (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.cpp240
-rw-r--r--src/lib/qtprofilesetup/templates/QtModule.qbs5
-rw-r--r--src/lib/qtprofilesetup/templates/core.qbs5
-rw-r--r--src/lib/qtprofilesetup/templates/dbus.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/gui.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/module.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/plugin.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/qml.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/quick.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/scxml.qbs2
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@