This document is for people using an Apple MacBook based on the Apple ARM architecture, ie. M1 or newer, who wants to run Ruby on Rails applications that does not work on the ARM architecture. The current use case is applications using Oracles instant client libraries which are not ARM compatible.
The general idea with this setup is to be able to have two separate shell environments. One for running things using the ARM architecture and one for things using the X86 architecture. Effectively we want to be able to have a shell that can act as either an ARM shell or an X86 shell and we want to be able to switch between the two.
After following this guide the user should be able to open a new terminal and be in a functional ARM environment. And then be able to switch to a functional X86 environment with a single command.
The first thing needed to be able to execute X86 programs is to install the Rosetta emulation layer. The Macbook will automatically ask to install this the first time one tries to run an X86 program.
We can do this by running the following command:
arch -x86_64 /bin/bash
This should install the Rosetta layer if not already installed and start a new
bash shell in the X86 environment. We can verify that we are indeed in the X86
environment by running the arch
command without arguments and observing the
output:
arch
If the output is i386
we're in the X86 environment, if the output is arm64
we're still in the ARM environment.
To get back to the ARM environment you can exit the X86 instance of
bash and it will drop you back to the shell where you started. Again you can
verify that you are in the correct environment by running arch
.
To make it easier to switch environments we can add an alias to our shell configuration. By default you will be using bash if you haven't chosen a different shell. To setup an alias in bash run:
echo "alias xsh=\"arch -x86_64 /bin/bash\"" >> ~/.bashrc
Now if you open a new shell you will be able to switch to the X86 environment
using the xsh
command. Again, you can verify that you are in the right
environment with the arch
command.
This guide assumes you want to use Homebrew to install software on your laptop in general. When using two environments we need to install a homebrew for each environment.
Assuming you are in the ARM environment you can install homebrew for ARM (if you haven't already) with the command:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
To install for the X86 environment use:
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
You're now ready to start installing programs for the different architectures using Homebrew.
After installing Homebrew in both environments you can install programs for
that environment using the brew
command while being in the environment you
want to install for.
To run the programs installed for X86 you need to add it to the path. So open
~/.bashrc
and add:
if [ $(arch) = "i386" ]; then
export PATH=/usr/local/bin:$PATH
fi
While Homebrew is great for regular programs you often want to be able to run different versions of things you use for development. Things like Ruby and NodeJS.
I recommend the rtx version manager for this purpose. let's get rtx installed in the ARM environment:
brew install rtx
And then in the X86 environment:
xsh
brew install rtx
After installing you need to active rtx for your shell - so pick the right one from:
echo 'eval "$(rtx activate bash)"' >> ~/.bashrc
echo 'eval "$(rtx activate zsh)"' >> ~/.zshrc
echo 'rtx activate fish | source' >> ~/.config/fish/config.fish
To get rtx to work well with the two environments we need to change where it
stores the things it installs for each environment. We do this by configuring the
RTX_DATA_DIR
environment variable for the shell. So open the ~/.bashrc
file
and add the following:
export RTX_DATA_DIR=$HOME/.config/share/rtx/$(arch)
After doing this we can start a new shell and rtx will work.
To install Ruby we rely on the project to tell us which version of Ruby it
wants. This is usually done by placing a .tool-versions
file in the root of
the project. If there is no such file look for a .tool-versions.example
and
copy that to .tool-versions
.
When there is a .tool-versions
file installing the dependencies is just a
matter of running rtx install
in the right shell environment.
For instance to install Ruby for an X86 environment we would do:
xsh
rtx install
After following these steps you have a fully functional two environment setup.
All you need to do is to remember to run the xsh
command when you want to
switch from the ARM environment to the X86 environment.
Ruby fails to install with compilation errors like use of undeclared identifier 'RUBY_FUNCTION_NAME_STRING'
Reinstall xcode command line tools:
sudo rm -rf /Library/Developer/CommandLineTools
sudo xcode-select --install