Skip to content

Instantly share code, notes, and snippets.

@jacobat
Last active November 17, 2023 10:06
Show Gist options
  • Save jacobat/77aa1d4cf11a615805fe09986c396d72 to your computer and use it in GitHub Desktop.
Save jacobat/77aa1d4cf11a615805fe09986c396d72 to your computer and use it in GitHub Desktop.
Jacobs dual architecture shell setup

Jacobs dual architecture setup

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.

Overview

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.

Rosetta

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.

Switching environments

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.

Homebrew

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

Version manager

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)

‼️ Note that thes line should be before the line enabling rtx.

After doing this we can start a new shell and rtx will work.

Installing Ruby

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

Done

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.

FAQ

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment