Making Sense of xcodebuild Arguments
Xcode projects, workspaces, targets and schemes -- better understand what each of these arguments means in an xcodebuild command.
xcodebuild is a command-line tool that offers the ability to build and test your Xcode projects. It is a pretty powerful tool – particularly for running CI jobs for macOS and iOS – but to use it well you need to have a solid understanding of several Xcode concepts that will inform the arguments that you pass when you call xcodebuild in the terminal. Specifically, you’ll need to have a solid handle on targets, schemes, projects, and workspaces.
We’ll define each below, and then demonstrate how they can each figure into an xcodebuild command.
An Xcode project is a repository that contains all the files, resources, and information that Xcode needs to compile one or more products. Within the project directory, you’ll find all the elements Xcode needs to build the various products that your app needs – this can include the app itself, libraries that the app depends on, and tests to be run against the compiled app.
The project also maintains the relationships between these various products. Moreover, it contains one or more targets, which specify how Xcode should build a single, given product.
Finally, the project defines default build settings for all the targets in the project, which further inform the build process.
It is worth noting that Swift Package Manager projects don’t include a project file. You can read more about creating a standalone Swift package with Xcode here.
A workspace is an Xcode document that groups projects and other documents so you can work on them together. A workspace can contain any number of Xcode projects, plus any other files you want to include. In addition to organizing all the files in each Xcode project, a workspace provides implicit and explicit relationships among the included projects and their targets.
An Xcode target specifies a single product to be built from a set of files in an Xcode project or workspace. It also inherits build settings from the project that tell Xcode how to build the target. In the simplest build, there will only be one target, which will specify an iOS, macOS, or watchOS app, etc., and will inherit instructions from the project that will tell Xcode how to build the target.
More commonly, a project will have multiple targets, which each specify a single product to be built that is related to other products associated with the project. For example, the product in question could be the app itself, or it could be something that the app will depend on, like a library, or tests to run against the compiled app. However, regardless of the number of targets in a project or workspace, each target will still have a one-to-one relationship with a single product.
When multiple targets exist in a project or workspace, Xcode can automatically detect any dependencies between them, in which case it will build the products in the required order. This sort of relationship between products is called an implicit dependency.
The build settings and build phases, which each target will inherit from the project, can be overridden at the target level. If they are not specified at the target level, though, the project level build settings will be applied.
You can see the targets associated with a project by clicking on the project in Xcode like so:
An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection of tests to execute. When you select an active scheme, you also select a run destination – i.e., the variety of the hardware for which the products are built.
A default scheme is created when you start a new Xcode project. You can edit the scheme, or create a new scheme by clicking on the scheme in Xcode, like so:
Putting it All Together with xcodebuild Examples
To list all targets, build configurations, and schemes used in your project, run the following from within the example directory:
xcodebuild -list -project example.xcodeproj
To build a scheme in the above project called “example,” you can run the following from within the example directory:
xcodebuild -scheme example build
To build for testing with the test suite associated with your project, you can run the following:
xcodebuild -project example.xcodeproj -scheme example build-for-testing
To execute the test suite associated with your project, you can run:
-project example.xcodeproj \
-scheme example \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 12,OS=14.3' \
In order to execute macOS or iOS CI jobs, you’ll need to be able to execute your builds and tests from the terminal. Xcode offers the handy tool xcodebuild to allow you to do this, but in order to use it, you need to have a solid grasp on concepts specific to Xcode, such as projects, workspaces, targets, and schemes. We’ve defined each above, and then provided example commands that include each of these items as arguments to be passed in the terminal.