Previous Entry Share Next Entry
Xcode: Build numbers and versioning with agvtool
Xcode includes agvtool — "Apple-generic versioning tool" — in the /Developer/Tools directory, a useful utility that can be used to easily apply build numbers to your software.

agvtool has a lot of options and will do a lot of things for you, so it may look complex at first glance. But getting started with it and using it for simple build number management is very straightforward.

The first thing you need to do is tell Xcode you'll be using agvtool. You do this by inspecting a target you want to version and selecting the Build tab. Be sure that you have All Configurations selected in the Configuration pop-up menu, and select Versioning in the Collection pop-up. For the value of the Versioning System setting, choose apple-generic. This tells Xcode to look for agvtool-generated version information to include in your project.

Next, you need to prepare the information that agvtool and Xcode will use to include version information in your software. You can do this by changing the Current Project Version setting to the floating-point build number that you want to use. If you're working on a new project, you should generally start with 1.

If you're building a library or framework, you should also set two other properties in the Linking settings collection. The Compatibility Version of your library is essentially the version of the API your library exports; you should set it to 1 to start with, and change it manually as necessary (which should not be often). The Current Library Version of your library is the current build version of the library, and will be kept in sync with the rest of the version information in the target by agvtool. For more information on these two properties, see the documentation for the -dylib_compatibility_version and -dylib_current_version flags in the ld(1) man page.

One other setting you may want to configure is your target's Version Info Prefix. When Xcode builds your project, it will actually generate a source code file with an exported double ProductNameVersionNumber and constant C string ProductNameVersionString containing the most up-to-date version information for your project. You can specify a prefix to use on these variables by adding a custom VERSION_INFO_PREFIX setting to your target's configurations, and setting it to the prefix (such as "CMH") that you need. This is most useful for libraries and frameworks, because you can provide extern declarations for these variables and your clients can use these to determine if they need to modify their behavior for different versions of your API.

There's one last thing you need to set up to use agvtool for a target: The CFBundleVersion key in your target's Info.plist file, if it has one. You can do this by switching to the Properties tab of the target inspector and modifying the Version field; set it to exactly the same string you used for the Current Product Version setting.

With all of this infrastructure in place, Xcode will generate build number information in your project when it's built and your application or library can access and make use of this information. In fact, Cocoa will do so automatically in your About panel — it will show your application's version as "Version CFBundleShortVersionString (CFBundleVersion)", providing immediate feedback on not just the "marketing version" of your software (e.g. 1.1) but the actual build number being used (e.g. 22).

I'm using the term build number a lot above, but what do I really mean when I say that? What I don't mean is a number that's incremented automatically every time you build in Xcode. That's a virtually meaningless number; it's likely to be in the thousands for even the simplest project by the time it ships. An agvtool build number is a version stamp for a version built by a more formal build process: When you are going to build your software for deployment (whether to testing or to release), that's when you increment the build number.

And that's where agvtool enters the picture: It's what actually increments your build number. So when it's time to build for deployment, first close your project and quit Xcode, since agvtool will be modifying the project file. Then in Terminal, in the directory containing your project, type the following at the prompt ("%" here):
 % /Developer/Tools/agvtool next-version -all
This will use agvtool to increment all of the appropriate version numbers in your project, including the CFBundleVersion keys in the Info.plist files for any versioned targets. Once this is done, you can check in your updated project file and any updated Info.plist files and build your software for deployment.

It sounds like a lot of work, but if you actually step through it, you'll find that it's only a few simple steps to provide this very useful information to your users and developers.

  • 1

Auto-incremented Number Not Meaningless

I'd like to submit that an auto-incremented build number (for every time you build) is not meaningless. Consider this scenario (which I work with regularly):

Suppose you're working with a group of beta testers who don't all follow the same schedule; some get builds every now and again, some get builds all at the same time with everyone else. If someone asks for a build, I want to be able to fire off a build as quickly as possible that's easily distinguishable from every other build. An auto-increment would help with this. agvtool does next to nothing for me here, because if the purpose is for semi-major release, that's not what I would want... these are just very incremental, testing-only builds.

Just my 2 cents.

Re: Auto-incremented Number Not Meaningless

Thanks, this was very informative :)

Almost two years after this post and it just helped me expliain why one of our libraries can't decrement the version number without breaking pretty much everybody else who depends on that library.


In Xcode 3.2 (and possibly earlier versions) agvtool has moved to /Developer/usr/bin/agvtool thus the command is now:
agvtool next-version -all

iPad app version challenge

Dear Chris,

Thanks for the excellent post, i am just stuck at the moment with the version issue.

I am trying to distribute the enterprise app to my fellow colleagues. Whenever i try to download it on an ipad using the url. it loads the previous version instead of the new one. I did all the steps as per your blog, i also tried to clear all cache on server, restarted the services. but it still is sticking to the old version. any idea from where this might be coming?

  • 1

Log in