summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qcore_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qcore_mac.mm')
-rw-r--r--src/corelib/kernel/qcore_mac.mm449
1 files changed, 279 insertions, 170 deletions
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index a3d1669b81..54c4373aed 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Petroules Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Petroules Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qcore_mac_p.h>
@@ -54,19 +18,57 @@
#include <cxxabi.h>
#include <objc/runtime.h>
#include <mach-o/dyld.h>
+#include <sys/sysctl.h>
+#include <spawn.h>
#include <qdebug.h>
+#include "qendian.h"
#include "qhash.h"
-#include "qpair.h"
#include "qmutex.h"
#include "qvarlengtharray.h"
#include "private/qlocking_p.h"
+#if !defined(QT_BOOTSTRAPPED)
+#include <thread>
+#endif
+
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+extern "C" {
+typedef uint32_t csr_config_t;
+extern int csr_get_active_config(csr_config_t *) __attribute__((weak_import));
+
+#ifdef QT_BUILD_INTERNAL
+int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t attrs, int disclaim)
+__attribute__((availability(macos,introduced=10.14),weak_import));
+pid_t responsibility_get_pid_responsible_for_pid(pid_t) __attribute__((weak_import));
+char *** _NSGetArgv();
+extern char **environ;
+#endif
+}
+#endif
+
QT_BEGIN_NAMESPACE
// --------------------------------------------------------------------------
+#if defined(Q_OS_MACOS)
+static void initializeStandardUserDefaults()
+{
+ // The standard user defaults are initialized from an ordered list of domains,
+ // as documented by NSUserDefaults.standardUserDefaults. This includes e.g.
+ // parsing command line arguments, such as -AppleFooBar "baz", as well as
+ // global defaults. To ensure that these defaults are available through
+ // the lower level Core Foundation preferences APIs, we need to initialize
+ // them as early as possible via the Foundation-API, as the lower level APIs
+ // do not do this initialization.
+ Q_UNUSED(NSUserDefaults.standardUserDefaults);
+}
+Q_CONSTRUCTOR_FUNCTION(initializeStandardUserDefaults);
+#endif
+
+// --------------------------------------------------------------------------
+
QCFString::operator QString() const
{
if (string.isEmpty() && value)
@@ -85,17 +87,35 @@ QCFString::operator CFStringRef() const
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
-bool AppleUnifiedLogger::willMirrorToStderr()
+bool AppleUnifiedLogger::preventsStderrLogging()
{
- // When running under Xcode or LLDB, one or more of these variables will
- // be set, which triggers libsystem_trace.dyld to log messages to stderr
- // as well, via_os_log_impl_mirror_to_stderr. Un-setting these variables
- // is not an option, as that would silence normal NSLog or os_log calls,
- // so instead we skip our own stderr output. See rdar://36919139.
+ // os_log will mirror to stderr if OS_ACTIVITY_DT_MODE is set,
+ // regardless of its value. OS_ACTIVITY_MODE then controls whether
+ // to include info and/or debug messages in this mirroring.
+ // For some reason, when launched under lldb (via Xcode or not),
+ // all levels are included.
+
+ // CFLog will normally log to both stderr, and via os_log.
+ // Setting CFLOG_FORCE_DISABLE_STDERR disables the stderr
+ // logging. Setting CFLOG_FORCE_STDERR will both duplicate
+ // CFLog's output to stderr, and trigger OS_ACTIVITY_DT_MODE,
+ // resulting in os_log calls also being mirrored to stderr.
+ // Setting ACTIVITY_LOG_STDERR has the same effect.
+
+ // NSLog is plumbed to CFLog, and will respond to the same
+ // environment variables as CFLog.
+
+ // We want to disable Qt's default stderr log handler when
+ // os_log has already mirrored to stderr.
static bool willMirror = qEnvironmentVariableIsSet("OS_ACTIVITY_DT_MODE")
- || qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
- || qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
- return willMirror;
+ || qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
+ || qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
+
+ // As well as when we suspect that Xcode is going to present os_log
+ // as structured log messages.
+ static bool disableStderr = qEnvironmentVariableIsSet("CFLOG_FORCE_DISABLE_STDERR");
+
+ return willMirror || disableStderr;
}
QT_MAC_WEAK_IMPORT(_os_log_default);
@@ -116,7 +136,7 @@ bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogCont
const bool isDefault = !context.category || !strcmp(context.category, "default");
os_log_t log = isDefault ? OS_LOG_DEFAULT :
- cachedLog(subsystem, QString::fromLatin1(context.category));
+ os_log_create(subsystem.toLatin1().constData(), context.category);
os_log_type_t logType = logTypeForMessageType(msgType);
if (!os_log_type_enabled(log, logType))
@@ -136,7 +156,7 @@ bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogCont
// system from redacting our log message.
os_log_with_type(log, logType, "%{public}s", qPrintable(message));
- return willMirrorToStderr();
+ return preventsStderrLogging();
}
os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
@@ -152,33 +172,31 @@ os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
return OS_LOG_TYPE_DEFAULT;
}
-os_log_t AppleUnifiedLogger::cachedLog(const QString &subsystem, const QString &category)
-{
- static QBasicMutex mutex;
- const auto locker = qt_scoped_lock(mutex);
+#endif // QT_USE_APPLE_UNIFIED_LOGGING
- static QHash<QPair<QString, QString>, os_log_t> logs;
- const auto cacheKey = qMakePair(subsystem, category);
- os_log_t log = logs.value(cacheKey);
+// -------------------------------------------------------------------------
- if (!log) {
- log = os_log_create(subsystem.toLatin1().constData(),
- category.toLatin1().constData());
- logs.insert(cacheKey, log);
+QDebug operator<<(QDebug dbg, id obj)
+{
+ if (!obj) {
+ // Match NSLog
+ dbg << "(null)";
+ return dbg;
+ }
- // Technically we should release the os_log_t resource when done
- // with it, but since we don't know when a category is disabled
- // we keep all cached os_log_t instances until shutdown, where
- // the OS will clean them up for us.
+ for (Class cls = object_getClass(obj); cls; cls = class_getSuperclass(cls)) {
+ if (cls == NSObject.class) {
+ dbg << static_cast<NSObject*>(obj);
+ return dbg;
+ }
}
- return log;
+ // Match NSObject.debugDescription
+ const QDebugStateSaver saver(dbg);
+ dbg.nospace() << '<' << object_getClassName(obj) << ": " << static_cast<void*>(obj) << '>';
+ return dbg;
}
-#endif // QT_USE_APPLE_UNIFIED_LOGGING
-
-// -------------------------------------------------------------------------
-
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
{
return dbg << (nsObject ?
@@ -215,63 +233,42 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY
QT_END_NAMESPACE
QT_USE_NAMESPACE
+
+#ifdef QT_DEBUG
@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject
@end
-@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) {
- NSAutoreleasePool **m_pool;
-}
-
-- (instancetype)initWithPool:(NSAutoreleasePool **)pool
-{
- if ((self = [self init]))
- m_pool = pool;
- return self;
-}
-
-- (void)dealloc
-{
- if (*m_pool) {
- // The pool is still valid, which means we're not being drained from
- // the corresponding QMacAutoReleasePool (see below).
-
- // QMacAutoReleasePool has only a single member, the NSAutoreleasePool*
- // so the address of that member is also the QMacAutoReleasePool itself.
- QMacAutoReleasePool *pool = reinterpret_cast<QMacAutoReleasePool *>(m_pool);
- qWarning() << "Premature drain of" << pool << "This can happen if you've allocated"
- << "the pool on the heap, or as a member of a heap-allocated object. This is not a"
- << "supported use of QMacAutoReleasePool, and might result in crashes when objects"
- << "in the pool are deallocated and then used later on under the assumption they"
- << "will be valid until" << pool << "has been drained.";
+@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker)
+@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
+#endif // QT_DEBUG
- // Reset the pool so that it's not drained again later on
- *m_pool = nullptr;
- }
+// Use the direct runtime interface to manage autorelease pools, as it
+// has less overhead then allocating NSAutoreleasePools, and allows for
+// a future where we use ARC (where NSAutoreleasePool is not allowed).
+// https://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support
- [super dealloc];
+extern "C" {
+void *objc_autoreleasePoolPush(void);
+void objc_autoreleasePoolPop(void *pool);
}
-@end
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
QT_BEGIN_NAMESPACE
QMacAutoReleasePool::QMacAutoReleasePool()
- : pool([[NSAutoreleasePool alloc] init])
+ : pool(objc_autoreleasePoolPush())
{
+#ifdef QT_DEBUG
+ static const bool debugAutoReleasePools = qEnvironmentVariableIsSet("QT_DARWIN_DEBUG_AUTORELEASEPOOLS");
+ if (!debugAutoReleasePools)
+ return;
+
Class trackerClass = [QMacAutoReleasePoolTracker class];
-#ifdef QT_DEBUG
void *poolFrame = nullptr;
- if (__builtin_available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) {
- void *frame;
- if (backtrace_from_fp(__builtin_frame_address(0), &frame, 1))
- poolFrame = frame;
- } else {
- static const int maxFrames = 3;
- void *callstack[maxFrames];
- if (backtrace(callstack, maxFrames) == maxFrames)
- poolFrame = callstack[maxFrames - 1];
- }
+ void *frames[2];
+ if (backtrace_from_fp(__builtin_frame_address(0), frames, 2))
+ poolFrame = frames[1];
if (poolFrame) {
Dl_info info;
@@ -297,30 +294,14 @@ QMacAutoReleasePool::QMacAutoReleasePool()
free((char*)symbolName);
}
}
-#endif
- [[[trackerClass alloc] initWithPool:
- reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease];
+ [[trackerClass new] autorelease];
+#endif // QT_DEBUG
}
QMacAutoReleasePool::~QMacAutoReleasePool()
{
- if (!pool) {
- qWarning() << "Prematurely drained pool" << this << "finally drained. Any objects belonging"
- << "to this pool have already been released, and have potentially been invalid since the"
- << "premature drain earlier on.";
- return;
- }
-
- // Save and reset pool before draining, so that the pool tracker can know
- // that it's being drained by its owning pool.
- NSAutoreleasePool *savedPool = static_cast<NSAutoreleasePool*>(pool);
- pool = nullptr;
-
- // Drain behaves the same as release, with the advantage that
- // if we're ever used in a garbage-collected environment, the
- // drain acts as a hint to the garbage collector to collect.
- [savedPool drain];
+ objc_autoreleasePoolPop(pool);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -342,15 +323,102 @@ QDebug operator<<(QDebug debug, const QCFString &string)
#ifdef Q_OS_MACOS
bool qt_mac_applicationIsInDarkMode()
{
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
- if (__builtin_available(macOS 10.14, *)) {
- auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
- @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
- return [appearance isEqualToString:NSAppearanceNameDarkAqua];
+ auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
+ @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
+ return [appearance isEqualToString:NSAppearanceNameDarkAqua];
+}
+
+bool qt_mac_runningUnderRosetta()
+{
+ int translated = 0;
+ auto size = sizeof(translated);
+ if (sysctlbyname("sysctl.proc_translated", &translated, &size, nullptr, 0) == 0)
+ return translated;
+ return false;
+}
+
+std::optional<uint32_t> qt_mac_sipConfiguration()
+{
+ static auto configuration = []() -> std::optional<uint32_t> {
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+ csr_config_t config;
+ if (csr_get_active_config && csr_get_active_config(&config) == 0)
+ return config;
+#endif
+
+ QIOType<io_registry_entry_t> nvram = IORegistryEntryFromPath(kIOMainPortDefault, "IODeviceTree:/options");
+ if (!nvram) {
+ qWarning("Failed to locate NVRAM entry in IO registry");
+ return {};
+ }
+
+ QCFType<CFTypeRef> csrConfig = IORegistryEntryCreateCFProperty(nvram,
+ CFSTR("csr-active-config"), kCFAllocatorDefault, IOOptionBits{});
+ if (!csrConfig)
+ return {}; // SIP config is not available
+
+ if (auto type = CFGetTypeID(csrConfig); type != CFDataGetTypeID()) {
+ qWarning() << "Unexpected SIP config type" << CFCopyTypeIDDescription(type);
+ return {};
+ }
+
+ QByteArray data = QByteArray::fromRawCFData(csrConfig.as<CFDataRef>());
+ if (data.size() != sizeof(uint32_t)) {
+ qWarning() << "Unexpected SIP config size" << data.size();
+ return {};
+ }
+
+ return qFromLittleEndian<uint32_t>(data.constData());
+ }();
+ return configuration;
+}
+
+#define CHECK_SPAWN(expr) \
+ if (int err = (expr)) { \
+ posix_spawnattr_destroy(&attr); \
+ return; \
}
+
+#ifdef QT_BUILD_INTERNAL
+void qt_mac_ensureResponsible()
+{
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+ if (!responsibility_get_pid_responsible_for_pid || !responsibility_spawnattrs_setdisclaim)
+ return;
+
+ auto pid = getpid();
+ if (responsibility_get_pid_responsible_for_pid(pid) == pid)
+ return; // Already responsible
+
+ posix_spawnattr_t attr = {};
+ CHECK_SPAWN(posix_spawnattr_init(&attr));
+
+ // Behave as exec
+ short flags = POSIX_SPAWN_SETEXEC;
+
+ // Reset signal mask
+ sigset_t no_signals;
+ sigemptyset(&no_signals);
+ CHECK_SPAWN(posix_spawnattr_setsigmask(&attr, &no_signals));
+ flags |= POSIX_SPAWN_SETSIGMASK;
+
+ // Reset all signals to their default handlers
+ sigset_t all_signals;
+ sigfillset(&all_signals);
+ CHECK_SPAWN(posix_spawnattr_setsigdefault(&attr, &all_signals));
+ flags |= POSIX_SPAWN_SETSIGDEF;
+
+ CHECK_SPAWN(posix_spawnattr_setflags(&attr, flags));
+
+ CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1));
+
+ char **argv = *_NSGetArgv();
+ posix_spawnp(&pid, argv[0], nullptr, &attr, argv, environ);
+ posix_spawnattr_destroy(&attr);
#endif
- return false;
}
+#endif // QT_BUILD_INTERNAL
+
#endif
bool qt_apple_isApplicationExtension()
@@ -381,32 +449,64 @@ AppleApplication *qt_apple_sharedApplication()
}
#endif
-#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED)
+#if !defined(QT_BOOTSTRAPPED)
+
+#if defined(Q_OS_MACOS)
+namespace {
+struct SandboxChecker
+{
+ SandboxChecker() : m_thread([this]{
+ m_isSandboxed = []{
+ QCFType<SecStaticCodeRef> staticCode = nullptr;
+ NSURL *executableUrl = NSBundle.mainBundle.executableURL;
+ if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
+ kSecCSDefaultFlags, &staticCode) != errSecSuccess)
+ return false;
+
+ QCFType<SecRequirementRef> sandboxRequirement;
+ if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"),
+ kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
+ return false;
+
+ if (SecStaticCodeCheckValidityWithErrors(staticCode,
+ kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess)
+ return false;
+
+ return true;
+ }();
+ })
+ {}
+ ~SandboxChecker() {
+ std::scoped_lock lock(m_mutex);
+ if (m_thread.joinable())
+ m_thread.detach();
+ }
+ bool isSandboxed() const {
+ std::scoped_lock lock(m_mutex);
+ if (m_thread.joinable())
+ m_thread.join();
+ return m_isSandboxed;
+ }
+private:
+ bool m_isSandboxed;
+ mutable std::thread m_thread;
+ mutable std::mutex m_mutex;
+};
+} // namespace
+static SandboxChecker sandboxChecker;
+#endif // Q_OS_MACOS
+
bool qt_apple_isSandboxed()
{
- static bool isSandboxed = []() {
- QCFType<SecStaticCodeRef> staticCode = nullptr;
- NSURL *bundleUrl = [[NSBundle mainBundle] bundleURL];
- if (SecStaticCodeCreateWithPath((__bridge CFURLRef)bundleUrl,
- kSecCSDefaultFlags, &staticCode) != errSecSuccess)
- return false;
-
- QCFType<SecRequirementRef> sandboxRequirement;
- if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"),
- kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
- return false;
-
- if (SecStaticCodeCheckValidityWithErrors(staticCode,
- kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess)
- return false;
-
- return true;
- }();
- return isSandboxed;
+#if defined(Q_OS_MACOS)
+ return sandboxChecker.isSandboxed();
+#else
+ return true; // All other Apple platforms
+#endif
}
QT_END_NAMESPACE
-@implementation NSObject (QtSandboxHelpers)
+@implementation NSObject (QtExtras)
- (id)qt_valueForPrivateKey:(NSString *)key
{
if (qt_apple_isSandboxed())
@@ -416,7 +516,7 @@ QT_END_NAMESPACE
}
@end
QT_BEGIN_NAMESPACE
-#endif
+#endif // !QT_BOOTSTRAPPED
#ifdef Q_OS_MACOS
/*
@@ -467,6 +567,9 @@ void qt_apple_check_os_version()
#elif defined(__TV_OS_VERSION_MIN_REQUIRED)
const char *os = "tvOS";
const int version = __TV_OS_VERSION_MIN_REQUIRED;
+#elif defined(__VISION_OS_VERSION_MIN_REQUIRED)
+ const char *os = "visionOS";
+ const int version = __VISION_OS_VERSION_MIN_REQUIRED;
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
const char *os = "iOS";
const int version = __IPHONE_OS_VERSION_MIN_REQUIRED;
@@ -474,10 +577,18 @@ void qt_apple_check_os_version()
const char *os = "macOS";
const int version = __MAC_OS_X_VERSION_MIN_REQUIRED;
#endif
- const NSOperatingSystemVersion required = (NSOperatingSystemVersion){
- version / 10000, version / 100 % 100, version % 100};
- const NSOperatingSystemVersion current = NSProcessInfo.processInfo.operatingSystemVersion;
- if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:required]) {
+
+ const auto required = QVersionNumber(version / 10000, version / 100 % 100, version % 100);
+ const auto current = QOperatingSystemVersion::current().version();
+
+#if defined(Q_OS_MACOS)
+ // Check for compatibility version, in which case we can't do a
+ // comparison to the deployment target, which might be e.g. 11.0
+ if (current.majorVersion() == 10 && current.minorVersion() >= 16)
+ return;
+#endif
+
+ if (current < required) {
NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
NSString *applicationName = plist[@"CFBundleDisplayName"];
if (!applicationName)
@@ -488,8 +599,8 @@ void qt_apple_check_os_version()
fprintf(stderr, "Sorry, \"%s\" cannot be run on this version of %s. "
"Qt requires %s %ld.%ld.%ld or later, you have %s %ld.%ld.%ld.\n",
applicationName.UTF8String, os,
- os, long(required.majorVersion), long(required.minorVersion), long(required.patchVersion),
- os, long(current.majorVersion), long(current.minorVersion), long(current.patchVersion));
+ os, long(required.majorVersion()), long(required.minorVersion()), long(required.microVersion()),
+ os, long(current.majorVersion()), long(current.minorVersion()), long(current.microVersion()));
exit(1);
}
@@ -608,7 +719,7 @@ QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machH
};
static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk, QOperatingSystemVersion::OSType osType) {
- return qMakePair(
+ return std::pair(
QOperatingSystemVersion(osType, dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff),
QOperatingSystemVersion(osType, sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff)
);
@@ -623,11 +734,9 @@ QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machH
|| loadCommand->cmd == LC_VERSION_MIN_TVOS || loadCommand->cmd == LC_VERSION_MIN_WATCHOS) {
auto versionCommand = reinterpret_cast<version_min_command *>(loadCommand);
return makeVersionTuple(versionCommand->version, versionCommand->sdk, osForLoadCommand(loadCommand->cmd));
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
} else if (loadCommand->cmd == LC_BUILD_VERSION) {
auto versionCommand = reinterpret_cast<build_version_command *>(loadCommand);
return makeVersionTuple(versionCommand->minos, versionCommand->sdk, osForPlatform(versionCommand->platform));
-#endif
}
commandCursor += loadCommand->cmdsize;
}