About | Buy Stuff | Industry Watch | Learning Curve | Products | Search | Twitter
Home » Learning Curve

Intel, Not Universal!

OS X users are increasingly protective of their disk free space.


As more and more Apple Intel boxes roll out more and more OS X users are thinking about what it means to be 'universal'. Some say it's good to leave things as they are; others want to save disk space; but there's no general agreement on either side as to what the benefits would be.

CAFEBABE or FEEDFACE

Universal binaries didn't start with OS X: NeXTSTEP used 'fat binaries' as did old MacOS. NeXTSTEP fat binaries ran on several platforms all at once; MacOS fat binaries (CFM/PEF packed in both forks) were used in the transition from 68000 to PowerPC.

Current OS X fat or 'universal' binaries let applications run on either Apple PowerPC or Apple Intel computers, either 32-bit or 64-bit. The debate's been about whether performing a 'liposuction' on these binaries - removing the unused portion for absent hardware - is worth the trouble.

Universal binaries - as their Mach-O counterparts - are easy to recognise. The former have the magic 'CAFEBABE' at offset 0; the latter have 'FEEDFACE' - this seen in hexadecimal.

Removing the unused portion of a fat binary - 'thinning it' - is easily performed from the command line.

/usr/bin/lipo <target> -thin <platform> -output <target>.out; /bin/mv <target>.out <target>

Where <target> is the binary to be 'thinned' and <platform> is the current computer hardware platform, eg i386 or ppc.

The program file can be used to determine if a binary is fat and suitable for 'thinning'.

An Opening Act

Before delving into the exigencies of dealing with universal binaries it might be interesting to see how the other 90% live. Users of Microsoft Windows won't get universal binaries - at least not yet - but their program files are self contained: code, data, and resources are all found in the same file.

Windows programs still have an MS-DOS header with a jump address to Dave Cutler's 'PE' ('portable executable') headers. It's there one begins to find the actual code and data sections of the program.

But the PE headers also contain information about 'resource' sections - all in binary format and all baked into the same file. A resource section actually has a number of resource 'directories' divided up according to resource type. The bottom line is that if a user wants to 'thin' things out on Windows said user will need a special resource editor - navigating around on disk won't do it. And Microsoft's own resource tools don't like saving back to a finished program file anymore.

The point - and it's not been made yet - is that thinning a fat binary is only the tip of the iceberg: if you want to clean up your downloaded software you have a bit farther to go. But at least on OS X you can go there. All on your own.

Main Attraction

When it comes to serving up well packaged software for one's own operating system, Apple and Microsoft are 180° diametric opposites. Microsoft are amongst the worst on the Windows platform, surpassed easily by many a third party vendor; Apple are amongst the best on theirs, and many third party vendors would do well to follow their good example.

Unfortunately too few bother.

A Test Case

Perhaps the best way to see exactly what can be saved by attending to fat binaries and other concerns is to download a product at random off the Internet and get to it. But seeing as there are a number of 'thinning' applications now available for OS X, perhaps the best place is to start there.

Xslimmer thins binaries and removes localisation files. The download's available here. It's 1.7 MB (1744796 bytes).

When the DMG is mounted it becomes 315 items for 3298066 bytes or 7952 blocks (4071424 bytes) with 104914 bytes in resource forks. The app bundle itself is 304 items for 3157426 bytes or 7424 blocks (3801088 bytes) with 0 bytes in resource forks.

304 items, 3157426 bytes, 7424 blocks, 0 bytes in resource forks.

