Developers worldwide use Intel-based Mac computers daily, but many face issues setting up their development environment on Apple silicon M1 Macs.
The big transition from Intel to M1
In November 2020, Apple released the first Mac with an ARM-based M1 chip, along with the new MacBook Pro, MacBook Air and Mac mini models. From the release, the M1 chip received excellent reviews and praise for its efficiency and performance – and it marks Apple's transition from Intel chips that have been used for the last 15 years.
Suppose you consider buying a new Apple silicone supercharged Mac or MacBook Pro for development, but you're worried about transitioning your existing project from your Intel-based Mac. If that’s the case, this blog will explain some development setup tips and tricks that will help you continue programming and make your transition easier.
Is the Apple silicon M1 suitable for developers?
Since Apple introduced the first M1 Macs two years ago, they delivered groundbreaking performance and incredible battery life.
In the beginning, M1 chips were only found on consumer-focused Macs and came with some limitations – such as being able to support only one external monitor. The next step came a couple of months ago - in October 2021, when Apple introduced Mac's new M1 Pro and M1 Max breakthrough chips.
The first things we noticed are more powerful M1 architecture, more CPU cores, more GPU cores, more RAM, more ports on the MacBook Pro models – and the possibility of connecting more than one external display.
There are a lot of pros when it comes to new Apple M1 chips; however – there are some disadvantages that need to be addressed, such as the software and tools you are used to may not be fully supported.
Although there is already a lot of software optimized for Apple silicon, there are some that require an extra step in the form of a translation environment – such as Apple Rosetta, which translates apps designed for Intel architecture to M1 architecture.
The software problem
Here at Devōt, we use both Intel- and M1-based Macs, and many of us use the Homebrew package manager, which simplifies the installation of different software - like Ruby, Git, MySQL, etc.
However, when trying to install some older versions of that software on the M1 architecture, we would encounter many issues related to installing native extensions and different dependencies.
To resolve those issues and try to install failing dependencies, we tried many different solutions and extensions, including various installations through the terminal on Apple and Intel architecture. Unfortunately, the result was a significant development software mess that didn't look promising—for example, installing the older Ruby 2.3.6 version (not supported on M1 architecture) caused constant issues with the ffi 1.9.18 gem and OpenSSL 1.0 (also not supported on M1 architecture).
After many tries with custom dependency installations, Ruby 2.3.6. seemed to be installed. However, there were also Ruby bundler issues with installing project gems – all in all, a big mess.
One of the biggest problems in this transition is that some large–scale projects use an older technology stack, which may not be supported by M1 architecture. For example, let's take MySQL Database Service - MySQL5.6 is not supported on M1 architecture, and trying to install it with Homebrew on M1 architecture results in many different errors.
If by any chance, you somehow manage to install MySQL 5.6 with some custom installation commands, other software such as Bundler for Ruby probably won’t work – because MySQL 5.6 is not supported on M1, and again you can expect different errors.
So, what is the solution?
The solution is more straightforward than it may seem. First, you should use only one architecture for installing the entire technology stack in your development environment.
For example – with Rosetta, we can have two Homebrew systems installed – with Apple silicon architecture – Homebrew's default directory is /opt/homebrew. However, when installed with Intel architecture, there is a different default directory, and it is /usr/local.
When using the terminal, we can run commands in Rosetta (on the Intel architecture), but mistakes can still happen, and we can end up with a mess again.
Example brew aliases:
In our example, we use iTerm on Mac as the main terminal app and zsh shell with Oh My Zsh framework for Zsh.
Adding some aliases to switch between Intel and Mac architecture can help us a lot in the environment setup – while installing all the libraries over homebrew and other tools and software.
To display in which architecture we are currently, we can add this setting to our zsh configuration file (.zshrc).
Even though it may sound trivial, ensuring you are in the correct architecture is crucial to avoid any issues caused by different homebrews.
For the version manager, our suggestion would be asdf. Asdf is a CLI tool that can manage multiple language runtime versions on a per-project basis.
How does it work?
Most tools and programs will work perfectly fine on M1 architecture, but some tools require installation that won't work. In our example, running asdf install Ruby 2.3.6 will fail due to architecture issues on M1, but if we switch to Rosetta using our alias command and run asdf install Ruby 2.3.6, it will succeed. So now Ruby 2.3.6 is compiled and installed from Rosetta, and we can use it even on M1 architecture (armzsh).
An M1 Mac only has an M1 architecture chip, so you'll have to adapt to M1 architecture if you plan to use it. How does it work on Apple M1 ARM architecture? Every time we use Rosetta to install an unsupported program or tool, Rosetta compiles it in Intel architecture – and then makes an M1 ARM installation. Rosetta is only required for compile and installs phases - then, our programs should work anywhere.
Since we use both Intel-based and M1 based Mac machines, feel free to contact us with any questions related to the development setup – we will gladly try to help.