[Development] Announcement for developers of Qt on macOS and iOS

Jake Petroules Jake.Petroules at qt.io
Mon Oct 2 08:12:22 CEST 2017


Hi all,

I've recently merged some changes into qtbase that I think warrant a warning/announcement to help people understand some strange errors that might pop up in the future.

The background is this: in Xcode 9, there is a new Clang builtin function called __builtin_available (C, C++) / @available (Objective-C). There is also a new warning, unguarded-availability, which will be emitted whenever you unconditionally call an API that might not be available on your deployment target (for example if we call an API introduced in macOS Sierra v10.12, but Qt must still be compatible with OS X Yosemite v10.10). By wrapping the API call site like so:

    if (__builtin_available(macOS 10.12, *)) {
        // Call 10.12 API normally
    } else {
        // Do something else for 10.10 and 10.11
    }

we inform the compiler via __builtin_available that we are performing the necessary runtime check for the OS version before calling any potentially unavailable APIs. This means that we get compile time validation of API availability for APIs we use in Qt, something that has previously only been availably in Swift. Like always, the compiler automatically takes care of weak-linking the functions so there is no need to use dlopen/dlsym, and this works for all languages.

This builtin is part of LLVM 5, here are the docs: https://clang.llvm.org/docs/LanguageExtensions.html#objective-c-available

Now, as for what this means for Qt. In Qt 5.10 and beyond, unguarded-availability warnings are now a hard error (https://codereview.qt-project.org/#/c/206348/). But what about older versions of Clang, and other compilers, where this builtin is not available? Thanks to a bit of macro magic (https://codereview.qt-project.org/#/c/206346/16//ALL), we'll be able to use this new builtin function everywhere in Qt, on all compilers and platforms. My "polyfill" will simply transform the __builtin_available calls to an implementation that uses QOperatingSystemVersion behind the scenes, to perform the check.

Basically, all you need to do is make sure you use __builtin_available where necessary (and Xcode 9 will force you to). You may no longer use QSysInfo::macVersion (which is deprecated entirely, by the way), QOperatingSystemVersion, or respondsToSelector, to perform API availability checks. If you run into an error like "symbol 'macOS' undefined", you probably forgot to include qglobal_p.h, where the polyfill is housed.

I've already audited the entire Qt codebase, and adjusted all call sites as necessary. Unless I missed something, the work is done, but for future development, now everyone knows.

Cheers,
-- 
Jake Petroules - jake.petroules at qt.io
The Qt Company - Silicon Valley
Qbs build tool evangelist - qbs.io


More information about the Development mailing list