Configuring bazel to cross compile for the Raspberry Pi 3

In the previous post, I described the motivation for switching the mjmech build system to bazel.  For that to be useful with Super Mega Microbot, I first had to get a toolchain configured for bazel such that it could produce binaries that would run on the raspberry pi.

All the work in this post is publicly available on github: https://github.com/mjbots/rpi_bazel

Compiler and sysroot

First, I needed to pick the compiler I would be using and how to get the target system libraries available for cross compilation.  In the past I’ve always done the gcc/binutils/gnu everything cross toolchain dance, however here I thought I would try something a bit more reproducible and see if I could make clang work.  Amazingly, a single clang binary supports all possible target types!  clang-6, which can be had through a PPA on Ubuntu 16.04 and natively on Ubuntu 18.04 supports it out of the box.

For the target system libraries, I wrote a small script: make_sysroot.py which when aimed at a live raspberry pi, will extract the Linux kernel headers and glibc headers and binaries.  These are stored in a single tar.xz file, with the latest version checked into the tree: 2018-06-10-sysroot.tar.xz.

Bazel configuration

bazel has a legacy mechanism for configuring toolchains, called the CROSSTOOL file.  It is not exactly pretty, is moderately underdocumented, but at least there are a few write ups online for how to create one.  The CROSSTOOL I created here is minimally functional, with options for both host/clang and rpi/clang with a few caveats:

  1. It isn’t hermetic, it relies on the system installation of clang
  2. It includes hard coded paths to micro releases of clang
  3. The C++ main function isn’t handled correctly yet, and you have to ‘extern “C”‘ it to link applications

With a functioning CROSSTOOL, the next step is to declare the “cc_toolchain_suite” and “cc_toolchain” definitions.  Those are defined in the tools/cc_toolchain/BUILD file and don’t have anything particularly complex in them.

Finally, I created a repository.bzl which is intended to be imported in client projects.  This provides a relatively simple API for a client project to import the toolchain, and gets the sysroot extracted properly.

Using it in a bazel project

The top level README gives the steps to use the toolchain, which while not too bad, still requires touching 4 non-empty files (and 2 possibly empty files).  Once that is done, you can use:

bazel test --config=pi //...

To build your entire project with binaries targeted to run on the raspberry pi!