A Closer Look At Apple’s Universal Binaries

Universal Binary

I think the idea behind Apple's / NeXT's concept of a Universal Binary is a great idea. With the different system architectures available for Apple computers these days (32-bit and 64-bit PowerPCs, 32-bit and 64-bit Intels) it makes sense to be able to package up specific code for each processor into one bundle so you don't have to choose between four different program downloads tailored for each processor.

How Universal Binaries Work

From what I can surmise [given I'm mostly a scripting language programmer cough!], a Universal Binary is a Mac OS X application that has had its code compiled multiple times to run natively on multiple processors, such as the PowerPC and the newer Intel chips. When an application is executed, Mac OS X checks the application's header (if it is not a Universal Binary on a compatible platform it kicks Rosetta into action and runs it in emulation mode), then runs the appropriate code for your processor architecture.

The beautiful thing is to the end user, it just looks and runs like any other program, regardless of the platform their using.

It then goes without saying that applications that have multiple compiled code parts will be larger, but not necessary double in size. Most programs use resources, such as HTML files, images, text and so forth, that would be shared among the two different programs within the application. And because only one of the compiled parts is loaded into memory, there generally isn't any performance hit.

Checking Universal Application Binaries

I think also from a developers standpoint Universal Binaries are a very elegant solution. I didn't know this until recently, but if you want to check what processors are natively supported by a program, you can use the file command in your Terminal. For example, to check what processors BASH natively supports, you can type:

file /bin/bash

And if you're running a later version of Mac OS X Tiger it should show:

/bin/bash: Mach-O universal binary with 2 architectures
/bin/bash (for architecture i386):      Mach-O executable i386
/bin/bash (for architecture ppc):       Mach-O executable ppc

So we have a program here compiled to run natively on 32-bit PowerPC's (such as the G3 and G4) and i386 processors (such as the first generation Intel Core Duo). Had this program not been Universal (such as Photoshop CS2 or Office 2004), it would have shown only ppc.

Removing Processor Code from Applications

As mentioned above though, the downside to having an application with many different compiled parts for different processors is that they can be larger. Some might argue that it also doesn't make sense to have code that wasn't compiled for their machine to be sitting there taking up hard disk space.

If you want to remove unnecessary processor support from a Universal Binary, you can use the lipo command… aptly short for liposuction.

To keep just Intel code:
lipo -thin i386 -output output_file input_file

To keep just PowerPC code:
lipo -thin ppc -output output_file input_file

Be VERY careful though when removing processor support from applications though. If PowerPC programs use resources from a universal program, removing the PowerPC code will break support and crash the application using the resource. Some programs will even refuse to run if they believe they have been tampered with.

Alteratively a somewhat safer way to remove code is to use TrimTheFat, a graphical program that has a built in blacklist of programs that it will refuse the compact because of known problems after lipo'ing. I'd still be very careful though.


Favourite this blog on Technorati! apple, next, mac os, mac os x, mac os x tiger, os x tiger, universal binaries, powerpc, intel core duo, intel core 2 duo, lipo, trimthefat, executables, binaries, applications