While Servo supports Android for a while now, it turned out cross compiling to ARM devices requires some additional work. Now that most of these patches have landed, it is possible to build for ARM with just some minor tweaks.

UPDATE: This tutorial has also been posted here: http://browser.sed.hu/blog/20150717/cross-compiling-servo-arm. Please visit that site if you wish to leave comments.

UPDATE 2: Most of the patches have landed, post updated.

UPDATE 3: The linker issue is now fixed (but, unfortunately there is an issue with the latest Skia).

UPDATE 4: Looks like the Skia issue was fixed, but another appeared in libexpat. Fortunately, there is a clean workaround for that.

Last update: 2015, Nov 2

For reference, in this post I’m going to use Servo at commit 73b52c0, which requires Rust version 2d0cbf3e3e25e092bd9e4c94d08e446b680869f0. You will need the Rust standart library of this particular version, compiled to ARM. The required version is stored in the file rust-snapshot-hash.

Unfortunately, you will probably have to build that yourself too, as ARM libs are not distributed with Rust yet. The first part of the on-board building guide describes how to do it. UPDATE: Now you should also be able to compile it by simply setting the appropriate configure flags.

You will also need the ARM system libraries, but you can copy them either from the system running on your board or from a downloaded distribution installer, eg. a Raspbian image.

Setting up a rootfs

First, I’m going to set up an Ubuntu 14.04 rootfs to build in a clean environment. You can safely skip this step (just don’t forget to change the paths later).

sudo apt-get install debootstrap
sudo debootstrap --arch=amd64 trusty rootfs-trusty
sudo mount -o bind /dev  rootfs-trusty/dev
sudo mount -o bind /proc rootfs-trusty/proc
sudo mount -o bind /sys  rootfs-trusty/sys
sudo chroot rootfs-trusty /bin/bash

Then, add a new user inside the roots (again, you can skip this):

useradd -m servobuild -s /bin/bash
passwd servobuild
usermod -aG sudo servobuild
su - servobuild

Prerequisites

All right, let’s install the ARM compiler. There are many kinds of toolchains (eg. optimized for a certain board, like the Raspberry Pi), but the default one is fine for me:

sudo apt-get update
sudo apt-get install g++-arm-linux-gnueabihf

Install the Servo dependencies (copied from the README):

sudo apt-get install curl freeglut3-dev \
    libfreetype6-dev libgl1-mesa-dri libglib2.0-dev xorg-dev \
    gperf g++ cmake python-virtualenv \
    libssl-dev libbz2-dev libosmesa6-dev libxmu6 libxmu-dev

Note: if python-virtualenv is not found, install it like this:

sudo apt-get install python-setuptools
curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-13.0.3.tar.gz
tar xzf virtualenv-13.0.3.tar.gz && cd virtualenv-13.0.3
sudo python setup.py install

Oh, and we will also need git:

sudo apt-get install git

Finally, download Servo, but leave it alone for now:

git clone https://github.com/servo/servo

Updating dependencies

UPDATE: Most dependencies work correctly now

+ See the steps anyway

What you still have to do, is setting up the build system:

git submodule init
git submodule update
./mach bootstrap-rust
./mach bootstrap-cargo

Installing libraries

We will need to install the Rust standart libraries for ARM if we want to cross compile programs written in Rust. Let’s exit from the rootfs for a minute:

exit    # log out from 'servobuild'
exit    # log out from the rootfs

and copy your ARM Rust libraries to the correct location:

cp -R path/to/your/rustc/lib/rustlib/arm-unknown-linux-gnueabihf rootfs-trusty/home/servobuild/servo/.servo/rust/2d0cbf3e3e25e092bd9e4c94d08e446b680869f0/rustc-1.2.0-dev-x86_64-unknown-linux-gnu/rustc/lib/rustlib/

Note: Your target directory might have a different Rust hash/version.

Note: In case you’ve skipped the preface, you have to build the Rust standard libraries of the version used by Servo for ARM

If you skip this step, you will get std-related errors when compiling Rust code

We will also need to install the ARM system libraries if we don’t want to get linker errors later:

sudo cp -R path/to/your/lib/arm-linux-gnueabihf rootfs-trusty/lib/
sudo cp -R path/to/your/usr/lib/arm-linux-gnueabihf rootfs-trusty/usr/lib/

If you are not working in a rootfs, just remove the rootfs-trusty part of the commands.

We’re done with the libraries, let’s go back into the rootfs:

sudo chroot rootfs-trusty /bin/bash
su - servobuild
cd servo

There are two ‘missing header’ errors, for OpenSSL and Zlib. Apparently this is a packaging issue on certain distros. Anyway, you can fix it like this:

sudo mkdir -p /usr/include/arm-linux-gnueabihf/
sudo ln -s /usr/include/x86_64-linux-gnu/openssl /usr/include/arm-linux-gnueabihf/
sudo ln -s /usr/include/x86_64-linux-gnu/zconf.h /usr/include/arm-linux-gnueabihf/

Building!

Finally! If you’ve followed the previous steps correctly, running

PKG_CONFIG_ALLOW_CROSS=1 \
PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig \
EXPAT_NO_PKG_CONFIG=1 \
CC=arm-linux-gnueabihf-gcc \
CXX=arm-linux-gnueabihf-g++ \
CPP="arm-linux-gnueabihf-gcc -E" \
LD=arm-linux-gnueabihf-ld \
AR=arm-linux-gnueabihf-ar \
RANLIB=arm-linux-gnueabihf-ranlib \
./mach build --target=arm-unknown-linux-gnueabihf --dev

should build servo correctly, and you can find it at ./target/arm-unknown-linux-gnueabihf/debug/servo. Congratulations!

+ Show the old linker errors

Issues

Servo still has some visual (X11 and OpenGL) problems on embedded Linux, whether you build on board or cross compile.