Xslimmer.app/Contents
Xslimmer.app/Contents/Frameworks
Xslimmer.app/Contents/Frameworks/Growl.framework
Xslimmer.app/Contents/Frameworks/Growl.framework/Growl
Xslimmer.app/Contents/Frameworks/Growl.framework/Headers
Xslimmer.app/Contents/Frameworks/Growl.framework/Headers/Growl.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Headers/GrowlApplicationBridge-Carbon.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Headers/GrowlApplicationBridge.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Headers/GrowlDefines.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Resources
Xslimmer.app/Contents/Frameworks/Growl.framework/Resources/Info.plist
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Growl
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Headers
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/Growl.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlDefines.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Resources
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/A/Resources/Info.plist
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Growl
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Headers
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Headers/Growl.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Headers/GrowlApplicationBridge-Carbon.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Headers/GrowlApplicationBridge.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Headers/GrowlDefines.h
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Resources
Xslimmer.app/Contents/Frameworks/Growl.framework/Versions/Current/Resources/Info.plist
Xslimmer.app/Contents/Frameworks/Sparkle.framework
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/NSApplication+AppCopies.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/NSFileManager+Authentication.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/NSFileManager+Verification.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/NSString+extras.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/RSS.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/Sparkle.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUAppcast.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUAppcastItem.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUAutomaticUpdateAlert.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUConstants.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUStatusChecker.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUStatusController.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUUnarchiver.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUUpdateAlert.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUUpdater.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Headers/SUUtilities.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/Info.plist
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/SUStatus.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/SUStatus.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/SUStatus.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Resources/SUStatus.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Sparkle
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/NSApplication+AppCopies.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/NSFileManager+Authentication.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/NSFileManager+Verification.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/NSString+extras.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/RSS.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/Sparkle.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUAppcast.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUAutomaticUpdateAlert.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUConstants.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUStatusChecker.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUStatusController.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUUnarchiver.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUUpdateAlert.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUUpdater.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Headers/SUUtilities.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Info.plist
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/SUStatus.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/A/Sparkle
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/NSApplication+AppCopies.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/NSFileManager+Authentication.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/NSFileManager+Verification.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/NSString+extras.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/RSS.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/Sparkle.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUAppcast.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUAppcastItem.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUAutomaticUpdateAlert.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUConstants.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUStatusChecker.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUStatusController.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUUnarchiver.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUUpdateAlert.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUUpdater.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Headers/SUUtilities.h
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/Sparkle.strings
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUAutomaticUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUUpdateAlert.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUUpdateAlert.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUUpdateAlert.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/Info.plist
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/SUStatus.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/SUStatus.nib/classes.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/SUStatus.nib/info.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Resources/SUStatus.nib/keyedobjects.nib
Xslimmer.app/Contents/Frameworks/Sparkle.framework/Versions/Current/Sparkle
Xslimmer.app/Contents/Info.plist
Xslimmer.app/Contents/MacOS
Xslimmer.app/Contents/MacOS/Xslimmer
Xslimmer.app/Contents/PkgInfo
Xslimmer.app/Contents/Resources
Xslimmer.app/Contents/Resources/About.png
Xslimmer.app/Contents/Resources/action.png
Xslimmer.app/Contents/Resources/actionPressed.png
Xslimmer.app/Contents/Resources/advanced.png
Xslimmer.app/Contents/Resources/Apps.png
Xslimmer.app/Contents/Resources/Back.png
Xslimmer.app/Contents/Resources/Black List.png
Xslimmer.app/Contents/Resources/black.plist
Xslimmer.app/Contents/Resources/Clear.png
Xslimmer.app/Contents/Resources/English.lproj
Xslimmer.app/Contents/Resources/English.lproj/Credits.rtf
Xslimmer.app/Contents/Resources/English.lproj/dropMessage.png
Xslimmer.app/Contents/Resources/English.lproj/InfoPlist.strings
Xslimmer.app/Contents/Resources/English.lproj/Localizable.strings
Xslimmer.app/Contents/Resources/English.lproj/MainMenu.nib
Xslimmer.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
Xslimmer.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib
Xslimmer.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/English.lproj/Preferences.nib
Xslimmer.app/Contents/Resources/English.lproj/Preferences.nib/classes.nib
Xslimmer.app/Contents/Resources/English.lproj/Preferences.nib/info.nib
Xslimmer.app/Contents/Resources/English.lproj/Preferences.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/English.lproj/slim.png
Xslimmer.app/Contents/Resources/English.lproj/slimDisabled.png
Xslimmer.app/Contents/Resources/English.lproj/slimGlow.png
Xslimmer.app/Contents/Resources/English.lproj/slimPressed.png
Xslimmer.app/Contents/Resources/folder.tiff
Xslimmer.app/Contents/Resources/footer.png
Xslimmer.app/Contents/Resources/French.lproj
Xslimmer.app/Contents/Resources/French.lproj/Credits.rtf
Xslimmer.app/Contents/Resources/French.lproj/dropMessage.png
Xslimmer.app/Contents/Resources/French.lproj/Localizable.strings
Xslimmer.app/Contents/Resources/French.lproj/MainMenu.nib
Xslimmer.app/Contents/Resources/French.lproj/MainMenu.nib/classes.nib
Xslimmer.app/Contents/Resources/French.lproj/MainMenu.nib/info.nib
Xslimmer.app/Contents/Resources/French.lproj/MainMenu.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/French.lproj/Preferences.nib
Xslimmer.app/Contents/Resources/French.lproj/Preferences.nib/classes.nib
Xslimmer.app/Contents/Resources/French.lproj/Preferences.nib/info.nib
Xslimmer.app/Contents/Resources/French.lproj/Preferences.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/French.lproj/slim.png
Xslimmer.app/Contents/Resources/French.lproj/slimDisabled.png
Xslimmer.app/Contents/Resources/French.lproj/slimGlow.png
Xslimmer.app/Contents/Resources/French.lproj/slimPressed.png
Xslimmer.app/Contents/Resources/Get Info.png
Xslimmer.app/Contents/Resources/globe.png
Xslimmer.app/Contents/Resources/grayedGlobe.png
Xslimmer.app/Contents/Resources/HistoryPrefsIcon.png
Xslimmer.app/Contents/Resources/Intel.png
Xslimmer.app/Contents/Resources/Italian.lproj
Xslimmer.app/Contents/Resources/Italian.lproj/Credits.rtf
Xslimmer.app/Contents/Resources/Italian.lproj/dropMessage.png
Xslimmer.app/Contents/Resources/Italian.lproj/Localizable.strings
Xslimmer.app/Contents/Resources/Italian.lproj/MainMenu.nib
Xslimmer.app/Contents/Resources/Italian.lproj/MainMenu.nib/classes.nib
Xslimmer.app/Contents/Resources/Italian.lproj/MainMenu.nib/info.nib
Xslimmer.app/Contents/Resources/Italian.lproj/MainMenu.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/Italian.lproj/MainMenu.nib/objects.nib
Xslimmer.app/Contents/Resources/Italian.lproj/Preferences.nib
Xslimmer.app/Contents/Resources/Italian.lproj/Preferences.nib/classes.nib
Xslimmer.app/Contents/Resources/Italian.lproj/Preferences.nib/info.nib
Xslimmer.app/Contents/Resources/Italian.lproj/Preferences.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/Italian.lproj/slim.png
Xslimmer.app/Contents/Resources/Italian.lproj/slimDisabled.png
Xslimmer.app/Contents/Resources/Italian.lproj/slimGlow.png
Xslimmer.app/Contents/Resources/Italian.lproj/slimPressed.png
Xslimmer.app/Contents/Resources/Magic Wand.png
Xslimmer.app/Contents/Resources/minus.png
Xslimmer.app/Contents/Resources/minusDisabled.png
Xslimmer.app/Contents/Resources/minusPressed.png
Xslimmer.app/Contents/Resources/monolingual.png
Xslimmer.app/Contents/Resources/multilingual.png
Xslimmer.app/Contents/Resources/plus.png
Xslimmer.app/Contents/Resources/plusDisabled.png
Xslimmer.app/Contents/Resources/plusPressed.png
Xslimmer.app/Contents/Resources/PowerPC.png
Xslimmer.app/Contents/Resources/Preferences.png
Xslimmer.app/Contents/Resources/ProgressBarBlack.png
Xslimmer.app/Contents/Resources/ProgressBarBlue.png
Xslimmer.app/Contents/Resources/ProgressBarEndBlack.png
Xslimmer.app/Contents/Resources/ProgressBarEndBlue.png
Xslimmer.app/Contents/Resources/ProgressBarEndGray.png
Xslimmer.app/Contents/Resources/ProgressBarEndGreen.png
Xslimmer.app/Contents/Resources/ProgressBarEndRed.png
Xslimmer.app/Contents/Resources/ProgressBarEndWhite.png
Xslimmer.app/Contents/Resources/ProgressBarGray.png
Xslimmer.app/Contents/Resources/ProgressBarGreen.png
Xslimmer.app/Contents/Resources/ProgressBarRed.png
Xslimmer.app/Contents/Resources/ProgressBarWhite.png
Xslimmer.app/Contents/Resources/Remove.png
Xslimmer.app/Contents/Resources/report.png
Xslimmer.app/Contents/Resources/reportHighlighted.png
Xslimmer.app/Contents/Resources/reportPressed.png
Xslimmer.app/Contents/Resources/restore.png
Xslimmer.app/Contents/Resources/restoreHighlighted.png
Xslimmer.app/Contents/Resources/restorePressed.png
Xslimmer.app/Contents/Resources/Reveal.png
Xslimmer.app/Contents/Resources/smallReveal.png
Xslimmer.app/Contents/Resources/smallRevealHighlighted.png
Xslimmer.app/Contents/Resources/smallRevealPressed.png
Xslimmer.app/Contents/Resources/Spanish.lproj
Xslimmer.app/Contents/Resources/Spanish.lproj/Credits.rtf
Xslimmer.app/Contents/Resources/Spanish.lproj/dropMessage.png
Xslimmer.app/Contents/Resources/Spanish.lproj/InfoPlist.strings
Xslimmer.app/Contents/Resources/Spanish.lproj/Localizable.strings
Xslimmer.app/Contents/Resources/Spanish.lproj/MainMenu.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/MainMenu.nib/classes.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/MainMenu.nib/info.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/MainMenu.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/MainMenu.nib/objects.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/Preferences.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/Preferences.nib/classes.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/Preferences.nib/info.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/Preferences.nib/keyedobjects.nib
Xslimmer.app/Contents/Resources/Spanish.lproj/slim.png
Xslimmer.app/Contents/Resources/Spanish.lproj/slimDisabled.png
Xslimmer.app/Contents/Resources/Spanish.lproj/slimGlow.png
Xslimmer.app/Contents/Resources/Spanish.lproj/slimPressed.png
Xslimmer.app/Contents/Resources/statusBarBackground.png
Xslimmer.app/Contents/Resources/Stop.png
Xslimmer.app/Contents/Resources/Universal Binary.png
Xslimmer.app/Contents/Resources/Xslimmer.icns
Xslimmer.app/Contents/Resources/XslimmerLicenseDoc.icns

