Making Xcode Work For You When Developing PrefPanes
Wednesday 18th November 2009The first few times I tried developing a Preference Pane in OS X, I had more than a few head-scratching, “what the heck do I do now?” kind of moments. Unlike a typical Mac OS X or iPhone project in Xcode, when you create a Preference Pane project from the built-in Xcode template, doing a ‘Build and Run’ doesn’t result in your project being run. In fact, as of Xcode 3.2.1 the ‘Build and Run’ item in the ‘Build’ menu is disabled ‘out of the box’. This is due to the fact that your project isn’t building an executable program, it’s building a .prefPane bundle/plug-in.
Getting ‘Build and Run’ (⌘+R) to work as you might expect for a PrefPane project (by building your .prefPane, then installing it in System Preferences.app and loading it) isn’t hard, but it’s not at all well documented.
My First Attempt
When I started working on my first PrefPane as a learning around two years ago, I wrote a macro in Keyboard Maestro that would fire when I pressed ⌘+R in Xcode. The macro would open my freshly built .prefPane (which makes System Preferences.app load it), wait 1 second, then hit the ‘Return’ key, which would install the new .prefPane by dismissing the following dialog:

This worked, but it had a lot of downsides. Firstly, I had to turn this macro on and off every time I changed from working on this particular PrefPane project to working on anything else so that ⌘+R would do what it should for other projects. Secondly, it didn’t allow me to debug the PrefPane, only run it. This is a serious impediment to development, especially if you don’t know what you are doing (which, at the time, I didn’t!).
When I returned to looking at PrefPanes for another project about a year ago, it occurred to me that there must be a better way…
A Better Way
To get Xcode to actually ‘Run’ something, you need to have an ‘Executable’. Since a PrefPane doesn’t generate an Executable (something that you can actually execute as a program), you’ll need to add a ‘Custom Executable’ to your Xcode project. To do this, go to the ‘Project’ menu, and select ‘New Custom Executable…’.

Call the Custom Executable ‘System Preferences’, and select the ‘System Preferences.app’ application in /Applications/ by clicking on the ‘Choose…’ button.
You can now Run and Debug System Preferences.app by pressing ⌘+R and ⌘+Y. That’s great, but it doesn’t install your .prefPane as part of the process, it just launches the System Preferences.app application.
System Preferences.app’s Hidden Command Line Argument
I found this out through trial and error, and I haven’t seen it documented anywhere, but the System Preferences.app application actually takes a command line argument, which is the path of a .prefPane to install.
To set this argument, go to the ‘Project’ menu, then select ‘Edit Active Executable “System Preferences”’. Click on the ‘Arguments’ tab at the top of this pane, then add a new command line argument that is the path of your built .prefPane bundle.

/Users/nick/Builds/Xcode/Debug/MyPrefPane.prefPane is the path to the .prefPane built for the MyPrefPane project when it is built in the ‘Debug’ configuration on my machine. Note that on my Xcode setup, I have a customised location for build products (/Users/nick/Builds/Xcode), so even if I move my PrefPane project folder around, this path won’t change. If you have Xcode setup to build in MyProject/build (which is the default), you’ll have a path that looks more like /Users/nick/Code/MyPrefPane/build/Debug/MyPrefPane.prefPane. If you move or rename your Xcode project folder, this path will change, and your project will break, so beware.
Also of note: this technique brings up the dialog shown above asking if you want to replace (or install, if it’s the first time) the .prefPane in question whenever you do a ‘Run’. Hitting ‘Return’ after a build isn’t a huge deal to me, but it would be nice to have this automated. Another command line argument for System Preferences.app could help here, but I’m not aware of the existence of such an option.
Why Doesn’t The Xcode Template Do This For Me?
There’s no good reason that I can think of why the default template doesn’t include System Preferences.app as a Custom Executable. There is, however, a good reason it doesn’t include the .prefPane path as a command line argument. The path is dependent on your Xcode configuration, and the path is fragile (by which I mean that if you renamed your Xcode project folder, “Run” would no longer install your .prefPane).
For Apple (or anyone else, for that matter) to make a template do all this for you, they’d have to allow the Executable ‘Argument’ fields to support Xcode variables. As of Xcode 3.2.1, I have been unable to work out a way to do this. In some fields in Xcode, you can use variables like $BUILT_PRODUCTS_DIR and $PRODUCT_NAME, to represent (not surprisingly), the Build Products Directory, and the Product Name of your current project. If the ‘Argument’ fields supported these variables, it should be possible to use something like $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.prefPane as a command line argument, which would not only be robust against configuration and path changes, but would mean that the setup I have described here could be built in to the Xcode Preference Pane project template itself, meaning that things would ‘just work’ out of the box.
Addendum
As pointed out by Rainer Brockerhoff in the comments, Xcode does support variables in Executable Arguments. The real problem is that for some reason $PRODUCT_NAME doesn’t work when using the default Xcode PrefPane template. Investigations continue…

Thursday 11th February 2010 at 12:30 am
That’s strange, things like $(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).prefPane work well for me in executable arguments…
Thursday 18th February 2010 at 3:40 pm
Rainer, you are correct, these variables do seem to work just fine in Executable Arguments, but there’s something else going on here. I’ve just done some testing, and have come to the conclusion that $(PRODUCT_NAME) doesn’t work properly for some reason when using the PrefPane project template.
Using this works as an executable argument:
But this doesn’t:
Often (usually?), PROJECT_NAME will be the same as PRODUCT_NAME for a PrefPane project. As long as they are the same, using PROJECT_NAME works, and means you wouldn’t have to configure anything unusual out of the box – an Xcode project template would be able to set all this up for you, which is the goal here.
The real question is: why is PRODUCT_NAME not working? I have checked, and the Target’s Build Settings has Product Name set as it should be, so I’m not sure why it doesn’t work as you would expect. Any ideas?
Friday 16th April 2010 at 10:22 am
With XCode 3.2.2, neither of these seem to be working for me. System preferences never asks to install the preference pane. I sure wish this would work as well.
Friday 16th April 2010 at 10:29 am
Actually I take that back. On the General tab of the custom executable you can “set the working directory to:” “Build Products directory”
Then simply put “$(PROJECT_NAME).prefPane” as argument.
Worked great!