More universal binary joy with Xcode 2.4

I've said before how Apple's universal (fat) binaries have won me over. Xcode 2.4 adds support for x86_64. So given this trivial program:

$ cat test.cpp
#include <iostream>
int main() {
std::cout << "hello, world!" << std::endl;
return 0;

I can now build for four different architectures, from any of those architectures, as easily as I can build for just one of the architectures:

$ g++ -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch ppc64 -arch i386 -arch x86_64 test.cpp -o test

Even when my OS isn't sufficiently modern to recognize one of them (Mac OS/x86_64):

$ file test
test: Mach-O fat file with 4 architectures
test (for architecture ppc): Mach-O executable ppc
test (for architecture ppc64): Mach-O 64-bit executable ppc64
test (for architecture i386): Mach-O executable i386
test (for architecture cputype (16777223) cpusubtype (3)): data

If I try hard to find something to be sad about, it's probably the familiarity of the magic number:

$ hexdump -C test | head -1
00000000 ca fe ba be 00 00 00 04 00 00 00 12 00 00 00 00 |????............|
$ hexdump -C JavaTest.class | head -1
00000000 ca fe ba be 00 00 00 31 02 0f 0a 00 99 00 ff 07 |????...1......?.|

Shhh... I think I hear the world's smallest violin, playing just for me.

Ignoring Java for the moment, because Java side-steps the issue by making you rely on a JVM vendor to solve your architecture problems, and still sometimes leaves you needing to write multi-architecture JNI or stand-alone helper programs anyway, the last time I had multi-architecture support anything like this good was Plan 9.

Plan 9 had a separate compiler for each architecture, and used union mounts so that /bin/ was the union of architecture-independent executables (scripts) and executables for your current architecture. Your ~/bin/ had a subdirectory for each architecture you supported and you'd union mount other directories containing executables rather than adding them to your shell's path as you would on Unix. Distributing multi-architecture Plan 9 applications wasn't really an issue. Assuming you knew anyone else running Plan 9, you'd let them build from source.

Back to the present, Plan 9 is mostly forgotten and we're all using Linux. Compared to Linux, Mac OS' multi-architecture support is like a dream of the distant future. I can understand the Linux distributions' reluctance to go with fat binaries: I wouldn't like to have to pay Debian's bandwidth bill either, and I assume that's why the Debian Policy Manual states that all installed binaries should be stripped. The lintian(1) package-checking utility even complains if you have non-stripped binaries in a package (as we do). Apple ships binaries with debugging information, but they ship those binaries on DVDs that cost $120/year. Ubuntu's (not yet implemented) idea of having symbols downloaded as needed to make up for the distribution of stripped binaries is pretty cunning, but having to install your OS twice and mess about with chroot just to build for x86 and x86_64 is a pain. Having to build separate packages is a pain too, and I don't really get the argument about saving bandwidth and disk space here (as opposed to with debugging symbols) because in the short term you're just forcing the 64-bit users to download two whole distributions, and in the long run, everyone's just running 64-bit anyway.

Until the next big shift.