Thinning the three binaries within will save approximately 300 KB; removing a few localisation files will save a bit more; but looking twice at the contents of the download is something else entirely. After a total clean the app package for either i386 or ppc is only 93 items. The i386 build uses 887334 bytes in 2072 blocks; the ppc build uses slightly more: 1069894 bytes in 2432 blocks. In both cases 3/4 of the download have happily disappeared, saving 3 MB (out of 4) for this app alone.

There are several issues with Xslimmer but they're not atypical.

  • Framework headers have been included.
  • Resources directories (and their contents) have been duplicated.
  • Symlinks to framework binaries have been replaced by duplicates.
  • One of the embedded frameworks has three localisations; the other has two.
  • Several images were not compressed, remaining at twice their necessary size.
  • Extraneous Interface Builder helper files were not removed prior to packaging.
  • Symlinks to current framework versions have been replaced by entire duplicates.
  • A help book is specified but not found.
    <key>CFBundleHelpBookFolder</key>
    <string>Help</string>
    <key>CFBundleHelpBookName</key>
    <string>Xslimmer Help</string>
  • The application icon is incorrectly specified.
    <key>CFBundleIconFile</key>
    <string>Xslimmer</string>
  • The main i386 binary can't be stripped as there's a linkage error in it.

    /usr/bin/strip: object: Xslimmer malformed object (unknown flavor for flavor number 0 in LC_UNIXTHREAD command 15 can't byte swap it)

[It's not germane but it's perhaps worth mentioning: this particular piece of software will nag about updates. See below.]

Software Update Feed URL
    <key>SUFeedURL</key>
    <string>http://www.xslimmer.com/releases.xml</string>

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
    <channel>
        <title>Xslimmer Changelog</title>
        <link>http://www.xslimmer.com/releases.xml</link>
        <description>Recent Xslimmer releases</description>
        <language>en</language>
        <item>
            <title>Xslimmer 1.2.2</title>
            <description>http://www.xslimmer.com/download/XslimmerReleaseNotes_1.2.2.html</description>
            <pubDate>Sat, 24 Feb 2007 01:31:11 +0000</pubDate>
            <enclosure sparkle:version="1.2.2" url="http://www.xslimmer.com/download/Xslimmer_1.2.dmg" length="1744796" type="application/octet-stream"/>
        </item>
    </channel>
</rss>

And there's to remember: that the disk space used is calculated by the number of 'clusters' used: a file of a single byte still takes up 4 KB.

Reducing the disk space from a near 4 MB to just over 1 MB (PowerPC) and 860 KB (Intel) isn't a meagre improvement.

Bottom Line

As things stand today - and until third party vendors more consistently follow Apple's good example - settling for simply 'thinning' binaries and removing unused localisation files will cut into but a small part of the total waste. [The example given above is the rule rather than the exception.]

But at least on OS X there's something you can do about it.

See Also
Rixstep Reviews: The Very Ugly
Mac OS Hints: Strip x86 code from fat binaries

About | ACP | Buy | Forum | Industry Watch | Learning Curve | Search | Twitter | Xnews
Copyright © Rixstep. All rights reserved.