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