Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qcore_mac.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2014 Petroules Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <private/qcore_mac_p.h>
6
7#ifdef Q_OS_MACOS
8#include <AppKit/AppKit.h>
9#endif
10
11#if defined(QT_PLATFORM_UIKIT)
12#include <UIKit/UIKit.h>
13#endif
14
15#include <new>
16#include <execinfo.h>
17#include <dlfcn.h>
18#include <cxxabi.h>
19#include <objc/runtime.h>
20#include <mach-o/dyld.h>
21#include <sys/sysctl.h>
22#include <spawn.h>
23
24#include <qdebug.h>
25
26#include "qendian.h"
27#include "qhash.h"
28#include "qpair.h"
29#include "qmutex.h"
30#include "qvarlengtharray.h"
31#include "private/qlocking_p.h"
32
33#if !defined(QT_BOOTSTRAPPED)
34#include <thread>
35#endif
36
37#if !defined(QT_APPLE_NO_PRIVATE_APIS)
38extern "C" {
39typedef uint32_t csr_config_t;
41
42#ifdef QT_BUILD_INTERNAL
43int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t attrs, int disclaim)
44__attribute__((availability(macos,introduced=10.14),weak_import));
45pid_t responsibility_get_pid_responsible_for_pid(pid_t) __attribute__((weak_import));
46char *** _NSGetArgv();
47extern char **environ;
48#endif
49}
50#endif
51
53
54// --------------------------------------------------------------------------
55
57{
58 // The standard user defaults are initialized from an ordered list of domains,
59 // as documented by NSUserDefaults.standardUserDefaults. This includes e.g.
60 // parsing command line arguments, such as -AppleFooBar "baz", as well as
61 // global defaults. To ensure that these defaults are available through
62 // the lower level Core Foundation preferences APIs, we need to initialize
63 // them as early as possible via the Foundation-API, as the lower level APIs
64 // do not do this initialization.
65 Q_UNUSED(NSUserDefaults.standardUserDefaults);
66}
68
69// --------------------------------------------------------------------------
70
71QCFString::operator QString() const
72{
73 if (string.isEmpty() && value)
74 const_cast<QCFString*>(this)->string = QString::fromCFString(value);
75 return string;
76}
77
78QCFString::operator CFStringRef() const
79{
80 if (!value)
81 const_cast<QCFString*>(this)->value = string.toCFString();
82 return value;
83}
84
85// --------------------------------------------------------------------------
86
87#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
88
90{
91 // os_log will mirror to stderr if OS_ACTIVITY_DT_MODE is set,
92 // regardless of its value. OS_ACTIVITY_MODE then controls whether
93 // to include info and/or debug messages in this mirroring.
94 // For some reason, when launched under lldb (via Xcode or not),
95 // all levels are included.
96
97 // CFLog will normally log to both stderr, and via os_log.
98 // Setting CFLOG_FORCE_DISABLE_STDERR disables the stderr
99 // logging. Setting CFLOG_FORCE_STDERR will both duplicate
100 // CFLog's output to stderr, and trigger OS_ACTIVITY_DT_MODE,
101 // resulting in os_log calls also being mirrored to stderr.
102 // Setting ACTIVITY_LOG_STDERR has the same effect.
103
104 // NSLog is plumbed to CFLog, and will respond to the same
105 // environment variables as CFLog.
106
107 // We want to disable Qt's default stderr log handler when
108 // os_log has already mirrored to stderr.
109 static bool willMirror = qEnvironmentVariableIsSet("OS_ACTIVITY_DT_MODE")
110 || qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
111 || qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
112
113 // As well as when we suspect that Xcode is going to present os_log
114 // as structured log messages.
115 static bool disableStderr = qEnvironmentVariableIsSet("CFLOG_FORCE_DISABLE_STDERR");
116
117 return willMirror || disableStderr;
118}
119
120QT_MAC_WEAK_IMPORT(_os_log_default);
122 const QString &message, const QString &optionalSubsystem)
123{
124 QString subsystem = optionalSubsystem;
125 if (subsystem.isNull()) {
126 static QString bundleIdentifier = []() {
127 if (CFBundleRef bundle = CFBundleGetMainBundle()) {
128 if (CFStringRef identifier = CFBundleGetIdentifier(bundle))
129 return QString::fromCFString(identifier);
130 }
131 return QString();
132 }();
133 subsystem = bundleIdentifier;
134 }
135
136 const bool isDefault = !context.category || !strcmp(context.category, "default");
137 os_log_t log = isDefault ? OS_LOG_DEFAULT :
138 os_log_create(subsystem.toLatin1().constData(), context.category);
139 os_log_type_t logType = logTypeForMessageType(msgType);
140
141 if (!os_log_type_enabled(log, logType))
142 return false;
143
144 // Logging best practices says we should not include symbolication
145 // information or source file line numbers in messages, as the system
146 // will automatically captures this information. In our case, what
147 // the system captures is the call to os_log_with_type below, which
148 // isn't really useful, but we still don't want to include the context's
149 // info, as that would clutter the logging output. See rdar://35958308.
150
151 // The format must be a string constant, so we can't pass on the
152 // message. This means we won't be able to take advantage of the
153 // unified logging's custom format specifiers such as %{BOOL}d.
154 // We use the 'public' format specifier to prevent the logging
155 // system from redacting our log message.
156 os_log_with_type(log, logType, "%{public}s", qPrintable(message));
157
158 return preventsStderrLogging();
159}
160
161os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
162{
163 switch (msgType) {
164 case QtDebugMsg: return OS_LOG_TYPE_DEBUG;
165 case QtInfoMsg: return OS_LOG_TYPE_INFO;
166 case QtWarningMsg: return OS_LOG_TYPE_DEFAULT;
167 case QtCriticalMsg: return OS_LOG_TYPE_ERROR;
168 case QtFatalMsg: return OS_LOG_TYPE_FAULT;
169 }
170
171 return OS_LOG_TYPE_DEFAULT;
172}
173
174#endif // QT_USE_APPLE_UNIFIED_LOGGING
175
176// -------------------------------------------------------------------------
177
179{
180 if (!obj) {
181 // Match NSLog
182 dbg << "(null)";
183 return dbg;
184 }
185
186 for (Class cls = object_getClass(obj); cls; cls = class_getSuperclass(cls)) {
187 if (cls == NSObject.class) {
188 dbg << static_cast<NSObject*>(obj);
189 return dbg;
190 }
191 }
192
193 // Match NSObject.debugDescription
194 const QDebugStateSaver saver(dbg);
195 dbg.nospace() << '<' << object_getClassName(obj) << ": " << static_cast<void*>(obj) << '>';
196 return dbg;
197}
198
199QDebug operator<<(QDebug dbg, const NSObject *nsObject)
200{
201 return dbg << (nsObject ?
202 dbg.verbosity() > 2 ?
203 nsObject.debugDescription.UTF8String :
204 nsObject.description.UTF8String
205 : "NSObject(0x0)");
206}
207
208QDebug operator<<(QDebug dbg, CFStringRef stringRef)
209{
210 if (!stringRef)
211 return dbg << "CFStringRef(0x0)";
212
213 if (const UniChar *chars = CFStringGetCharactersPtr(stringRef))
214 dbg << QStringView(reinterpret_cast<const QChar *>(chars), CFStringGetLength(stringRef));
215 else
216 dbg << QString::fromCFString(stringRef);
217
218 return dbg;
219}
220
221// Prevents breaking the ODR in case we introduce support for more types
222// later on, and lets the user override our default QDebug operators.
223#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
224 __attribute__((weak)) Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType)
225
230
231// -------------------------------------------------------------------------
232
235
236#ifdef QT_DEBUG
237@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject
238@end
239
240@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker)
241@end
242QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
243#endif // QT_DEBUG
244
245// Use the direct runtime interface to manage autorelease pools, as it
246// has less overhead then allocating NSAutoreleasePools, and allows for
247// a future where we use ARC (where NSAutoreleasePool is not allowed).
248// https://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support
249
250extern "C" {
253}
254
256
259{
260#ifdef QT_DEBUG
261 static const bool debugAutoReleasePools = qEnvironmentVariableIsSet("QT_DARWIN_DEBUG_AUTORELEASEPOOLS");
262 if (!debugAutoReleasePools)
263 return;
264
265 Class trackerClass = [QMacAutoReleasePoolTracker class];
266
267 void *poolFrame = nullptr;
268 void *frames[2];
269 if (backtrace_from_fp(__builtin_frame_address(0), frames, 2))
270 poolFrame = frames[1];
271
272 if (poolFrame) {
273 Dl_info info;
274 if (dladdr(poolFrame, &info) && info.dli_sname) {
275 const char *symbolName = info.dli_sname;
276 if (symbolName[0] == '_') {
277 int status;
278 if (char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status))
279 symbolName = demangled;
280 }
281
282 char *className = nullptr;
283 asprintf(&className, " ^-- allocated in function: %s", symbolName);
284
285 if (Class existingClass = objc_getClass(className))
286 trackerClass = existingClass;
287 else
288 trackerClass = objc_duplicateClass(trackerClass, className, 0);
289
290 free(className);
291
292 if (symbolName != info.dli_sname)
293 free((char*)symbolName);
294 }
295 }
296
297 [[trackerClass new] autorelease];
298#endif // QT_DEBUG
299}
300
302{
304}
305
306#ifndef QT_NO_DEBUG_STREAM
308{
309 QDebugStateSaver saver(debug);
310 debug.nospace();
311 debug << "QMacAutoReleasePool(" << (const void *)pool << ')';
312 return debug;
313}
314
316{
317 debug << static_cast<QString>(string);
318 return debug;
319}
320#endif // !QT_NO_DEBUG_STREAM
321
322#ifdef Q_OS_MACOS
323bool qt_mac_applicationIsInDarkMode()
324{
325 auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
326 @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
327 return [appearance isEqualToString:NSAppearanceNameDarkAqua];
328}
329
330bool qt_mac_runningUnderRosetta()
331{
332 int translated = 0;
333 auto size = sizeof(translated);
334 if (sysctlbyname("sysctl.proc_translated", &translated, &size, nullptr, 0) == 0)
335 return translated;
336 return false;
337}
338
339std::optional<uint32_t> qt_mac_sipConfiguration()
340{
341 static auto configuration = []() -> std::optional<uint32_t> {
342#if !defined(QT_APPLE_NO_PRIVATE_APIS)
345 return config;
346#endif
347
348 QIOType<io_registry_entry_t> nvram = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
349 if (!nvram) {
350 qWarning("Failed to locate NVRAM entry in IO registry");
351 return {};
352 }
353
354 QCFType<CFTypeRef> csrConfig = IORegistryEntryCreateCFProperty(nvram,
355 CFSTR("csr-active-config"), kCFAllocatorDefault, IOOptionBits{});
356 if (!csrConfig)
357 return {}; // SIP config is not available
358
359 if (auto type = CFGetTypeID(csrConfig); type != CFDataGetTypeID()) {
360 qWarning() << "Unexpected SIP config type" << CFCopyTypeIDDescription(type);
361 return {};
362 }
363
364 QByteArray data = QByteArray::fromRawCFData(csrConfig.as<CFDataRef>());
365 if (data.size() != sizeof(uint32_t)) {
366 qWarning() << "Unexpected SIP config size" << data.size();
367 return {};
368 }
369
370 return qFromLittleEndian<uint32_t>(data.constData());
371 }();
372 return configuration;
373}
374
375#define CHECK_SPAWN(expr) \
376 if (int err = (expr)) { \
377 posix_spawnattr_destroy(&attr); \
378 return; \
379 }
380
381#ifdef QT_BUILD_INTERNAL
382void qt_mac_ensureResponsible()
383{
384#if !defined(QT_APPLE_NO_PRIVATE_APIS)
385 if (!responsibility_get_pid_responsible_for_pid || !responsibility_spawnattrs_setdisclaim)
386 return;
387
388 auto pid = getpid();
389 if (responsibility_get_pid_responsible_for_pid(pid) == pid)
390 return; // Already responsible
391
392 posix_spawnattr_t attr = {};
393 CHECK_SPAWN(posix_spawnattr_init(&attr));
394
395 // Behave as exec
396 short flags = POSIX_SPAWN_SETEXEC;
397
398 // Reset signal mask
399 sigset_t no_signals;
400 sigemptyset(&no_signals);
401 CHECK_SPAWN(posix_spawnattr_setsigmask(&attr, &no_signals));
402 flags |= POSIX_SPAWN_SETSIGMASK;
403
404 // Reset all signals to their default handlers
405 sigset_t all_signals;
406 sigfillset(&all_signals);
407 CHECK_SPAWN(posix_spawnattr_setsigdefault(&attr, &all_signals));
408 flags |= POSIX_SPAWN_SETSIGDEF;
409
410 CHECK_SPAWN(posix_spawnattr_setflags(&attr, flags));
411
412 CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1));
413
414 char **argv = *_NSGetArgv();
415 posix_spawnp(&pid, argv[0], nullptr, &attr, argv, environ);
416 posix_spawnattr_destroy(&attr);
417#endif
418}
419#endif // QT_BUILD_INTERNAL
420
421#endif
422
424{
425 static bool isExtension = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSExtension"];
426 return isExtension;
427}
428
429#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
431{
432 // Application extensions are not allowed to access the shared application
434 qWarning() << "accessing the shared" << [AppleApplication class]
435 << "is not allowed in application extensions";
436
437 // In practice the application is actually available, but the App
438 // review process will likely catch uses of it, so we return nil just
439 // in case, unless we don't care about being App Store compliant.
440#if QT_CONFIG(appstore_compliant)
441 return nil;
442#endif
443 }
444
445 // We use performSelector so that building with -fapplication-extension will
446 // not mistakenly think we're using the shared application in extensions.
447 return [[AppleApplication class] performSelector:@selector(sharedApplication)];
448}
449#endif
450
451#if !defined(QT_BOOTSTRAPPED)
452
453#if defined(Q_OS_MACOS)
454namespace {
455struct SandboxChecker
456{
457 SandboxChecker() : m_thread([this]{
458 m_isSandboxed = []{
459 QCFType<SecStaticCodeRef> staticCode = nullptr;
460 NSURL *executableUrl = NSBundle.mainBundle.executableURL;
461 if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
462 kSecCSDefaultFlags, &staticCode) != errSecSuccess)
463 return false;
464
465 QCFType<SecRequirementRef> sandboxRequirement;
466 if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"),
467 kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
468 return false;
469
470 if (SecStaticCodeCheckValidityWithErrors(staticCode,
471 kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess)
472 return false;
473
474 return true;
475 }();
476 })
477 {}
478 ~SandboxChecker() {
479 std::scoped_lock lock(m_mutex);
480 if (m_thread.joinable())
481 m_thread.detach();
482 }
483 bool isSandboxed() const {
484 std::scoped_lock lock(m_mutex);
485 if (m_thread.joinable())
486 m_thread.join();
487 return m_isSandboxed;
488 }
489private:
490 bool m_isSandboxed;
491 mutable std::thread m_thread;
492 mutable std::mutex m_mutex;
493};
494} // namespace
495static SandboxChecker sandboxChecker;
496#endif // Q_OS_MACOS
497
499{
500#if defined(Q_OS_MACOS)
501 return sandboxChecker.isSandboxed();
502#else
503 return true; // All other Apple platforms
504#endif
505}
506
508@implementation NSObject (QtSandboxHelpers)
509- (id)qt_valueForPrivateKey:(NSString *)key
510{
512 return nil;
513
514 return [self valueForKey:key];
515}
516@end
518#endif // !QT_BOOTSTRAPPED
519
520#ifdef Q_OS_MACOS
521/*
522 Ensure that Objective-C objects auto-released in main(), directly or indirectly,
523 after QCoreApplication construction, are released when the app goes out of scope.
524 The memory will be reclaimed by the system either way when the process exits,
525 but by having a root level pool we ensure that the objects get their dealloc
526 methods called, which is useful for debugging object ownership graphs, etc.
527*/
528
530#define ROOT_LEVEL_POOL_MARKER QT_ROOT_LEVEL_POOL__THESE_OBJECTS_WILL_BE_RELEASED_WHEN_QAPP_GOES_OUT_OF_SCOPE
531@interface QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) : NSObject @end
532@implementation QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) @end
533QT_NAMESPACE_ALIAS_OBJC_CLASS(ROOT_LEVEL_POOL_MARKER);
535
536const char ROOT_LEVEL_POOL_DISABLE_SWITCH[] = "QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL";
537
538QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool()
539{
540 if (qEnvironmentVariableIsSet(ROOT_LEVEL_POOL_DISABLE_SWITCH))
541 return;
542
543 pool.reset(new QMacAutoReleasePool);
544
545 [[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease];
546
547 if (qstrcmp(qgetenv("OBJC_DEBUG_MISSING_POOLS"), "YES") == 0) {
548 qDebug("QCoreApplication root level NSAutoreleasePool in place. Break on ~%s and use\n" \
549 "'p [NSAutoreleasePool showPools]' to show leaked objects, or set %s",
550 __FUNCTION__, ROOT_LEVEL_POOL_DISABLE_SWITCH);
551 }
552}
553
554QMacRootLevelAutoReleasePool::~QMacRootLevelAutoReleasePool()
555{
556}
557#endif
558
559// -------------------------------------------------------------------------
560
562{
563#if defined(__WATCH_OS_VERSION_MIN_REQUIRED)
564 const char *os = "watchOS";
565 const int version = __WATCH_OS_VERSION_MIN_REQUIRED;
566#elif defined(__TV_OS_VERSION_MIN_REQUIRED)
567 const char *os = "tvOS";
568 const int version = __TV_OS_VERSION_MIN_REQUIRED;
569#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
570 const char *os = "iOS";
571 const int version = __IPHONE_OS_VERSION_MIN_REQUIRED;
572#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
573 const char *os = "macOS";
574 const int version = __MAC_OS_X_VERSION_MIN_REQUIRED;
575#endif
576
577 const auto required = QVersionNumber(version / 10000, version / 100 % 100, version % 100);
578 const auto current = QOperatingSystemVersion::current().version();
579
580#if defined(Q_OS_MACOS)
581 // Check for compatibility version, in which case we can't do a
582 // comparison to the deployment target, which might be e.g. 11.0
583 if (current.majorVersion() == 10 && current.minorVersion() >= 16)
584 return;
585#endif
586
587 if (current < required) {
588 NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
589 NSString *applicationName = plist[@"CFBundleDisplayName"];
590 if (!applicationName)
591 applicationName = plist[@"CFBundleName"];
592 if (!applicationName)
593 applicationName = NSProcessInfo.processInfo.processName;
594
595 fprintf(stderr, "Sorry, \"%s\" cannot be run on this version of %s. "
596 "Qt requires %s %ld.%ld.%ld or later, you have %s %ld.%ld.%ld.\n",
597 applicationName.UTF8String, os,
598 os, long(required.majorVersion()), long(required.minorVersion()), long(required.microVersion()),
599 os, long(current.majorVersion()), long(current.minorVersion()), long(current.microVersion()));
600
601 exit(1);
602 }
603}
605
606// -------------------------------------------------------------------------
607
609{
610 if (observer)
611 [[NSNotificationCenter defaultCenter] removeObserver:observer];
612 observer = nullptr;
613}
614
615// -------------------------------------------------------------------------
616
619{
620}
621
622void QMacKeyValueObserver::addObserver(NSKeyValueObservingOptions options)
623{
624 [object addObserver:observer forKeyPath:keyPath options:options context:callback.get()];
625}
626
628 if (object)
629 [object removeObserver:observer forKeyPath:keyPath context:callback.get()];
630 object = nil;
631}
632
633KeyValueObserver *QMacKeyValueObserver::observer = [[KeyValueObserver alloc] init];
634
636@implementation QT_MANGLE_NAMESPACE(KeyValueObserver)
637- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
638 change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
639{
641 Q_UNUSED(object);
642 Q_UNUSED(change);
643
644 (*reinterpret_cast<QMacKeyValueObserver::Callback*>(context))();
645}
646@end
648
649// -------------------------------------------------------------------------
650
652{
653 switch (target) {
654 case ApplicationBinary: return applicationVersion().second;
655 case QtLibraries: return libraryVersion().second;
656 }
657 Q_UNREACHABLE();
658}
659
661{
662 switch (target) {
663 case ApplicationBinary: return applicationVersion().first;
664 case QtLibraries: return libraryVersion().first;
665 }
666 Q_UNREACHABLE();
667}
668
670{
672}
673
674// Mach-O platforms
675enum Platform {
676 macOS = 1,
677 iOS = 2,
678 tvOS = 3,
679 watchOS = 4,
680 bridgeOS = 5,
681 macCatalyst = 6,
682 iOSSimulator = 7,
683 tvOSSimulator = 8,
684 watchOSSimulator = 9
685};
686
687QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader)
688{
689 static auto osForLoadCommand = [](uint32_t cmd) {
690 switch (cmd) {
691 case LC_VERSION_MIN_MACOSX: return QOperatingSystemVersion::MacOS;
692 case LC_VERSION_MIN_IPHONEOS: return QOperatingSystemVersion::IOS;
693 case LC_VERSION_MIN_TVOS: return QOperatingSystemVersion::TvOS;
694 case LC_VERSION_MIN_WATCHOS: return QOperatingSystemVersion::WatchOS;
695 default: return QOperatingSystemVersion::Unknown;
696 }
697 };
698
699 static auto osForPlatform = [](uint32_t platform) {
700 switch (platform) {
701 case Platform::macOS:
703 case Platform::iOS:
704 case Platform::iOSSimulator:
706 case Platform::tvOS:
707 case Platform::tvOSSimulator:
709 case Platform::watchOS:
710 case Platform::watchOSSimulator:
712 default:
714 }
715 };
716
717 static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk, QOperatingSystemVersion::OSType osType) {
718 return qMakePair(
719 QOperatingSystemVersion(osType, dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff),
720 QOperatingSystemVersion(osType, sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff)
721 );
722 };
723
724 const bool is64Bit = machHeader->magic == MH_MAGIC_64 || machHeader->magic == MH_CIGAM_64;
725 auto commandCursor = uintptr_t(machHeader) + (is64Bit ? sizeof(mach_header_64) : sizeof(mach_header));
726
727 for (uint32_t i = 0; i < machHeader->ncmds; ++i) {
728 load_command *loadCommand = reinterpret_cast<load_command *>(commandCursor);
729 if (loadCommand->cmd == LC_VERSION_MIN_MACOSX || loadCommand->cmd == LC_VERSION_MIN_IPHONEOS
730 || loadCommand->cmd == LC_VERSION_MIN_TVOS || loadCommand->cmd == LC_VERSION_MIN_WATCHOS) {
731 auto versionCommand = reinterpret_cast<version_min_command *>(loadCommand);
732 return makeVersionTuple(versionCommand->version, versionCommand->sdk, osForLoadCommand(loadCommand->cmd));
733 } else if (loadCommand->cmd == LC_BUILD_VERSION) {
734 auto versionCommand = reinterpret_cast<build_version_command *>(loadCommand);
735 return makeVersionTuple(versionCommand->minos, versionCommand->sdk, osForPlatform(versionCommand->platform));
736 }
737 commandCursor += loadCommand->cmdsize;
738 }
739 Q_ASSERT_X(false, "QMacVersion", "Could not find any version load command");
740 Q_UNREACHABLE();
741}
742
743QMacVersion::VersionTuple QMacVersion::applicationVersion()
744{
745 static VersionTuple version = []() {
746 const mach_header *executableHeader = nullptr;
747 for (uint32_t i = 0; i < _dyld_image_count(); ++i) {
748 auto header = _dyld_get_image_header(i);
749 if (header->filetype == MH_EXECUTE) {
750 executableHeader = header;
751 break;
752 }
753 }
754 Q_ASSERT_X(executableHeader, "QMacVersion", "Failed to resolve Mach-O header of executable");
755 return versionsForImage(executableHeader);
756 }();
757 return version;
758}
759
760QMacVersion::VersionTuple QMacVersion::libraryVersion()
761{
762 static VersionTuple version = []() {
763 Dl_info qtCoreImage;
764 dladdr((const void *)&QMacVersion::libraryVersion, &qtCoreImage);
765 Q_ASSERT_X(qtCoreImage.dli_fbase, "QMacVersion", "Failed to resolve Mach-O header of QtCore");
766 return versionsForImage(static_cast<mach_header*>(qtCoreImage.dli_fbase));
767 }();
768 return version;
769}
770
771// -------------------------------------------------------------------------
772
774
static bool preventsStderrLogging()
static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message, const QString &subsystem=QString())
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
X as() const
\inmodule QtCore
\inmodule QtCore
Q_CORE_EXPORT ~QMacAutoReleasePool()
Definition qcore_mac.mm:301
Q_NODISCARD_CTOR Q_CORE_EXPORT QMacAutoReleasePool()
Definition qcore_mac.mm:257
std::function< void()> Callback
QMacKeyValueObserver()=default
static QOperatingSystemVersion deploymentTarget(VersionTarget target=ApplicationBinary)
static QOperatingSystemVersion currentRuntime()
static QOperatingSystemVersion buildSDK(VersionTarget target=ApplicationBinary)
\inmodule QtCore
Definition qlogging.h:39
QVersionNumber version() const
static QOperatingSystemVersion current()
[0]
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
\inmodule QtCore
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
static void * context
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
Q_CONSTRUCTOR_FUNCTION(initializeStandardUserDefaults)
QT_FOR_EACH_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType)
Definition qcore_mac.mm:223
QT_BEGIN_NAMESPACE void qt_apple_check_os_version()
Definition qcore_mac.mm:561
bool qt_apple_isApplicationExtension()
Definition qcore_mac.mm:423
QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
int csr_get_active_config(csr_config_t *) __attribute__((weak_import))
uint32_t csr_config_t
Definition qcore_mac.mm:39
static QT_BEGIN_NAMESPACE void initializeStandardUserDefaults()
Definition qcore_mac.mm:56
QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
bool qt_apple_isSandboxed()
Definition qcore_mac.mm:498
void objc_autoreleasePoolPop(void *pool)
QT_END_NAMESPACE QT_USE_NAMESPACE void * objc_autoreleasePoolPush(void)
QDebug operator<<(QDebug dbg, id obj)
Definition qcore_mac.mm:178
AppleApplication * qt_apple_sharedApplication()
Definition qcore_mac.mm:430
#define QT_MAC_WEAK_IMPORT(symbol)
Definition qcore_mac_p.h:60
UIApplication AppleApplication
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
Definition qcore_mac_p.h:57
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QDBusError::ErrorType get(const char *name)
static QString header(const QString &name)
static struct AttrInfo attrs[]
EGLConfig config
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:160
QtMsgType
Definition qlogging.h:29
@ QtCriticalMsg
Definition qlogging.h:32
@ QtInfoMsg
Definition qlogging.h:34
@ QtWarningMsg
Definition qlogging.h:31
@ QtFatalMsg
Definition qlogging.h:33
@ QtDebugMsg
Definition qlogging.h:30
#define qWarning
Definition qlogging.h:162
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLuint id
[7]
GLuint object
[3]
GLenum type
GLenum target
GLbitfield flags
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLhandleARB obj
[2]
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
char ** environ
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
static QString keyPath(const QString &rKey)
#define qPrintable(string)
Definition qstring.h:1391
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define Q_UNUSED(x)
QT_BEGIN_NAMESPACE Platform platform()
Platform
const char className[16]
[1]
Definition qwizard.cpp:100
QString bundle
QFileInfo info(fileName)
[8]
QReadWriteLock lock
[0]
QSharedPointer< T > other(t)
[5]