Hi,
If you don’t write macOS-specific code, you can stop reading now.
We have a minimum macOS version that we require for chrome (currently macOS 10.9). This is called the deployment target.
macOS SDKs are versioned: The 10.9 SDK contains declarations for all functions and classes available on 10.9+, the 10.10 SDK for functions and classes available on 10.10+, and so on.
We used to use the SDK version corresponding to our deployment target. However, Apple recommends always using the newest SDK, independent of your deployment target. Also, some frameworks behave in buggy-but-backwards-compatible ways if you use an older SDK (*).
So now we use a new-ish SDK (currently 10.10, but hopefully 10.12 soon).
This creates a new problem: Accidental unconditional calls to new APIs. We might call a 10.10+-only API. On 10.9, this would result in a runtime crash.
We didn’t want to risk this, so before we switched to using a newer SDK version than deployment target, we added a wrning called -Wpartial-availability to clang:
The CL description describes how it works. In a nut, you manually need to redeclare newer APIs to suppress warning, which requires manual opt-in in a way. This was kind of klunky, but was good enough for us, and we've used it for the last 2+ years. This is changing now.
Recently, Apple invented new, better, officially-supported way to address the same problem: -Wunguarded-availability. They also made -Wpartial-availability an alias for the new -Wunguarded-availability, and made it so that redeclaring things no longer suppresses the warning. So we had to switch to the new thing in a bit of a rush when we recently updated our compiler. We added some documentation for how the new thing, @available, at
https://clang.llvm.org/docs/LanguageExtensions.html#objective-c-available. Go read that, I won’t repeat it here.
Shout-out to pcc for converting the codebase to @available when updating our clang to a version that added this requirement, and to erikchen who did the follow-up changes needed to keep building with -Wunguarded-availability in his upcoming switch to the 10.12 SDK. (This isn’t 100% done yet, but the final bits should hopefully make it into the tree today and unbreak building with th 10.12 SDK again.)
If you read the document I linked to above, you know most of what there is to know about @available. Here are some notes on complications we’ve seen:
* In rare cases, the availability annotation on an API might be overly conservative. For example, [NSProcessInfo processInfo] secretly responds to -operatingSystemVersion as of macOS 10.9.2, but officially only starting with macOS 10.10. Hence, its availability attribute claims that it exists as of 10.10. If there are just few callers, do:
void my_fun(NSSomeClass* var) {
if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
NSOperatingSystemVersion version = [processInfo operatingSystemVersion];
#pragma clang diagnostic pop
}
}
* API_AVAILABLE currently has the somewhat annoying side effect of also marking C++ (not Objective-C) functions and classes that aren’t in an unnamed namespace as visible. This means those classes have to explicitly be marked hidden, and then if they’re exported, as exported, in that order. This is luckily very rare in practice (2 examples in all of chrome), and also hopefully something that we can fix in the compiler:
https://bugs.llvm.org/show_bug.cgi?id=33796
And that’s it!
What about iOS? -Wunguarded-availability is generally opt-in, and chrome/ios doesn’t opt-in to this warning. On iOS, SDK version and deployment target are usually fairly close to each other, so the warning has less value there. However, for APIs in iOS 11 and newer, this warning is enabled. So chrome/iOS will have to use @available soon, too. Chrome/iOS uses Xcode’s clang instead of Chromium’s clang, and Xcode only supports @available in Xcode 9, which is currently still in beta.
Nico
*: Examples of system libraries behaving differently when linked against an older SDK:
2.) NSThemeFrame is layer backed (if the contentView is layer backed) when linking against 10.9. This doesn’t happen when linking against 10.8 or earlier.
There are probably more cases.