Getting Ready for Mobile CI/CD on Apple Silicon M1

As Apple leaps forward from Macs built with Intel-based chips to Macs with ARM-based chips, this transition means both Bitrise and our customers, need to update tooling and software in preparation for this transition in order to take full advantage of the Apple Silicon for the development work.

By now, you have probably heard that we are hard at work to bring you the world’s first virtualized M1 CI/CD environment on Bitrise. As Apple leaps forward from Macs built with Intel-based chips to Macs with ARM-based chips, they will naturally want to move the iOS and macOS development ecosystem along, too.

There are tools Apple is using to help developers with the transition from Intel-based apps over to Apple Silicon such as Rosetta 2, but because this is one of the most major architecture update, this transition means not only Bitrise, but also our customers, need to update tooling and software in preparation for this transition, in order to take full advantage of the Apple Silicon for the development work.

Our goal today is to show you some major differences, and common issues you may run into, as well as how to fix them before you migrate your projects to M1-based machines.

How does Apple Silicon affect the default Bitrise stack

On Bitrise’s iOS stack, we not only pre-installed thousands of mobile-specific tools but also actively manage them. These tools range from dependency manager such as CocoaPods, to different Xcode versions.

For Bitrise to enable M1 support, we have to do a complete review on all these pre-installed tooling. Some tools may work out of the box; some won’t. Certain versions of these tools and software need to be updated to the latest version, because a build may break if the application is not lined with the latest version.

Here is a list of tools that Bitrise has pre-installed and updated. Bitrise will update all our tools and software to be compatible with M1 natively where possible. Where it’s not possible for native support, we will patch the version to make it work.

The reality is: your build will probably not work out of the gate if your team had previously run on Intel-based machines when switching to M1, just because this is one of the most major architecture change.

The best way to migrate your projects is to first test everything locally on M1 hardware to catch any potential issues and bugs. For this purpose, Bitrise CLI would be a helpful tool.

Recommendation: migrate your projects to your M1 machines locally to catch any bugs and version differences in your tools.

What is Rosetta, and why it may slow you down?

Rosetta is an emulator/translator designed by Apple to bridge the compatibilities between Intel and Apple processors. Basically that means that it will translate apps built for Intel so they will run on Apple Silicon, like the M1 chip. To use it, you just need to toggle it on when prompted to install Rosetta 2 the first time you attempt to run an Intel-targeting executable and then opt in to use it.

One of the major benefits of Rosetta is that, to the user, the process is mostly transparent. Under the hood it works by detecting if an executable is using Intel instructions, meaning that it targets an Intel-based architecture, and, if so, macOS will automatically use Rosetta to translate the instructions to Apple Silicon.

The trade-off of running Rosetta is that you’ll see some decreased performance. That’s because Rosetta will first translate the code and then cache the result, so the second time you run the code, it will be slightly faster, but due to the delay in translation, it will not run as fast as native M1 support.

And because Rosetta can detect if the software is supporting M1 natively, many users will use Rosetta to determine if they want to install the software.

In fact, you may discover tools you haven’t updated just by running Rosetta on your own M1 machine. If you discover that something isn’t working that you suspect is based on a lack of architecture support, the best thing to do is to insert specific flags, such as arch -x86_64, to downgrade to Intel based tools before the command. Then, when Rosetta comes across these tags, it’ll run them on Intel-based mode.


// pass a flag on each command
$ arch -x86_64 echo 1

// change default shell and have it default to arch....
$ arch -x86_64 $SHEL
$ arch -x86_64 /bin/bash

// example
$ arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

// script to check cpu arch

#!/bin/zsh
 
arch_name="$(uname -m)"
        
if [ "${arch_name}" = "x86_64" ]; then
    if [ "$(sysctl -in sysctl.proc_translated)" = "1" ]; then
        echo "Running on Rosetta 2"
    else
        echo "Running on native Intel"
    fi 
    elif [ "${arch_name}" = "arm64" ]; then
        echo "Running on ARM"
    else
        echo "Unknown architecture: ${arch_name}"
    fi
Copy code


Rosetta has been installed and enabled in Bitrise’s stacks. Our Step library has been updated to support M1 - we’ve done the patches and improvements so make them work out of the box. If you’re using Bitrise Steps, you don’t need to do anything; we’ve got you covered!

Common problems you might face building a typical iOS app

  • Xcode versions: Xcode 13 fully supported on M1. However, Xcode 12 will need to be supported by Rosetta. If you have an older project, you have to run it in Rosetta mode, which will allow you to translate features without issues.
  • Third-party dependencies that have a static library: these static libraries have different architecture and live in places like iPhone iOS or for Mac Simulator. This is one of the biggest problems the mobile development industry faces because numerous bigger applications use third-party vendor libraries such as PayPal SDK. In these situations, there isn’t an easy fix: you’d have to fork off a copy of the code to fix it yourself, or your build will fail.

Homebrew’s default path will change

Homebrew is the most popular package manager for Mac; it simplifies the installation of software on Apple’s macOS (but as well as on Linux).

By default, Bitrise has installed the Homebrew native M1 support package. Back in the Intel world Homebrew saved the package in the /usr/local/ folder, but now on the M1 MacBook, by default, packages are stored in /usr/local/bin/, /usr/local/share/, and /usr/local/lib/. They are owned by root and require sudo access.

So, because of this, if you use a hard-coded Intel-based path, your M1-based build will break. Therefore, you’ll need to make sure to point to the M1 specific folder path. Here’s an example using Homebrew, because it puts ARM binaries in its own /opt/homebrew/ folder.


if [[ $OSTYPE == darwin* && uname -m == "arm64" ]]; then
# M1 MacBook use /opt/homebrew
mv /tmp/pspdfkitd /opt/homebrew/bin
else
# Use /usr/local
mv /tmp/pspdfkitd /usr/local/bin
fi
Copy code

Other 3rd-party tools

Because a lot of our tools are from third-party vendors (i.e. CocoaPods), we rely on these vendors to push updates to enable native execute on Apple Silicon.

We’ll share more details of the tooling and software that may require your attention soon.

Sign up to be notified about M1 availability

If you haven’t signed up for M1 early access, you can still do that here. We will let you know as soon as M1 is available on Bitrise. As always, happy building! 🚀

No items found.
The Mobile DevOps Newsletter

Explore more topics

App development

Best practices from engineers on how to use Bitrise to build better apps, faster.

Community

Meet other Bitrise engineers, technology experts, power users, partners and join our BUGs.

Company

All the updates about Bitrise events, sponsorships, employees, and more.

Insights

Mobile development, latest tech, industry insights, and interviews with experts.

Mobile DevOps

Learn why mobile development is unique and requires a set of unique practices.

Releases

Stay tuned for the last updates, new features, and product improvements.

The Mobile DevOps Newsletter

Join 1000s of your peers. Sign up to receive Mobile DevOps tips, news, and best practice guides once every two weeks.