From 25e0e6273d9e9ba20147aa3c7479830fd12a254d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 28 Jul 2020 16:45:07 +0200 Subject: Add QOperatingSystemVersion support for macOS Big Sur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ide57f675b20b08210f301da5177df45d008423c4 Reviewed-by: Thiago Macieira Reviewed-by: Timur Pocheptsov (cherry picked from commit 19d32f0a5fc8b12e03a84ab6e18845337fd3b70f) Reviewed-by: Tor Arne Vestbø --- src/corelib/global/qoperatingsystemversion.cpp | 25 ++++++++ src/corelib/global/qoperatingsystemversion.h | 1 + src/corelib/global/qsystemdetection.h | 6 ++ src/corelib/kernel/qcore_mac.cpp | 88 ++++++++++++++++++++++++++ src/corelib/kernel/qcore_mac_p.h | 26 ++++++++ src/plugins/platforms/cocoa/qcocoahelpers.h | 22 ------- src/plugins/platforms/cocoa/qcocoahelpers.mm | 87 ------------------------- 7 files changed, 146 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp index bc6adb54dc..a0ea801ba1 100644 --- a/src/corelib/global/qoperatingsystemversion.cpp +++ b/src/corelib/global/qoperatingsystemversion.cpp @@ -42,6 +42,10 @@ #include "qoperatingsystemversion_p.h" #endif +#if defined(Q_OS_DARWIN) +#include +#endif + #include #include @@ -445,6 +449,27 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSMojave = const QOperatingSystemVersion QOperatingSystemVersion::MacOSCatalina = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 15); +/*! + \variable QOperatingSystemVersion::MacOSBigSur + \brief a version corresponding to macOS Big Sur + + The actual version number depends on whether the application was built + using the Xcode 12 SDK. If it was, the version number corresponds + to macOS 11.0. If not it will correspond to macOS 10.16. + + By comparing QOperatingSystemVersion::current() to this constant + you will always end up comparing to the right version number. + \since 6.0 + */ +const QOperatingSystemVersion QOperatingSystemVersion::MacOSBigSur = [] { +#if defined(Q_OS_DARWIN) + if (QMacVersion::buildSDK(QMacVersion::ApplicationBinary) >= QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16)) + return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 11, 0); + else +#endif + return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16); +}(); + /*! \variable QOperatingSystemVersion::AndroidJellyBean \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16). diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h index 89c60c4960..db4da1a9ae 100644 --- a/src/corelib/global/qoperatingsystemversion.h +++ b/src/corelib/global/qoperatingsystemversion.h @@ -72,6 +72,7 @@ public: static const QOperatingSystemVersion MacOSHighSierra; static const QOperatingSystemVersion MacOSMojave; static const QOperatingSystemVersion MacOSCatalina; + static const QOperatingSystemVersion MacOSBigSur; static const QOperatingSystemVersion AndroidJellyBean; static const QOperatingSystemVersion AndroidJellyBean_MR1; diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index 3e38e6790b..d87e181e5c 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -234,6 +234,9 @@ # if !defined(__MAC_10_15) # define __MAC_10_15 101500 # endif +# if !defined(__MAC_10_16) +# define __MAC_10_16 101600 +# endif # if !defined(MAC_OS_X_VERSION_10_11) # define MAC_OS_X_VERSION_10_11 __MAC_10_11 # endif @@ -249,6 +252,9 @@ # if !defined(MAC_OS_X_VERSION_10_15) # define MAC_OS_X_VERSION_10_15 __MAC_10_15 # endif +# if !defined(MAC_OS_X_VERSION_10_16) +# define MAC_OS_X_VERSION_10_16 __MAC_10_16 +# endif # # if !defined(__IPHONE_10_0) # define __IPHONE_10_0 100000 diff --git a/src/corelib/kernel/qcore_mac.cpp b/src/corelib/kernel/qcore_mac.cpp index b048576f5b..bef50d8d9b 100644 --- a/src/corelib/kernel/qcore_mac.cpp +++ b/src/corelib/kernel/qcore_mac.cpp @@ -45,6 +45,9 @@ #include "qmutex.h" #include "qvarlengtharray.h" +#include +#include + QT_BEGIN_NAMESPACE QCFString::operator QString() const @@ -159,4 +162,89 @@ os_log_t AppleUnifiedLogger::cachedLog(const QString &subsystem, const QString & // -------------------------------------------------------------------------- +QOperatingSystemVersion QMacVersion::buildSDK(VersionTarget target) +{ + switch (target) { + case ApplicationBinary: return applicationVersion().second; + case QtLibraries: return libraryVersion().second; + } + Q_UNREACHABLE(); +} + +QOperatingSystemVersion QMacVersion::deploymentTarget(VersionTarget target) +{ + switch (target) { + case ApplicationBinary: return applicationVersion().first; + case QtLibraries: return libraryVersion().first; + } + Q_UNREACHABLE(); +} + +QOperatingSystemVersion QMacVersion::currentRuntime() +{ + return QOperatingSystemVersion::current(); +} + +QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader) +{ + static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk) { + return qMakePair( + QOperatingSystemVersion(QOperatingSystemVersion::currentType(), + dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff), + QOperatingSystemVersion(QOperatingSystemVersion::currentType(), + sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff) + ); + }; + + const bool is64Bit = machHeader->magic == MH_MAGIC_64 || machHeader->magic == MH_CIGAM_64; + auto commandCursor = uintptr_t(machHeader) + (is64Bit ? sizeof(mach_header_64) : sizeof(mach_header)); + + for (uint32_t i = 0; i < machHeader->ncmds; ++i) { + load_command *loadCommand = reinterpret_cast(commandCursor); + if (loadCommand->cmd == LC_VERSION_MIN_MACOSX || loadCommand->cmd == LC_VERSION_MIN_IPHONEOS + || loadCommand->cmd == LC_VERSION_MIN_TVOS || loadCommand->cmd == LC_VERSION_MIN_WATCHOS) { + auto versionCommand = reinterpret_cast(loadCommand); + return makeVersionTuple(versionCommand->version, versionCommand->sdk); +#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(loadCommand); + return makeVersionTuple(versionCommand->minos, versionCommand->sdk); +#endif + } + commandCursor += loadCommand->cmdsize; + } + Q_ASSERT_X(false, "QMacVersion", "Could not find any version load command"); + Q_UNREACHABLE(); +} + +QMacVersion::VersionTuple QMacVersion::applicationVersion() +{ + static VersionTuple version = []() { + const mach_header *executableHeader = nullptr; + for (uint32_t i = 0; i < _dyld_image_count(); ++i) { + auto header = _dyld_get_image_header(i); + if (header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + Q_ASSERT_X(executableHeader, "QMacVersion", "Failed to resolve Mach-O header of executable"); + return versionsForImage(executableHeader); + }(); + return version; +} + +QMacVersion::VersionTuple QMacVersion::libraryVersion() +{ + static VersionTuple version = []() { + Dl_info qtCoreImage; + dladdr((const void *)&QMacVersion::libraryVersion, &qtCoreImage); + Q_ASSERT_X(qtCoreImage.dli_fbase, "QMacVersion", "Failed to resolve Mach-O header of QtCore"); + return versionsForImage(static_cast(qtCoreImage.dli_fbase)); + }(); + return version; +} + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 168e0418e4..b78bc3207d 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -53,6 +53,9 @@ #include "private/qglobal_p.h" +#include +struct mach_header; + #ifndef __IMAGECAPTURE__ # define __IMAGECAPTURE__ #endif @@ -72,6 +75,7 @@ #include "qstring.h" #include "qscopedpointer.h" +#include "qpair.h" #if defined( __OBJC__) && defined(QT_NAMESPACE) #define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__) @@ -397,6 +401,28 @@ private: // ------------------------------------------------------------------------- +class Q_CORE_EXPORT QMacVersion +{ +public: + enum VersionTarget { + ApplicationBinary, + QtLibraries + }; + + static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary); + static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary); + static QOperatingSystemVersion currentRuntime(); + +private: + QMacVersion() = default; + using VersionTuple = QPair; + static VersionTuple versionsForImage(const mach_header *machHeader); + static VersionTuple applicationVersion(); + static VersionTuple libraryVersion(); +}; + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE #endif // QCORE_MAC_P_H diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 22ea569c67..1d8461d5f2 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -178,28 +178,6 @@ T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &pro // ------------------------------------------------------------------------- -class QMacVersion -{ -public: - enum VersionTarget { - ApplicationBinary, - QtLibraries - }; - - static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary); - static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary); - static QOperatingSystemVersion currentRuntime(); - -private: - QMacVersion() = default; - using VersionTuple = QPair; - static VersionTuple versionsForImage(const mach_header *machHeader); - static VersionTuple applicationVersion(); - static VersionTuple libraryVersion(); -}; - -// ------------------------------------------------------------------------- - QT_END_NAMESPACE // @compatibility_alias doesn't work with protocols diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 2048bccf65..5374199360 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -55,9 +55,6 @@ #include -#include -#include - QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); @@ -370,90 +367,6 @@ QString qt_mac_removeAmpersandEscapes(QString s) return QPlatformTheme::removeMnemonics(s).trimmed(); } -// ------------------------------------------------------------------------- - -QOperatingSystemVersion QMacVersion::buildSDK(VersionTarget target) -{ - switch (target) { - case ApplicationBinary: return applicationVersion().second; - case QtLibraries: return libraryVersion().second; - } - Q_UNREACHABLE(); -} - -QOperatingSystemVersion QMacVersion::deploymentTarget(VersionTarget target) -{ - switch (target) { - case ApplicationBinary: return applicationVersion().first; - case QtLibraries: return libraryVersion().first; - } - Q_UNREACHABLE(); -} - -QOperatingSystemVersion QMacVersion::currentRuntime() -{ - return QOperatingSystemVersion::current(); -} - -QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader) -{ - static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk) { - return qMakePair( - QOperatingSystemVersion(QOperatingSystemVersion::MacOS, - dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff), - QOperatingSystemVersion(QOperatingSystemVersion::MacOS, - sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff) - ); - }; - - const bool is64Bit = machHeader->magic == MH_MAGIC_64 || machHeader->magic == MH_CIGAM_64; - auto commandCursor = uintptr_t(machHeader) + (is64Bit ? sizeof(mach_header_64) : sizeof(mach_header)); - - for (uint32_t i = 0; i < machHeader->ncmds; ++i) { - load_command *loadCommand = reinterpret_cast(commandCursor); - if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) { - auto versionCommand = reinterpret_cast(loadCommand); - return makeVersionTuple(versionCommand->version, versionCommand->sdk); -#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13) - } else if (loadCommand->cmd == LC_BUILD_VERSION) { - auto versionCommand = reinterpret_cast(loadCommand); - return makeVersionTuple(versionCommand->minos, versionCommand->sdk); -#endif - } - commandCursor += loadCommand->cmdsize; - } - Q_ASSERT_X(false, "QCocoaIntegration", "Could not find any version load command"); - Q_UNREACHABLE(); -} - -QMacVersion::VersionTuple QMacVersion::applicationVersion() -{ - static VersionTuple version = []() { - const mach_header *executableHeader = nullptr; - for (uint32_t i = 0; i < _dyld_image_count(); ++i) { - auto header = _dyld_get_image_header(i); - if (header->filetype == MH_EXECUTE) { - executableHeader = header; - break; - } - } - Q_ASSERT_X(executableHeader, "QCocoaIntegration", "Failed to resolve Mach-O header of executable"); - return versionsForImage(executableHeader); - }(); - return version; -} - -QMacVersion::VersionTuple QMacVersion::libraryVersion() -{ - static VersionTuple version = []() { - Dl_info cocoaPluginImage; - dladdr((const void *)&QMacVersion::libraryVersion, &cocoaPluginImage); - Q_ASSERT_X(cocoaPluginImage.dli_fbase, "QCocoaIntegration", "Failed to resolve Mach-O header of Cocoa plugin"); - return versionsForImage(static_cast(cocoaPluginImage.dli_fbase)); - }(); - return version; -} - QT_END_NAMESPACE /*! \internal -- cgit v1.2.3