Fri, 11 Mar 2005
As I don't like to fall too far behind with the times, today I decided to start updating our code base to use the new Objective-C @try/@catch exception handling system, replacing the old NS_HANDLER macros.
To do this however, you need to enable the -fobjc-exceptions build option on each project that needs it. This wouldn't be so terrible, except we have 20 some odd different project files in our repository currently. Updating each one by hand, which I've done in the past, gets to be real painful after about the third one.
Luckily, Xcode has an amazingly complete AppleScript dictionary:
This seems to be a little known fact about Xcode, but it's a real life saver in situations like this. Instead of spending the day manually clicking checkboxes, I just wrote the following Batch Updater script:
Download XcodeProjectBatchUpdater.scpt
(* Xcode Project Batch Updater *** (C) Copyright 2005, Rogue Amoeba Software, LLC
Configuration Options:
RelaunchXcodeForEachProject - Quit and relaunch Xcode for each project (or leave it open)
*)
property RelaunchXcodeForEachProject : true
on _updateProjectDocument(aPrjDoc)
tell application "Xcode"
repeat with aTarget in (every target of aPrjDoc)
--set newBuildSettings to {|GCC_ENABLE_OBJC_EXCEPTIONS|:"YES"}
--set build settings of aTarget to ((build settings of aTarget) & newBuildSettings)
end repeat
end tell
end _updateProjectDocument
on _updateProjectAtPath(aPrjPath)
set aPrjAlias to (POSIX file aPrjPath) as alias
tell application "Xcode"
open aPrjAlias
--set aPrjDoc to first item of (every project document whose path starts with aPrjPath
set aPrjDoc to current project document
my _updateProjectDocument(aPrjDoc)
if not RelaunchXcodeForEachProject then
close window of aPrjDoc
end if
end tell
end _updateProjectAtPath
on _gatherUserAcceptedProjects(aSearchPath)
set allPrjs to _gatherAllProjects(aSearchPath)
return choose from list allPrjs with prompt "Choose the projects to update:" default items allPrjs OK button name "Update" with multiple selections allowed
end _gatherUserAcceptedProjects
on _gatherAllProjects(aSearchPath)
set cmd to "find " & aSearchPath & " -type d \\( \\( -not \\( \\( -name .svn -and -prune \\) -or \\( -name build -and -prune \\) \\) \\) -and \\( -name '*.xcode' \\) \\) -print"
set results to do shell script cmd
set text item delimiters to ASCII character 13
return text items of results
end _gatherAllProjects
on run
set searchRootPath to POSIX path of (choose folder with prompt "Search for projects in:" default location (path to home folder))
if searchRootPath ends with "/" then
set text item delimiters to ""
set searchRootPath to (items 1 thru ((length of searchRootPath) - 1) of searchRootPath as list) as string
end if
repeat with aPrjPath in _gatherUserAcceptedProjects(searchRootPath)
if RelaunchXcodeForEachProject then
tell application "Xcode" to quit
delay 1
else
tell application "Xcode" to close every window
end if
try
_updateProjectAtPath(aPrjPath)
on error
set reply to display dialog "Failed to update project: '" & aPrjPath & "'" with icon caution buttons {"Stop", "Skip"} default button 2
if button returned of reply is not "Skip" then
return
end if
end try
end repeat
if RelaunchXcodeForEachProject then
tell application "Xcode" to quit
end if
end run
Heres a brief walkthrough of the script, since you need to modify the script to do anything useful with it.
1. The run handler first prompts you for a folder in which to look for project files in (and below of, it's recursive).
2. _gatherAllProjects() uses do shell script and `find` to locate the project files.
3. _gatherUserAcceptedProjects() prompts for which projects to update, since odds are there are some that shouldn't be updated.
4. _updateProjectAtPath() opens the project(s) in Xcode, and finds the "project document" reference and hands it off to _updateProjectDocument()
5. _updateProjectDocument() does actual work on the project. In our example script above, it would turn the GCC_ENABLE_OBJC_EXCEPTIONS build setting on. This is probably the only handler you'll need to modify.
There is one bug workaround in the script, RelaunchXcodeForEachProject. I found that if you try and keep Xcode open the entire time, after about the 4th or 5th project, it would start throwing Internal Errors. Quitting and relaunching it for each and every project alleviates the problem (most of the time, anyhow).
As with any batch update system, I advise to take some caution with using it, as you can quickly mangle all your projects. Having a version control system or recent backups in place before hacking away, is highly recommended.