Add QOperatingSystemVersion support for macOS Big Sur

Change-Id: Ide57f675b20b08210f301da5177df45d008423c4
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
(cherry picked from commit 19d32f0a5fc8b12e03a84ab6e18845337fd3b70f)
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Tor Arne Vestbø 2020-07-28 16:45:07 +02:00
parent 512c2cf2fb
commit 25e0e6273d
7 changed files with 146 additions and 109 deletions

View File

@ -42,6 +42,10 @@
#include "qoperatingsystemversion_p.h"
#endif
#if defined(Q_OS_DARWIN)
#include <QtCore/private/qcore_mac_p.h>
#endif
#include <qversionnumber.h>
#include <qdebug.h>
@ -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).

View File

@ -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;

View File

@ -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

View File

@ -45,6 +45,9 @@
#include "qmutex.h"
#include "qvarlengtharray.h"
#include <dlfcn.h>
#include <mach-o/dyld.h>
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<load_command *>(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<version_min_command *>(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<build_version_command *>(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<mach_header*>(qtCoreImage.dli_fbase));
}();
return version;
}
// -------------------------------------------------------------------------
QT_END_NAMESPACE

View File

@ -53,6 +53,9 @@
#include "private/qglobal_p.h"
#include <QtCore/qoperatingsystemversion.h>
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<QOperatingSystemVersion, QOperatingSystemVersion>;
static VersionTuple versionsForImage(const mach_header *machHeader);
static VersionTuple applicationVersion();
static VersionTuple libraryVersion();
};
// -------------------------------------------------------------------------
QT_END_NAMESPACE
#endif // QCORE_MAC_P_H

View File

@ -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<QOperatingSystemVersion, QOperatingSystemVersion>;
static VersionTuple versionsForImage(const mach_header *machHeader);
static VersionTuple applicationVersion();
static VersionTuple libraryVersion();
};
// -------------------------------------------------------------------------
QT_END_NAMESPACE
// @compatibility_alias doesn't work with protocols

View File

@ -55,9 +55,6 @@
#include <algorithm>
#include <mach-o/dyld.h>
#include <dlfcn.h>
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<load_command *>(commandCursor);
if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) {
auto versionCommand = reinterpret_cast<version_min_command *>(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<build_version_command *>(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<mach_header*>(cocoaPluginImage.dli_fbase));
}();
return version;
}
QT_END_NAMESPACE
/*! \internal