Start Building for Free
CircleCI.comAcademyBlogCommunitySupport

Using the macOS execution environment

2 months ago6 min read
Cloud
On This Page

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: 15.4.0
    resource_class: m2pro.medium

    steps:
      # Commands will execute in macOS container
      # with Xcode 15.4.0 installed
      - run: xcodebuild -version

Supported Xcode versions

Supported Xcode versions for Apple silicon

ConfigXcode VersionmacOS VersionVM Software ManifestRelease Notes

16.2.0

Xcode 16.2 GA (16C5032a)

14.6.1

Installed software

Release Notes

16.1.0

Xcode 16.1 (16B40)

14.6.1

Installed software

Release Notes

16.0.0

Xcode 16.0 (16A242d)

14.6.1

Installed software

Release Notes

15.4.0

Xcode 15.4 (15F31d)

14.3.1

Installed software

Release Notes

15.3.0

Xcode 15.3 (15E204a)

14.3.1

Installed software

Release Notes

15.2.0

Xcode 15.2 (15C500b)

14.1

Installed software

Release Notes

15.1.0

Xcode 15.1 (15C65)

14.1

Installed software

Release Notes

15.0.0

Xcode 15 (15A240d)

13.5.1

Installed software

Release Notes

14.3.1

Xcode 14.3.1 (14E300b)

13.2.1

Installed software

Release Notes

14.2.0

Xcode 14.2 (14C18)

12.6.3

Installed software

Release Notes

14.1.0

Xcode 14.1 (14B47b)

12.6.1

Installed software

Release Notes

14.0.1

Xcode 14.0.1 (14A400)

12.6.1

Installed software

Release Notes

13.4.1

Xcode 13.4.1 (13F100)

12.6.1

Installed software

Release Notes

Available resource classes

ClassvCPUsRAMCloudServer

macos.m1.medium.gen1

4 @ 3.2 GHz

6GB

macos.m1.large.gen1

8 @ 3.2 GHz

12GB

m2pro.medium

4 @ 3.49 GHz

8GB

m2pro.large

8 @ 3.49 GHz

16GB

jobs:
  build:
    macos:
      xcode: "15.4.0"
    resource_class: m2pro.medium

View resource usage

To view the compute resource usage for the duration of a job in the CircleCI web app:

  1. Select Dashboard from the sidebar menu

  2. Use the dropdown menus to select a project, and a branch

  3. Expand your workflow ( )

  4. Select a job by clicking on the job name

  5. Select the Resources tab to view CPU and RAM usage for the duration of the job

You can use these insights to decide whether to make changes to the job’s configured resource class. You can also access resource class Insights.

Resources tab

Image update cycle for the macOS executor

Each macos job is run in a fresh virtual machine, using a specified version of 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 .circleci/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 announcements 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 and associated tooling, which are beyond CircleCI’s control.

To read about CircleCI’s customer support policy regarding beta images, check out the following support center article.

Apple silicon support

Running or testing Apple silicon apps natively can be done on our silicon-based Macs or by using CircleCI runner.

It is also 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.

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.

Extract 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 the following:

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 practices

Pre-start 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"

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 repository. 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, ensure the Fetch CocoaPods Specs step is removed from your CircleCI configuration, and ensure the following line is removed from your Podfile:

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.

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 two to five 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: 14.2.0
    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, see our demo React Native application

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 a deploy image will run in Docker.

version: 2.1
jobs:
  build-and-test:
    macos:
      xcode: 14.2.0
    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

  deploy-snapshot:
    docker:
      - image: cimg/deploy:2022.08
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference
    steps:
      - checkout
      - run: echo "Do the things"

workflows:
  build-test-lint:
    jobs:
      - deploy-snapshot
      - build-and-test

Suggest an edit to this page

Make a contribution
Learn how to contribute