Wednesday, September 16, 2009

I develop a lot of c++ code on my mac for cross-platform applications, and I've often wanted a convenient way to export a list of source files belonging to a given target in an XCode project. That way when one of my colleagues wants to create a new project on another platform (e.g. Visual Studio or makefile) I can tell them which subset of the source tree to compile for a given application. I've looked several times for a solution but never had any luck. So finally last night I did what any programmer would do and I wrote my own shell script to parse this information out of the XCode pbxproj file.

I'm sharing it here because I'm not sure where else to post it, so if anyone has any suggestions let me know. I also had to learn a bit about awk and sed and I'm not a bash programmer by trade so I'm sure there is a more efficient/elegant/obfuscated way to do this - if anyone has suggestions please do share.

The pbxproj file is coded by long hex codes - so the trick was to find the section of the file that defines the names of the targets, then work forwards from there using the hex codes to find the right lines of the file and figuring out the right awk/sed commands to parse out the relevant information.

I've only tested this with XCode 3.1.3 and with only a single project, so I don't know how robust it is. It's at least a start. Thanks to http://formatmysourcecode.blogspot.com/ for their quick source code formatter.

#!/bin/bash

# Dan Swain dan.t.swain at gmail.com 9/15/09

# Bash script to list the source files that are compiled for each target# in an xcode project file.# If an argument is specified, it is taken to be the name of the# xcode project - the program looks for argument.xcodeproj/project.pbxproj# If no argument is specified, the program searches for a .xcodeproject# directory in the current directory. This probably won't work# if there is more than one .xcodeproj directory.

# given the name of the project, this is the location of the project fileif [ $1 ]then PBXFILE=$1.xcodeproj/project.pbxprojelse XCODEPROJ=`find . -name '*.xcodeproj'` PBXFILE=$XCODEPROJ/project.pbxprojfi

# for each targetfor LINE in $LINESdo # the target name is on the previous line and is the second field # delimited by *'s, we also remove a leading and trailing space TARGETNAME=`awk 'NR=='$((LINE-1)) $PBXFILE | awk -F\* '{print $2}' | sed 's/^[ ]//;s/[ ]$//'`

# this is the hex code corresponding to the sources for this target SOURCES=`awk 'NR=='$((LINE+4)) $PBXFILE | awk '{print $1}'`

# find the line numbers containing the hex code for the sources SOURCESLINE=`sed -n '/'$SOURCES'/=' $PBXFILE` # there are two of these, so this leaves us with just the last one for SL in $SOURCESLINE do : # just want the last one done

# the first file is 4 lines below this SL=$((SL+4)) # loop over the subsequent lines until the awk command fails OK=0 while [ "$OK" = "0" ] do # the source file is the third field FILE=`awk 'NR=='$SL $PBXFILE | awk '{print $3}'` if [ $FILE ] then echo $FILE else OK=1 fi # next line SL=$((SL+1)) donedone