Jon Simpson

Versioning & Xcode 4 Info.plist Processing

4 Mar 2012 — xcode, git, versioning, plist

On upgrading to Xcode 4.3 (now as a normal app bundle from the Mac App Store, rather than an installer), I found that the usual git describe output we use to generate long versioning information for our apps has gained white space between the dashes (e.g. 1.0rc14-12-g45b2748 becomes 1.0rc14 - 12 - g45b2748 in the app).

We’ve been using Fraser Hess’ Git build tagging technique since the outset of the project and it’s been extremely useful to see at a glance whether builds contains major changes off the latest tag, and which git revision they represent at a glance.

After doing some initial investigation, the output of git describe is still being captured without the spaces into Xcode and placed into the intermediary #define. Conventional wisdom before Xcode 4 determined that the CFBundleShortVersionString field in an App’s Info.plist could take any value, and the CFBundleVersion should be a monotonically increased integer, which was used by the system for programmatic use (determining latest versions etc.) However, it appears that Apple have changed the definitions of these fields, and now CFBundleShortVersionString is strictly defined as expecting a typically formatted marketing version number.

CFBundleShortVersionString (String - iOS, Mac OS X) specifies the release version number of the bundle, which identifies a released iteration of the application. The release version number is a string comprised of three period-separated integers.

Apple Developer - Information Property List Key Reference: Core Foundation Keys

(As an aside, it would be helpful if Apple would expose the revision information for their Developer Documentation, so it’d be possible to track down when exactly this definition changed.)

Given this information, it would appear Xcode 4.3 is now parsing the CFBundleShortVersionString field with the preprocessor where previous versions have left it verbatim. Our app makes use of the version string for client version checking against a remote API, so keeping the additional padding is not ideal. A quick look at Apple’s notes on Info.plist pre-processing reveals that tokens will have whitespace appended to them unless the -traditional flag is set on the Info.plist preprocessor flags of the project, in testing though the -traditional flag has no effect on this space padding around hyphens.

To avoid the pre-processor entirely (and avoid the need for a separate Version target), the same result can be achieved by directly writing the output of git describe into the plist file using plistbuddy. For now we’re using a build phase which runs the following script.

GIT=`which git`
GIT_DESCRIBE=`$GIT describe`
echo "Git describe output: $GIT_DESCRIBE"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $GIT_DESCRIBE" "Info.plist"

This is definitely a hack but less invasive (no extra target, magic values set in the Info.plist) than the original solution and means that Xcode can see the values in the plist from the last build (the UI can show the ShortVersionString from last build)- the downside with this is that we’re blindly ignoring any constraints that the toolchain want to place on the key, as it’s written in without their involvement.