summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2023-02-13 16:12:06 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2023-02-18 18:20:25 +0100
commitd05f2fb2d567617730d7d4757fff39ddc3e903ce (patch)
tree21408f793ffee0791e156e4fe303738c87a8f3d2
parentfb09c82a2c7c44d41a0a36d8fe6d6d22e792668a (diff)
Resolve actual macOS version despite process running in compatibility mode
If the application executable was built against a pre-macOS 11 SDK, macOS will report its version as 10.16 on every OS from macOS 11 and up, for compatibility reasons. From Qt 6.2 and up, we require at least Xcode 12 with the macOS 11 SDK to build Qt applications, so normally this should not be an issue, but in the case where the Qt 'app' is a plugin library hosted by a third party host application, the host application determines the behavior, and we might end up in the compatibility situation after all. However, since the Qt app was built against at least the macOS 11 SDK, we know that it can/should handle the new version number scheme, and we can resolve the real version number for QOperatingSystemVersion. We do that by launching the sysctl binary with the SYSTEM_VERSION_COMPAT environment variable set to 0, which is the supported way of disabling the compatibility mode. Now that we have the real version number we can use that for the deployment target check via qt_apple_check_os_version(), but we still need to account for possible failures in reading the plist file. We can also simplify the QOperatingSystemVersion::MacOSBigSur definition, now that we always know the app the should be able to handle major versions above 10. Pick-to: 6.5 6.4 6.2 Task-number: QTBUG-111114 Change-Id: I2a2756381c31b195f7b8800c5008a87b37114080 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp19
-rw-r--r--src/corelib/global/qoperatingsystemversion.h4
-rw-r--r--src/corelib/global/qoperatingsystemversion_darwin.mm49
-rw-r--r--src/corelib/kernel/qcore_mac.mm16
4 files changed, 54 insertions, 34 deletions
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index b9da31149e..c57483273f 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -537,24 +537,11 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSCatalina =
/*!
\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.
+ \brief a version corresponding to macOS Big Sur (version 11).
\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);
-}();
+const QOperatingSystemVersion QOperatingSystemVersion::MacOSBigSur =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 11, 0);
/*!
\variable QOperatingSystemVersion::MacOSMonterey
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index 1e4eb5cc49..80a4cbbacb 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -165,12 +165,8 @@ public:
static constexpr QOperatingSystemVersionBase MacOSHighSierra { QOperatingSystemVersionBase::MacOS, 10, 13 };
static constexpr QOperatingSystemVersionBase MacOSMojave { QOperatingSystemVersionBase::MacOS, 10, 14 };
static constexpr QOperatingSystemVersionBase MacOSCatalina { QOperatingSystemVersionBase::MacOS, 10, 15 };
-#if !defined(Q_OS_DARWIN) || QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_11_0)
static constexpr QOperatingSystemVersionBase MacOSBigSur = { QOperatingSystemVersionBase::MacOS, 11, 0 };
static constexpr QOperatingSystemVersionBase MacOSMonterey = { QOperatingSystemVersionBase::MacOS, 12, 0 };
-#else // ### Qt 7: Verify the assumption
-# error Either you are using an outdated SDK or my assumption that Qt7 would require at least 11.0 was wrong
-#endif
static constexpr QOperatingSystemVersionBase AndroidJellyBean { QOperatingSystemVersionBase::Android, 4, 1 };
static constexpr QOperatingSystemVersionBase AndroidJellyBean_MR1 { QOperatingSystemVersionBase::Android, 4, 2 };
diff --git a/src/corelib/global/qoperatingsystemversion_darwin.mm b/src/corelib/global/qoperatingsystemversion_darwin.mm
index 6581244821..99f38ea430 100644
--- a/src/corelib/global/qoperatingsystemversion_darwin.mm
+++ b/src/corelib/global/qoperatingsystemversion_darwin.mm
@@ -2,19 +2,56 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoperatingsystemversion_p.h"
+
#import <Foundation/Foundation.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qversionnumber.h>
+
+#if !defined(QT_BOOTSTRAPPED)
+#include <QtCore/qprocess.h>
+#endif
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QOperatingSystemVersionBase QOperatingSystemVersionBase::current_impl()
{
NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
- QOperatingSystemVersionBase v;
- v.m_os = currentType();
- v.m_major = osv.majorVersion;
- v.m_minor = osv.minorVersion;
- v.m_micro = osv.patchVersion;
- return v;
+ QVersionNumber versionNumber(osv.majorVersion, osv.minorVersion, osv.patchVersion);
+
+ if (versionNumber.majorVersion() == 10 && versionNumber.minorVersion() >= 16) {
+ // The process is running in system version compatibility mode,
+ // due to the executable being built against a pre-macOS 11 SDK.
+ // This might happen even if we require a more recent SDK for
+ // building Qt applications, as the Qt 'app' might be a plugin
+ // hosted inside a host that used an earlier SDK. But, since we
+ // require a recent SDK for the Qt app itself, the application
+ // should be prepared for versions numbers beyond 10, and we can
+ // resolve the real version number here.
+#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(process)
+ QProcess sysctl;
+ QProcessEnvironment nonCompatEnvironment;
+ nonCompatEnvironment.insert("SYSTEM_VERSION_COMPAT", "0");
+ sysctl.setProcessEnvironment(nonCompatEnvironment);
+ sysctl.start("/usr/sbin/sysctl"_L1, QStringList() << "-b"_L1 << "kern.osproductversion"_L1);
+ if (sysctl.waitForFinished()) {
+ auto versionString = QString::fromLatin1(sysctl.readAll());
+ auto nonCompatSystemVersion = QVersionNumber::fromString(versionString);
+ if (!nonCompatSystemVersion.isNull())
+ versionNumber = nonCompatSystemVersion;
+ }
+#endif
+ }
+
+ QOperatingSystemVersionBase operatingSystemVersion;
+ operatingSystemVersion.m_os = currentType();
+ operatingSystemVersion.m_major = versionNumber.majorVersion();
+ operatingSystemVersion.m_minor = versionNumber.minorVersion();
+ operatingSystemVersion.m_micro = versionNumber.microVersion();
+
+ return operatingSystemVersion;
}
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 992713a374..17cd03d975 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -553,18 +553,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;
+
+ 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; // FIXME: Find a way to detect the real OS version
+ if (current.majorVersion() == 10 && current.minorVersion() >= 16)
+ return;
#endif
- if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:required]) {
+ if (current < required) {
NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
NSString *applicationName = plist[@"CFBundleDisplayName"];
if (!applicationName)
@@ -575,8 +575,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);
}