Wednesday, January 11, 2012

Removing Xcode 3 shared build settings from Xcode 4

This is about me getting a substantial amount of grey hair over the past couple of days, trying to hunt down a setting that would cause the current version of Xcode 4 to build my iOS projects to an unexpected, but not unfamiliar, taken over from Xcode 3, location, but not presenting any obvious way to revert that.


A little history


In Xcode3 you could use the preferences dialog to configure custom build output folders. This was necessary when you wanted to organize a somewhat more complex software into several cross-referencing Xcode projects and at the same time retain some sanity when linking and packaging it. Clint Harris Tutorial on shared libraries describes it in more detail.

The preferences dialog looked like this (image copied from Clint’s site, because I didn’t have any Xcode3 installation lying around anymore):

In my venerable Xcode 3 setup I configured the shared build output to /Users/ds/Documents/cc/SharedBuildOutput.


Introducing Xcode 4


In March of 2011 Apple released Xcode4, a major overhaul of the IDE with many new features and, of course, new configuration. At the time of me writing this in January 2012 the latest Xcode release is 4.2.1 and I installed most releases as upgrades on my MacBook Pro. The settings dialog for build locations looks like this in my current installation:

As you can see, there is no trace of the previously configured shared build output setting, let alone my custom directory.
Ok, so apparently this is the new way of doing things, and starting with new projects will surely apply.


Not so quick…


Despite what (I for) one would expect, nevertheless, this is what a brand new (iOS) project’s actual build setting look like (I filtered to just show the relevant parts):


Switching from the Combined to the Levels view shows that the setting is clearly not coming from the project itself, which explains why even a freshly created project could know about this old folder:


This clearly goes against the current Xcode standard of placing build products into so-called “Derived Data” subfolder folders with (partly) random names. Build scripts can use these by referring to them using the environment variables, but more often than not, leaving the (now already) trodden path of the new defaults will cause more trouble than it’s usually worth.

“How do I fix this?”, you might ask. Well, that’s what I asked myself, too, and it took me a few days to finally figure it out. Remember that Xcode 4 no longer shows this path in its Build Locations preferences, so this is obviously not getting us any further.


Circumventing the problem…


Changing the folder at the project level works, overriding the default. As soon as you have created a new project, you can change the “Build projects path” and “Intermediate Build Files Path” to simply build. This should be the same value that’s the default in a fresh Xcode 4 installation.

I like to keep my build settings in a separate .xcconfig file that makes it easier to share and change settings with other project contributors using version control. If you do that, you could also use that to override the old default by putting these lines it it:

SYMROOT = build
OBJROOT = build
However, that, too, requires you to remember making the change for each and every new project. Surely it would be better to get rid of that now-unwanted setup.


…or solving it


Albeit there is no UI preference setting to modify the SYMROOT and OBJROOT settings in Xcode 4 anymore, apparently it still honors them from the previous Xcode 3 installation. So in order to reset them, we need to know where they are stored. I did not know anything more than that it must be a user-specific setting, because a newly created account did not use it. So – after deleting everything from ~/Library/Developer/Xcode/DerivedData – I tried (in this order):

$ grep -r SYMROOT ~/Library/Developer 2>/dev/null
$ grep -r SYMROOT ~/Library/Application\ Support/Developer 2>/dev/null
$ grep -r SYMROOT ~/Library/Preferences 2>/dev/null

Well, actually I tried searching for Documents/cc/SharedBuildOutput first, but that also matched several archived applications. The last command revealed this:

Binary file ./com.apple.dt.Xcode.plist matches

Converting the first match to XML with plutil -convert xml1 -o tmp.xml com.apple.dt.Xcode.plist and searching inside it I found this:

<key>IDEApplicationwideBuildSettings</key>
<dict>
    ...
    <key>SYMROOT</key>
    <string>/Users/ds/Documents/cc/SharedBuildOutput</string>
    ...
</dict>

Instead of removing these two lines and converting the file back to its binary format, I deleted that entry with the handy little PrefSetter application by navigating to the com.apple.dt.Xcode domain and searching for SYMROOT in there. That way there is no risk of making any typos, damaging the file.


Do not forget to save the change!


Success!


Restarting Xcode and looking at the build settings of the very same “Test” project created earlier proves that the change had the desired effect:


Of course, as a last resort (maybe there are more problems with your Xcode settings?), you could also just delete – or rename – the com.apple.dt.Xcode.plist file and have Xcode start afresh, even though I noticed when I tried this, that several settings were left unchanged, e. g. Source Trees. These are apparently stored somewhere else…

1 comment:

Andras Bubics said...

Thanks! Been looking for a fix to this for a few months now :C