It wasn’t a particularly demanding request: someone wanted a version of my little security tool LockRattler which runs on El Capitan, rather than Sierra.
It took me a little while to check that my code didn’t do anything specific to Sierra. As much of it works by running shell commands, and I developed it partly as an example of how to script in Swift 3, it looked fine.
My mistake was to assume that I could make this new backward-compatible version by changing a single setting in Apple’s Xcode development environment. From among the scores of different switches and options, I found the one which claimed to set the macOS deployment target. Up popped choices ranging from 10.6 (back in 2009) to the latest 10.12. I set that to 10.11 for El Capitan, and rebuilt my app.
Only being able to test this new version on Sierra, I put it through its paces, and updated its documentation. When I posted it on my blog, I pointed out that I had not tested it on El Capitan, and invited users to try it and report back. Within a few minutes I got the first response: this new version crashed on starting up on El Capitan, before it had even got to any of my code.
I went back to Xcode to look for clues, and discovered that there was a second setting which I needed to change, controlling the Base SDK. Although the app was now set to try to run on El Capitan, Xcode was stupidly still using all the hooks and features for Sierra.
Then I hit a snag. Whereas older versions of Xcode shipped with a choice of target versions of OS X, this Xcode offered just one. Well, two if you believed its non-choice between macOS 10.12 and Latest macOS (macOS 10.12). That should be easy to fix – I opened its preferences and went to the Components tab, where it would offer me some earlier SDKs to support older releases of OS X. Only it doesn’t: there is no option to download and install El Capitan or any other older OS X support.
I searched its help, looked online to see if such support was downloadable separately, and ended up – as I often seem to when faced with Xcode issues – rummaging through old Stack Overflow postings to discover a solution. The only feasible way ahead, other than reverting to an old version of Xcode, was to download and install the El Capitan SDK from a version of Xcode which still supported it.
My next call was to my Time Machine backup. Although my LockRattler tool isn’t complex, it is written in Swift 3, which first became available in Xcode 8.0 betas last summer. I hadn’t installed those, but had a backup of the first 8.0 release, which had preceded Sierra. After restoring that from my backup, I discovered it too only shipped with support for Sierra, not El Capitan. I had Xcode 7.3.1, which definitely did support El Capitan, but being the previous major version and only offering Swift 2, I decided that would only be worse trouble.
Then I found a developer discussion thread with a potential solution: others had downloaded the required SDK from a GitHub collection of them, inserted that into Xcode, and tweaked a flag in one of its multitude of property lists. That step involved some delicate surgery in Terminal:
sudo /usr/libexec/PlistBuddy -c "Set :MinimumSDKVersion 10.11" /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist
When I tried switching Xcode’s Base SDK to my new-found 10.11 target, the build failed with a fatal error relating to Swift. That was odd, because I had not even needed to hack Xcode’s property list, which was already set to allow 10.11 as a target SDK.
After a couple of hours, I was forced to conclude that Apple does not want those using Xcode 8 to build anything which can run on macOS prior to Sierra. The discussion thread which suggested the solution which almost worked also carried dire warnings from an Apple engineer: do not hack Xcode in this way. Xcode is only developed for and tested with the SDKs which ship with it. Trying to use older SDKs is likely to lead to problems. And it did.
Apple is also insistent that developers only use the latest version of Xcode, which is hardly surprising after the XcodeGhost problems in 2015. In any case for anyone using Swift, reverting to Xcode 7.3.1 and Swift 2 could only be more wasted effort.
In deciding not to ship SDKs supporting versions of macOS/OS X prior to Sierra, Apple is making it very difficult for developers to maintain products so they still run on El Capitan and earlier. The only practical means to do so is to stick with source languages other than Swift, and to continue to use older versions of Xcode.
Doing what should be best for the user – upgrading to the latest version of Xcode and taking advantage of the features of Swift 3 – enforces obsolescence, in that it seems well nigh impossible for those products to run on any previous version of OS X/macOS.
So long as Apple continues to ship Xcode with just the single macOS SDK for Sierra, it is telling those many millions of Mac users still running El Capitan that it does not care about them. That’s not a good message, particularly when Apple leaves it to developers to break that bad news.