Friday, September 22, 2017

JAEUA (Just another endangered Universal application), or, the three heads of Tutti II

On this blog, Universal doesn't mean that watered-down 32-bit/64-bit Intel nonsense. It means actually running on multiple system architectures, like 68K and PowerPC in the "fat binary" days, or PowerPC and Intel at the dawn of the OS X i386 era (as OS X has always been able to do even when Marklar was a skunkworks project thanks to NeXTSTEP).

So here's another one. I maintain an emulator of the first home computer I ever had as a kid, the Tomy Tutor, called Tutti II (the original Tutti was actually a simulator for the Commodore 64, and I wrote that too). It descends from an earlier emulator written for Windows called TutorEm which was conveniently SDL-based, so I made some endian fixes for PowerPC and ported it to OS X with some fixes and new features. Download it and play with the demo tape images on the page. It runs on any Mac that can run 10.4 or later, PowerPC or Intel. It runs just dandy on my Sierra-based i7 MacBook Air all the way down to my Tiger-based Sawtooth G4.

The point of this blog post isn't (merely) shameless self-promotion, though; there are some technical points I want to make too. Tutti II isn't just a Universal PowerPC/Intel app; it's actually a three-headed chimera. While the SDL dylib it uses is a relatively pedestrian ppc and i386 Universal library, if you run lipo on the core tutti executable itself you'll find three architectures: one for ppc750 (i.e., G3), one for ppc7400 (i.e., G4), and one for i386 (Intel 32-bit).

Why are there three versions? Because AltiVec. If you look at the source code, you'll find conditional defines for AltiVec acceleration mostly within the TMS 9918A video chip emulation which are used for bitmap splats and scales. This is part of what enables it to run well even on my 1GHz iMac G4. In fact, given that the Mach-O field for number of architectures is a 32-bit integer, you are likely to run out of file offset space (also a 32-bit integer) in a multi-architecture binary long before you run out of actual and artificial architectures to cram in it. Mac OS X looks at the binary and if your system has Intel, runs the Intel portion. If it's PowerPC and it has AltiVec, it runs the AltiVec version, and failing that, the G3 version. No runtime checking is required within the code itself. (The only reason I haven't bothered to do a ppc7450 or ppc970 version too and make it five-headed is because it runs so fast already they're not likely to yield much, if any, noticeable benefit.)

The second point is that this is made much easier because everything is 32-bit. Although Tutti II is mostly Cocoa-based internally and probably could be made to build 64-bit, Xcode 2.5 doesn't support 64-bit Intel compilation, the Universal 10.4 SDK is only 32-bit, and the specific 32-bit SDL 1.2.14 version I use occupies a narrow sweet spot where it uses CoreGraphics instead of QuickDraw for forward compatibility while still functioning on PowerPC 10.4. But, because it's 32-bit, I can build the entire app from the G5 on 10.4 with that library and everything easily descends from almost exactly the same code base. This may no longer be possible after macOS 10.14, whatever it's called (I'm hoping for "macOS Arvin"), ends the ability to run "32-bit applications without compromise." Apple doesn't say what that compromise might be, but my guess is either that the operating system will not include 32-bit components and they will be a separate download for some transitional period (like Rosetta in 10.6), or Intel Carbon applications will be entirely unsupported, as there is no 64-bit Carbon, or maybe even both. Apple may also choose to completely remove things like Intel QuickDraw at the same time, which hasn't been supported since 10.4 but does still run on current versions of macOS, and is only really meaningful for Carbon also. After these pieces are completely decommissioned, you'll have to run High Sierra or Snow Leopard in a VM, I suppose.

As I've mentioned before, this is bad for Power Macs because other than PowerPC bigots like me, what residual PowerPC application support remains is largely due to the fact it works without additional effort and it's more work to remove it than not to bother. I suspect many cross-builders have some old Power Mac or early Intel Mac in a corner with an Xcode that just happens to still build for PowerPC, and the binary it spits out still "just works" on modern Macs, so they leave it alone. Even codesigning didn't really change this much because these cross-platform builders don't like paying the Apple developer tax as much as I don't, so they don't need it (Tutti II is also not a signed application, and probably never will be). Once this is no longer possible, however, these builders will probably just remove PowerPC support entirely since it won't be compatible with newer versions of Xcode, so start preserving source code archives where you find them so you can maintain and build it yourself.

In my case, since I'm planning to move to POWER9 on Linux instead of whatever the next Mac Pro turns out to be, when 32-bit Mac apps are gone completely that will mean the end of Tutti II on current versions of macOS. There will still be a build for Power Macs, but since I'm actually looking into cross-compiling it for Windows, rather than chugging out a special 64-bit macOS build and maintaining it separately I'll just make current Mac users run the 32-bit Windows binary in WINE. That's just less work for me and satisfies my internal curmudgeon, so there.

Look for TenFourFox FPR3 final probably tomorrow or Sunday, depending on when the build cycle finishes.

No comments:

Post a Comment

Due to an increased frequency of spam, comments are now subject to moderation.