Building Halium 9.0 on an M1 MacBook Air

I'm primarily a Halium and UBports developer, focussed on a GNU/Linux landscape, though I had to acknowledge the precision and capability of the M1 chip and what Apple had accomplished with it. Also, I wanted to dabble into the world of developing for Apple devices, solely to earn some money on the side.

For that matter, I got myself a MacBook Air with an M1 chip and I'm pleasantly surprised by its performance and versatility. Applications built for Intel chips still run through Rosetta 2, which makes this blog post even possible.

Through some slight modifications to the Halium build system and sources, the use of Homebrew and Rosetta 2 it is possible to build a whole boot image for the Google Pixel 3a on macOS Big Sur 11.4.


Ready to Brew!

We use a handfull of tools available via the Homebrew package manager. Here we go a different route than the official installation instructions wants us to: Installing both the ARM-native and the Intel binaries into separate prefixes, instead of using only one prefix for the respective host environment. To achieve that one needs to install Homebrew a second time, using the following procedure:

# Make sure ARM brew is not available
export PATH="/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"

# Trick the brew installation script into thinking it's running on an Intel Mac
arch -x86_64 zsh

With this newly opened shell one can easily run all commands using Rosetta 2, which in turn allows the Intel binaries to be used. So in this new shell, just run the installation script again:

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

Now you have two brew prefixes!


But how to Brew in Intel land occasionally?

To run your main Terminal applications using native M1 binaries, but having a full-blown Intel environment as necessary, it is crucial to tinker with the zsh initialization script.

Add this into the ~/.zshenv script file:

MODDED_PATH=$(echo "$PATH" | sed "s/\/usr\/local\/bin\://g")
PATH="$MODDED_PATH"

if [ "$(arch)" = "arm64" ]; then
  eval $(/opt/homebrew/bin/brew shellenv);
else
  eval $(/usr/local/bin/brew shellenv);
fi

What this does is filter out /usr/local/bin, which is typically occupied by Intel binaries installed through Homebrew, and evaluate the shell environment variable initialization depending on whether you're running native or through Rosetta 2.

All you need to do now is run arch -x86_64 zsh whenever you need tools made for Intel in your toolbelt.


The necessary tools

This one is simple, install a handful of nifty command line tools into your Intel environment:

arch -x86_64 zsh -c "brew install coreutils gnu-sed dtc lz4"

Installing the GNU Coreutils is a crucial one, even though we only need it for one command specifically. There's this funny bug that happens with Make where the number of CPU cores cannot be detected and, instead of returning to a sane maximum value, it spawns as many compiler processes as possible, filling up the RAM and ending the build in a "Your system ran out of memory" dialog and a stuck system prematurely.


Halium, you're missing something...

Now we come to patching a few things in Halium and the kernel sources to accomplish our goal of building a Halium 9.0 boot image on an M1 Mac.

The changes (in no particular order):

  • Allow halium/devices/setup to find device manifest files on macOS
  • Make newer Xcode SDKs suitable for Big Sur available to the build system
  • Pull a prebuilt Go compiler capable of building without running into a segfault
  • Fix a header in libelf to properly use extern "C" declarations
  • Fix the kernel to choose gsed over the macOS default sed implementation when building AppArmor.

To put it in a gist, here's the gist: https://gist.github.com/fredldotme/7cb6649bb6992140b3041f76dfa352a0


Aaand we're done, on to the conclusion!

The M1 Macs are very capable devices, though they were missing that little oomph a Linux connaisseur like me craves. With a few changes made to the set of default macOS Terminal tools, the Halium sources and an interesting technology like Rosetta 2 it is very much possible to build Halium images for your favorite GNU/Linux smartphone environments on an M1 Mac. Also, due to its ARM-native nature, it is possible to build userspace packages for distributions more quickly on those Macs compared to cross-building or running a VM from within an Intel-based computer.

Happy hacking!

Alfred Neumayer

Born and raised in Austria, enjoys making music and writing software.

Austria