Using the macOS execution environment
The macOS execution environment is used for iOS and macOS development, allowing you to test, build, and deploy macOS and iOS applications on CircleCI. The macOS executor runs jobs in a macOS environment and provides access to iPhone, iPad, Apple Watch and Apple TV simulators.
You can use the macOS execution environment to run your jobs in a macOS environment on a virtual machine (VM). You can access the macOS execution environment by using the macos
executor and specifying an Xcode version:
jobs:
build:
macos:
xcode: 12.5.1
steps:
# Commands will execute in macOS container
# with Xcode 12.5.1 installed
- run: xcodebuild -version
Supported Xcode versions
(1) Xcode 10.3 is unsupported by our dedicated hosts. See the Dedicated Host for macOS page to learn more about this resource class.
Note: macOS App UI Testing is supported on Xcode 11.7 and higher
Available resource classes
Class | vCPUs | RAM |
---|---|---|
medium | 4 @ 2.7 GHz | 8GB |
macos.x86.medium.gen2 | 4 @ 3.2 GHz | 8GB |
large | 8 @ 2.7 GHz | 16GB |
macos.x86.metal.gen1 | 12 @ 3.2 GHz | 32GB |
Note: The macos.x86.metal.gen1
resource requires a minimum 24-hour lease. See the Dedicated Host for macOS page to learn more about this resource class.
Note: The large
resource class is only available for customers with an annual contract. Open a support ticket if you would like to learn more about our annual plans.
jobs:
build:
macos:
xcode: 12.5.1
resource_class: large
macOS VM Storage
The amount of available storage on CircleCI macOS virtual machines depends on the resource class and Xcode image being used. The size of the Xcode images varies based on which tools are pre-installed. The table below indicates how much storage will be available with various Xcode/resource class combinations. Also note the exceptions to this noted below.
Xcode Version | Class | Minimum Available Storage |
---|---|---|
10.3.0 | medium, large | 36GB |
10.3.0 | macos.x86.medium.gen2 | 36GB |
11.* | medium, large | 23GB |
11.* | macos.x86.medium.gen2 | 23GB |
12.* | medium, large | 30GB |
12.* | macos.x86.medium.gen2 | 30GB |
13.* | medium, large | 23GB |
13.* | macos.x86.medium.gen2 | 89GB |
Note: If you specify Xcode 12.0.1, 12.4.0 and 12.5.1 you have a minimum 100GB of available storage.
Image update cycle for the macOS executor
Each macos
job is run in a fresh virtual machine, using a specified version macOS. CircleCI builds and deploys a new image each time a new stable, or beta, version of Xcode is released by Apple. The contents of build images remain unchanged in most circumstances. However, in exceptional circumstances CircleCI might be forced to re-build a container. CircleCI’s goal is to keep your execution environment stable, and to allow you to opt-in to newer macOS environments by setting the xcode
key in your config.yml
file.
Periodically, CircleCI will update the version of macOS each image includes to ensure the execution environment is as up to date as possible. When a new major version of macOS is released, CircleCI will update once the new major version of Xcode reaches the xx.2
release. This ensures the execution environment is kept stable.
CircleCI will announce the availability of new macOS containers, including Xcode betas, in the annoucements section of our Discuss site.
Beta image support
CircleCI aims to make beta Xcode versions available on the macOS executor as soon as possible to allow developers to test their apps ahead of the next stable Xcode release.
Unlike CircleCI’s stable images (which are frozen and will not change), once a new beta image is released it will overwrite the previous beta image until a GM (stable) image is released, at which point the image is frozen and no longer updated.
If you are requesting an image using an Xcode version that is currently in beta, you should expect it to change when Apple releases a new Xcode beta with minimal notice. This can include breaking changes in Xcode/associated tooling which are beyond CircleCI’s control.
To read about CircleCI’s customer support policy regarding beta images, please check out the following support center article.
Apple silicon support
It is possible to build Apple Silicon/Universal binaries using Xcode 12.0.0
and higher as Apple provides both the Intel (x86_64
) and Apple Silicon (arm64
) toolchains in this release. Cross-compiling Apple Silicon binaries on Intel hosts has an additional overhead, and, as a result, compilation times will be longer than native compilation for Intel.
Running or testing Apple Silicon apps natively is currently not possible as CircleCI build hosts are Intel-based Macs. Binaries will need to be exported as artifacts for testing apps locally. Alternatively, CircleCI runner can also be used to run jobs natively on Apple Silicon.
Xcode Cross Compilation
Universal Binaries
Xcode currently supports the creation of universal binaries which can be run on both x86_64
and ARM64
CPU architectures without needing to ship separate executables. This is supported only under Xcode 12.2+, although older Xcode versions can still be used to compile separate x86_64
and ARM64
executables.
Extracting Unwanted Architectures
By default, Xcode 12.2+ will create universal binaries, compiling to a single executable that supports both x86_64
and ARM64
based CPUs. If you need to remove an instruction set, you can do so by using the lipo
utility.
Assuming that you want to create a standalone x86_64
binary from a universal binary called circleci-demo-macos
, you can do so by running the command:
lipo -extract x86_64 circleci-demo-macos.app/Contents/MacOS/circleci-demo-macos -output circleci-demo-macos-x86_64
You can then confirm the supported architecture of the extracted binary with lipo -info circleci-demo-macos-x86_64
, which will output the following
Architectures in the fat file: circleci-demo-macos-x86_64 are: x86_64
Cross Compiled Binaries
While universal binaries are only supported under Xcode 12.2+, you can still cross compile binaries for architectures other than the architecture of the machine being used to build the binary. For xcodebuild the process is relatively straightforward. To build ARM64
binaries, prepend the xcodebuild
command with ARCHS=ARM64 ONLY_ACTIVE_ARCH=NO
such that it reads xcodebuild ARCHS=ARM64 ONLY_ACTIVE_ARCH=NO ...
. For the x86_64
architecture simply change ARCHS
to x86_64
.
Optimization and best practises
Pre-starting the simulator
Pre-start the iOS simulator before building your application to make sure that the simulator is booted in time. Doing so generally reduces the number of simulator timeouts observed in builds.
To pre-start the simulator, add the macOS orb (version 2.0.0
or higher) to your config:
orbs:
macos: circleci/macos@2
Then call the preboot-simulator
command, as shown in the example below:
steps:
- macos/preboot-simulator:
version: "15.0"
platform: "iOS"
device: "iPhone 13 Pro Max"
It is advisable to place this command early in your job to allow maximum time for the simulator to boot in the background.
If you require an iPhone simulator that is paired with an Apple Watch simulator, use the preboot-paired-simulator
command in the macOS orb:
steps:
- macos/preboot-paired-simulator:
iphone-device: "iPhone 13"
iphone-version: "15.0"
watch-device: "Apple Watch Series 7 - 45mm"
watch-version: "8.0"
Note: It may take a few minutes to boot a simulator, or longer if booting a pair of simulators. During this time, any calls to commands such as xcrun simctl list
may appear to hang while the simulator is booting up.
Collecting iOS simulator crash reports
Often if your scan
step fails, for example due to a test runner timeout, it is likely that your app has crashed during the test run. In such cases, collecting crash report is useful for diagnosing the exact cause of the crash. Crash reports can be uploaded as artifacts, as follows:
steps:
# ...
- store_artifacts:
path: ~/Library/Logs/DiagnosticReports
Optimizing Fastlane
By default, Fastlane Scan generates test output reports in html
and junit
formats. If your tests are taking a long time and you do not need these reports, consider disabling them by altering the output_type
parameter as described in the fastlane docs.
Optimizing Cocoapods
In addition to the basic setup steps, it is best practice to use Cocoapods 1.8 or newer which allows the use of the CDN, rather than having to clone the entire Specs repo. This will allow you to install pods faster, reducing build times. If you are using Cocoapods 1.7 or older, consider upgrading to 1.8 or newer as this change allows for much faster job execution of the pod install
step.
To enable this, ensure the first line in your Podfile is as follows:
source 'https://cdn.cocoapods.org/'
If upgrading from Cocoapods 1.7 or older, additionally ensure the following line is removed from your Podfile, along with removing the “Fetch CocoaPods Specs” step in your CircleCI Configuration:
source 'https://github.com/CocoaPods/Specs.git'
To update Cocoapods to the latest stable version, simply update the Ruby gem with the following command:
sudo gem install cocoapods
A further recommendation is to check your Pods directory into source control. This will ensure that you have a deterministic, reproducible build.
Note: The previous S3 mirror provided here for the Cocoapods Spec repo is no longer being maintained or updated since the release of Cocoapods 1.8. It will remain available to prevent existing jobs breaking, switching to the CDN method described above is recommended.
Optimizing Homebrew
Homebrew, by default, will check for updates at the start of any operation. As Homebrew has a fairly frequent release cycle, this means that any step which calls brew
can take some extra time to complete.
If build speed, or bugs introduced by new Homebrew updates are a concern, this automatic update feature can be disabled. On average, this can save up to 2-5 minutes per job.
To disable this feature, define the HOMEBREW_NO_AUTO_UPDATE
environment variable within your job:
version: 2.1
jobs:
build-and-test:
macos:
xcode: 12.5.1
environment:
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- checkout
- run: brew install wget
Supported build and test tools
With the macOS executor on CircleCI, it is possible to customize your build as needed to satisfy almost any iOS build and test strategy.
Common test tools
The following common test tools are known to work well on CircleCI:
React Native projects
React Native projects can be built on CircleCI using macos
and docker
executor types. For an example of configuring a React Native project, please see our demo React Native application
Creating a config.yml
File
The most flexible way to customize your build is to modify the CircleCI configuration for your project in .circleci/config.yml
. This allows you to run arbitrary bash commands as well as use built-in features such as workspaces and caching. See the Configuring CircleCI documentation for a detailed description of the structure of the .circleci/config.yml
file.
Using Multiple Executor Types (macOS + Docker)
It is possible to use multiple executor types in the same workflow. In the following example each push of an iOS project will be built on macOS, and additional iOS tools (SwiftLint and Danger) will be run in Docker.
version: 2.1
jobs:
build-and-test:
macos:
xcode: 12.5.1
environment:
FL_OUTPUT_DIR: output
steps:
- checkout
- run:
name: Install CocoaPods
command: pod install --verbose
- run:
name: Build and run tests
command: fastlane scan
environment:
SCAN_DEVICE: iPhone 8
SCAN_SCHEME: WebTests
- store_test_results:
path: output/scan
- store_artifacts:
path: output
swiftlint:
docker:
- image: bytesguy/swiftlint:latest
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
steps:
- checkout
- run: swiftlint lint --reporter junit | tee result.xml
- store_artifacts:
path: result.xml
- store_test_results:
path: result.xml
danger:
docker:
- image: bytesguy/danger:latest
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
steps:
- checkout
- run: danger
workflows:
build-test-lint:
jobs:
- swiftlint
- danger
- build-and-test
Next steps
Get started with Configuring a Simple macOS Application on CircleCI.
Help make this document better
This guide, as well as the rest of our docs, are open source and available on GitHub. We welcome your contributions.
- Suggest an edit to this page (please read the contributing guide first).
- To report a problem in the documentation, or to submit feedback and comments, please open an issue on GitHub.
- CircleCI is always seeking ways to improve your experience with our platform. If you would like to share feedback, please join our research community.
Need support?
Our support engineers are available to help with service issues, billing, or account related questions, and can help troubleshoot build configurations. Contact our support engineers by opening a ticket.
You can also visit our support site to find support articles, community forums, and training resources.
CircleCI Documentation by CircleCI is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.