NOTE!: It’s now the year 2020 and I believe this technique no longer works in the latest versions of xcode. I have archived the github repo. I’ve left everything public so the information still exists. What follows is my original article from 2014…
There have been times when building xcode projects from terminal has been very convenient, i’ve also done it in a lot of scripts, however there is a drawback to this technique and I hope to solve it in this article. That is drawback is
Currently there is no way of adding files to a project without opening up Xcode and doing it manually.
For automated builds this is a major drawback! Want to dump resources into your project and build from command line? Too bad you’re gonna have to open up Xcode and add the files to the project yourself. Want to use a separate IDE to create your .h and .m files and then build the project through a script? again too bad…
I was very surprised at this so I set out to research the ‘.xcodeproj’ file format and find a solution and here’s what I found.
Firstly, this may not be a surprise but the .xcodeproj file, like many files in OSX is actually just a container for many more files (right click any .xcodeproj select “Show package contents” and you will see what I mean)
The important file in this case, the one that Xcode uses to keep track of the project’s state is ‘project.pbxproj’.
As far as I can tell .pbxproj is a completely undocumented format (publically) on the plus side it does have a ‘JSON like’ structure. To explore it I started to add different file types to a project and studied the changes in the .pbxproj entries.
I saw that the comments in the .pbxproj are actually very useful, for example “/* Begin PBXCopyFilesBuildPhase section */“ tells us that the items listed are destined for the copy file build phase and the ‘files’ array contains the ID for each file to be added in that section. Every file in your Xcode project has a unique ID generated by Xcode and you can find every file’s ID by taking a look in the ‘PBXFileReference’ section. An example entry in this section can be seen below.
B240659C199957A4000782C3 /* LukesProjectTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LukesProjectTests.m; sourceTree = ""; };
This entry translates to:
B240659C199957A4000782C3 = Entry ID
PBXFileReference = Entry type
sourcecode.c.objc = File type
LukesProjectTests.m = Relative location
With this knowledge, I quickly wrote a small command line application in C++ called “Xcode Proj Adder” to add a file to an Xcode project from command line. You can find links to the application and source code at the end of the article.
Adding files to an Xcode project through command line is now as simple as entering this
$ ./XcodeProjAdder -XCP /Users/jimjohn/Products/TestProj.xcodeproj -SCSV ../tst1.cpp,../tst2.cpp,../tst1.h
the -XCP parameter supplies the fully qualified path of ‘.xcodeproj’ (the project you want to add files to) and -SCSV is a CSV list of source file locations relative to the .xcodeproj file (In this example the .cpp files are in the folder above the .xcodeproj), when adding the files to your Xcode project the tool also creates a backup incase you want to remove the files you just added, to revert the project back to the state it was before you added these files you can run the following command.
$ ./XcodeProjAdder -XCP /Users/jimjohn/Products/TestProj.xcodeproj -RESTORE
I have found this functionality useful for files that are supposed to be updated with every run of a script, an example is a project where images are constantly getting updated by a designer. I have my Xcode project with none of the images added to it, then I run a script that uses this tool to add all the latest images to the project from a specific folder, the script then builds the project through command line and lastly uses the tool to ‘restore’ the project removing the images ready for next run, this ensures that when built the project always has the most up-to-date images.
Get the tool
The Xcode-Proj-Adder tool is available Here (You may need to run chmod a+x XcodeProjAdder
to make it executable)
The source is also available on GitHub
Xcode Proj Adder is confirmed working with Xcode versions 4,5 and 6. It looks like the .pbxproj file format has not changed in a very long time so I expect this to be my solution for at least a while.