Building the RPi5 kernel on your Mac
Docker is your friend. The default MacOS filesystem is not!
As I develop the WiFi Diving substack, I’m starting to hack code to run on my pair of Raspberry Pi 5 devices.
Most of the interesting things I do are kernelspace changes - mac80211, cfg80211, nl80211 etc., which necessitate recompiling of the kernel, or at least some kernel modules.
The options I considered are:
Manually build the RPi5 cross compile tools for MacOS;
Install a virtual machine, inside of which run Ubuntu or equivalent, install the appropriate cross compile tools for Linux (much easier proposition to the first option); and
Use a Docker image developed purely for cross-compilation of the RPi kernel.
Option 1 was ruled out pretty quickly as I want to write articles, not struggle with building cross-compiler toolchains.
Option 2 was a pretty simple proposition, but still a non-trivial amount of work (see point 1 - writing not struggling!)
Option 3 seemed just right - someone else did the hard work, all I needed to do was build the Docker image and run the container… which is almost the full story.
The Docker image I used for RPi5 cross-compilation is: https://github.com/xoseperez/pi-kernel
Here are my steps for building the RPi5 Linux kernel on MacOS - my laptop is an Apple M2 based Macbook Pro running MacOS 14.4:
Install Docker Desktop
First of all install Docker Desktop for MacOS: https://docs.docker.com/desktop/install/mac-install/
Make a new filesystem volume with case sensitivity
This step is crucial in the checkout and build for the Linux kernel. Do not ignore it!
By default, new volumes created on your MacOS HD will be case insensitive. The problem this raises with the Linux kernel in particular are that there exist files in the kernel tree with the same name but different case structure.
Examples:
'include/uapi/linux/netfilter/xt_CONNMARK.h'
'include/uapi/linux/netfilter/xt_connmark.h'
If you check out the kernel on a case insensitive filesystem, it will even warn you of this being a bad idea:
To create a new case-sensitive volume on your Mac, open the Disk Utility application, which looks like below, and is in the Launchpad→Other directory by default.
Launching Disk Utility you’ll see something like below:
Note that the ‘linux’ filesystem in the above screenshot is the new case-sensitive filesystem I created to build my kernel.
To add a new volume, click the ‘Volume’ ‘+’ on the top bar of the application, fill out the Name appropriately, then select the Format as ‘APFS (Case-sensitive)’ and click ‘Add’. MacOS will automatically mount the filesystem on ‘/Volumes/<name>’ which you can then use as your base directory for your pi-kernel Docker image + container.
Install the pi-kernel Docker image
Installation of this Docker image is simple enough:
git clone https://github.com/xoseperez/pi-kernel.git
cd pi-kernel
./builder
Note: Make sure you run the pi-checker Docker container on a case-sensitive filesystem or you’ll get checkout and build errors for the kernel. Alternatively you can mess around with the Docker configuration to point the filesystem to a case-sensitive area, but that’s too much work - faster the better!
After running ./builder, the command line is dropped into a shell within the Docker container, where the RPi5 kernel itself can be built.
Build the RPi kernel
First of all, make sure kernel version you would like to build is properly specified:
Open the ‘make’ file in the pi-kernel subdir, and find the ‘KERNEL_TAG’ variable.
Modify this to the version you’d like to build. The tags available to use can be found at the RPi github repository (https://github.com/raspberrypi/linux/branches).
The current stable and version running on my new RPi5 boards is rpi-6.6.y, so I changed KERNEL_TAG to use this.
The default value for this variable within the pi-kernel Docker image ‘make’ file at the time of writing was rpi-6.1.y
Once you've updated the version of the kernel, run:
./make init
./make default
./make build
All of this and more is documented in the pi-kernel README.md
After the build completes, you’ll have the artefacts for the kernel build in the usual location, ready for your next step.
Hope this helped - feel free to add your comments below, especially if you have a CLI method to create the new MacOS volume, or details on how to avoid case sensitivity problems with some Docker magic!
Thank you Richard. This is very helpful
Here is a a CLI method to create the new MacOS volume
```bash
#!/bin/zsh
ImageName=linuxbuild
ImageNameExt=${ImageName}.sparseimage
diskutil umount force /Volumes/${ImageName} && true
rm -f ${ImageNameExt} && true
hdiutil create ${ImageName} -volname ${ImageName} -type SPARSE -size 12g -fs HFSX
hdiutil mount ${ImageNameExt}
cd /Volumes/$ImageName
```