iOS developers and Apple Silicon M1 - early experience

Today my message is gonna be way more technical than I expected - and probably interesting mostly for developers. It's about month old when my M1 MacBook Pro came in - and might be outdated already. But I thought it's worth sharing. Should we get right into that?! 🚀

If you work on an iOS project, you either use Carthage, CocoaPods or SPM. (or all/some together). SPM is easy - it’s developed by Apple, it’s ready for ARM. But CocoaPods are different world.

So you have a project. Project uses CocoaPods.

  • CocoaPods are not supported on M1.

To install CocoaPods, you usually use Bundler.

  • Bundler is not supported on M1.

Bundler is installed via gem, which needs Ruby. And system Ruby is bad Ruby. Latest 2.7 Ruby is 2.7.2. So you want RBENV.

  • RBENV is not supported on M1.

  • Installation of Ruby 2.7.2 is not supported on M1

RBENV is usually installed via Homebrew.

  • Homebrew is not supported on M1.

So that’s current status. Awesome, right? 💛

So you have multiple options:

  • Run terminal as on Intel processor through Rosetta

  • Install everything through arch -x86_64 prefix as on Intel processor

  • Install CocoaPods without Bundler and only via arch -x86_64 prefix

  • Go wild and try to make it work on M1

Let’s see what we have here.

1: - Go to /Applications/Utils , duplicate Terminal app, call it for example Terminal x86, right click on it, go to Informations and check Run through Rosetta. This means when you runt Terminal x86 app, it will be running as if you are on Intel processor.

Pretty boring, where is some adventure in this?!

2: - Run regular terminal, and install Homebrew through Intel-compatible way, so:

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

instead of

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

This will run it through Rosetta as well as you added the arch prefix, which... might, and might not work as expected in upcoming steps, because it will still install Homebrew to /usr/local folder - incorrectly.

3: - Install cocoapods via prefix is really easy. However not many developers use cocoapods directly unrealted to Bundler, so not really ideal case.

arch -x86_64 gem install ffi
arch -x86_64 gem install cocoapods

4: - Go wild on an Adventure!

With upcoming release, Homebrew on M1 will switch to installation folder /opt/homebrew instead of /usr/local - so we will install Homebrew natively for M1 to this folder:

$ sudo mkdir -p /opt/homebrew
$ sudo chown -R $(whoami):staff /opt/homebrew
$ cd /opt
$ curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

Notice we are installing from master, to homebrew folder - on master there is already couple of fixes for M1, that’s why we do that here.

Now as we installed Homebrew to different location, we need to update our $PATH to let shell know where is our installation directory and add /opt/homebrew/bin to that - put export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" to the top of your ~/.zshrc file (if you use ZSH, or to the bash profile if you use bash still).

Great, Homebrew setup! Let’s install RBENV.

brew install rbenv succeeds without any issue, cool! Let’s install Ruby 2.7.2

rbenv install 2.7.2 tries to instal OpenSSL - but OpenSSL is not yet compatible with M1 (and there is a looooong thread about if it should be, or if it will come in 3.0.0 - bleh). Okay, let’s try to install OpenSSL manually - gem install openssl. Woho, that works! ðŸŽ‰ Okay, let’s try rbenv install 2.7.2 again. Hmm, failed again on the same error.

In this moment you need to let RBENV know there is an OpenSSL preinstalled already and it should be re-used for Ruby installation.

RUBY_CONFIGURE_OPTS=--with-openssl-dir=/opt/homebrew/Cellar/openssl@1.1/1.1.1h rbenv install 2.7.2 will do the trick - Ruby installed, woho!

Let’s switch to the new version by rbenv global 2.7.2 and restart terminal. Next is to install Bundler via new Ruby - gem install bundler - there is no issue with this although bundle install might fail depending on which gems you try to install. We are trying only CocoaPods now, so this should succeed. The next - and obviously last step is to install CocoaPods included in our project. bundle exec pod install - ufff, Error on getting CDN https://cdn.cocoapods.org size_t unknown type caused by ffiffi is not supported by M1. Okay, CocoaPods might be pointing to older version - let’s try to do gem install ffi. Success! 

 Let’s try bundle exec pod install again. New error appears.

gems/ffi-1.13.1/lib/ffi/library.rb:275: [BUG] Bus Error at 0x0000000103460000 because ffi uses wrong allocation methods causes SEGV on M1 (https://github.com/ffi/ffi/issues/800)

And this is for now the end of our adventure. As of now, there is NO WAY to run CocoaPods on M1 natively. And these are going to be fixed (https://github.com/ffi/ffi/pull/843, https://github.com/ffi/ffi/pull/809, https://github.com/ffi/ffi/pull/801), but it will take some time. And then there is the OpenSSL fix which might be included in upcoming release, or might not (https://github.com/openssl/openssl/pull/12369). And also Homebrew, working on native M1 support, but stated it won’t come in near future, probably months, due to missing CI infrastructure (https://github.com/Homebrew/brew/issues/7857).So as a summary:

  • it’s definitely interesting time to try get this working on M1 devices, but it’s not possible right now ðŸ˜”

  • you can still normally work and exist on M1 devices, but with Rosetta everywhere

  • this doesn’t even mention issues related to XCode itself (like building for new architecture arm64-ios-apple-simulator - ohhh yes, M1 XCode needs also M1 simulators! ðŸ˜‚) but let’s leave that for now - we can go through it different day

Soooo - yes - I went through the 4. option, and tried all of this by myself just by try-and-fail and finding a workarounds. And at the end, in last step, I found out it won’t work! But there is an option to install Homebrew also as x86_64 compatible and alias it - more info here: https://soffes.blog/homebrew-on-apple-silicon - so I now have both and I will keep working through Rosetta while trying to make it work on M1 natively.

What a journey!