Published : 2017-01-14

Poudriere cross compiling

Poudriere can perform cross-compilation, that is, build targets for a different architecture. This article uses the example of an amd64 host cross-compiling for ARMv6, targeting a Raspberry Pi 2.

Preparing the Poudriere Jail

First download a usable RPI2 image from the FreeBSD mirror and decompress it:

fetch http://ftp.freebsd.org/pub/FreeBSD/releases/ISO-IMAGES/11.0/FreeBSD-11.0-RELEASE-arm-armv6-RPI2.img.xz
unxz FreeBSD-11.0-RELEASE-arm-armv6-RPI2.img.xz

Then expose it on the filesystem using mdconfig:

mdconfig -a -t vnode -f FreeBSD-11.0-RELEASE-arm-armv6-RPI2.img
mount /dev/md0s2a /mnt

Now remove the firstboot flag (useless here, since we’ll be in a build jail) and create the directory /usr/local/bin for poudriere:

rm /mnt/firstboot
mkdir -p /mnt/usr/local/bin

The image is ready, let’s create the archive for poudriere:

tar -cpf /tmp/FreeBSD-11.0-RELEASE-arm-armv6-RPI2.tar .

We can now create the jail:

poudriere jail -c -j 11-arm6 -m tar=/tmp/FreeBSD-11.0-RELEASE-arm-armv6-RPI2.tar -a arm.armv6 -v 11.0-RELEASE

ARM Build Support

First we need qemu-user-static to do the cross-compilation. It has two advantages:

  • It has no particular dependencies.
  • The binary is static, which lets poudriere run properly without copying additional dynamic libraries into the jail.
pkg install qemu-user-static

Now add the ARM emulator to the interpreters that poudriere can use:

binmiscctl add armv6 --interpreter "/usr/local/bin/qemu-arm-static"
      --magic
      "\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00"
      --mask
      "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"
      --size 20 --set-enabled

Cross-Compiling!

The environment is ready — all that’s left is to launch a build, for example of zsh:

poudriere bulk -j 11-arm6 -p default shells/zsh
 [00:00:00] ====>> Cross-building ports for arm.armv6 on amd64 requires QEMU
 [00:00:00] ====>> Creating the reference jail... done
 [00:00:00] ====>> Mounting system devices for 11-arm6-default
 [00:00:00] ====>> Mounting ports/packages/distfiles
 [00:00:00] ====>> Using packages from previously failed build
 [00:00:00] ====>> Mounting packages from: /usr/local/poudriere/data/packages/11-arm6-default
 [00:00:00] ====>> Copying /var/db/ports from: /usr/local/etc/poudriere.d/11-arm6-options
 [00:00:00] ====>> Raising MAX_EXECUTION_TIME and NOHANG_TIME for QEMU
 [00:00:00] ====>> Copying latest version of the emulator from: /usr/local/bin/qemu-arm-static
 /etc/resolv.conf -> /usr/local/poudriere/data/.m/11-arm6-default/ref/etc/resolv.conf
 [00:00:00] ====>> Starting jail 11-arm6-default
 [00:00:01] ====>> Logs: /usr/local/poudriere/data/logs/bulk/11-arm6-default/2017-01-13_22h51m51s
 [00:00:01] ====>> Loading MOVED
 [00:00:02] ====>> Calculating ports order and dependencies
 [00:00:32] ====>> Sanity checking the repository
 [00:00:32] ====>> Checking packages for incremental rebuild needed
 [00:00:32] ====>> Deleting stale symlinks
 [00:00:32] ====>> Deleting empty directories
 [00:00:32] ====>> Cleaning the build queue
 [00:00:33] ====>> Recording filesystem state for prepkg... done
 [00:00:33] ====>> Building 36 packages using 2 builders
 [00:00:33] ====>> Starting/Cloning builders
 [00:00:35] ====>> Hit CTRL+t at any time to see build progress and stats
 [00:00:35] ====>> [01][00:00:00] Starting build of ports-mgmt/pkg

Your cross-compilation jail is now operational. You can compile on a real CPU and stop waiting days for your Raspberry Pi to build X11.