Generating Xcode Schemes Programatically


#1

Im in the process of setting up our build server to build plugins but I’m a little stuck with the clean/xcodebuild stage as the PJ doesn’t create a the .xcscheme files automatically. Therefore, my

xcodebuild -scheme "$PRODUCT_NAME - All" -configuration "$CONFIG" clean
xcodebuild -scheme "$PRODUCT_NAME - All" -configuration "$CONFIG"

commands fail.

  1. Does anyone know how to generate these schemes without having to open the Xcode UI?
  2. Failing that, do you know if we just omit the -scheme option and build all of the schemes (which is the default behaviour), if this is actually much different to specifying the - All scheme?

#2

Edit the All scheme and click the shared tick box at the bottom. This will create a new file inside your Xcode project. If you browse inside the Xcode project (right click and select “Show Package Contents”) then go into xcsharedata >> xcschemes you should see a file such as “Project Name - All.xcscheme”, commit this file to your repo and the build server should work just fine.


#3

Sorry, I should have mentioned that we don’t store anything that the PJ creates on the build server. This keeps our repository small and clean and avoid problems with making local changes to the IDE files which can happen either by accident or because Xcode has generated some changes to the PJ created text.

What I’d ideally like to know is if I leave out the the -scheme option (so it defaults to building all the targets), does building the - All target along with all the others mean that every target is built twice (once for the All and independently) or is xcodebuild smart enough to know that the targets have already been compiled?

The other thing I’ve noticed is that you can specify a -target option which may do the same thing in practice as the -scheme option. I’m testing this now but if anyone else has this workflow I’d be interested in your approaches.


#4

We do the same with lean .jucer projects (no JuceLibraryCode nor IDE projects in the repo). Our build builds a fresh Projucer, gets it to save the IDE projects from the command line then builds the plugin project.

This is command that our Jenkins server uses:
/usr/bin/xcodebuild -target "MyPlugIn (All)" -configuration Release build INSTALL_PATH=/Users/Shared/Jenkins/Home/workspace/MyPlugInBuild/mac DEBUG_INFORMATION_FORMAT=dwarf-with-dsym DWARF_DSYM_FOLDER_PATH=/Users/Shared/Jenkins/Home/workspace/MyPlugInBuild/macsym

(Forcing the dSYM generation too and allowing these to be archived easily.)

I can’t see in the log that it causes it to build things twice unnecessarily.


#5

The Projucer wont write over your shared schemes. We also use the .jucer file to track our project changes. Although it’s possible to build without the schemes option by using the target option I don’t recommend it as I’ve found a couple of oddities with xcodebuild when you don’t!

To see what I mean try the following. In xcode do a build and take a copy of all the exported symbols. Then using xcodebuild call your command without the scheme option but pass in the extra option “-showBuildSettings” now if you compare the two they should be identical except some temporary file paths. Great you might say exactly what you expect… but now run xcodebuild without the -showBuildSettings command, and compare that with the other two.

You should’ve notice a couple of differences, from memory it’s something to do with the derived data path. I’ve no idea if this is a bug or not (although it certainly seems like it), unfortunately due to the protection we use and a pre-build script we have to call when adding that protection it caused us some serious issues that took quite a while to track down. Essentially this other script was calling xcodebuild with the -showBuildSettings command and was getting the path to the derived data wrong, but only on command line builds. This resulted in it throw a wobbly about something later on in the script. Unless your adding protection of the same nature you’re probably not going to hit this issue but as a result I would still recommend sharing the schemes.


#6

@Anthony_Nicholls: Are you using the Legacy derived data path in Xcode?

Cheers,

Rail


#7

We were which if I remember correctly also “fixes” the issue, I think this only works because it seems xcodebuild is probably using the legacy option when you don’t pass the scheme or the showBuildSettings argument. However it means asking every developer to remember to change that setting when they set-up a new system and to remember to do it on our build servers. It was just annoying plus there are tools that although we’re not using at the moment insisted on a scheme such as xctool.


#8

Sounds about right :smiley:

Cheers,

Rail


#9

Is there a consensus on whether it’s better to use -target or -scheme with xcodebuild? I’d like to avoid checking in .xcscheme files to the repository and only check in .jucer files, if at all possible…


#10

We used to use -target, in most cases it works just fine but, we found there were cases where some differences occur (see the list of exports in the pre/post build steps, a couple of the variables have some differences), so annoyingly to get identical behaviour between our command line builds and the builds developers were making locally from Xcode we started committing shared schemes as well as the jucer files. The other negatives of checking in just a jucer file (although it is what we do) are you need a Projucer build or you need to build the Projucer before you build anything else (which adds to the build time). Also I’ve not had success using the Projucer on a headless linux machine - maybe others have?


#11

Thanks. I took a look at the exports, and it seems as if the only differences are some build/file locations (related to DerivedData locations, it appears).