Raspberry Pi – Cross-compiling

Now that you have the hardware built and tested (although that’s not necessary), you can either use the code I’ve written-which is specific to the hardware and environment I have, or compile your own version. If you want to compile your own there are two options:

  1. Compile on the Pi itself
  2. Compile on an ARM virtual machine
  3. Cross-compile on a faster machine

The trade off? Compiling on the Pi is slow (very slow). The virtual machine is a marked improvement for compiling speed, but is complicated to setup. Cross-compiling is about the same difficulty as setting up a virtual machine but a bit faster and less “bulky”. So it depends. The virtual machine is nice if you have a lot of libraries you want to use, since you’ll have to compile all of them to be available for linking. If any of them have poor autoconfig support, it might be a pain to fix if you weren’t already on the target machine. But, since I just needed one or two popular libraries, I decided to setup cross-compiling from my host (x86_64) machine.

The last time I setup cross-compiling it was on Gentoo, and it wasn’t pleasant. However, after a little bit of research it looks like the crosstool-ng project is pretty popular and useful. I only had to patch one tiny thing.

Here’s the overall process:

  1. Install crosstool-ng
  2. Configure a cross toolchain with it
  3. Try and build the toolchain
  4. Use the toolchain to build your Pi code

Here are some relevant links that I found useful. I installed from source since there wasn’t a package available. Add `ct-ng` to your PATH if you want. Now create a folder just for Pi compiling, where your toolchain and other libraries will reside. I used `~/dev/rpi`.

You can `ct-ng menuconfig` to configure what compiler and arch you need. I’ve got all the settings here, which you can save and import:

~/dev/rpi/arm-rpi-linux-gnueabi/samples/crosstool.config
CT_EXPERIMENTAL=y
CT_LOCAL_TARBALLS_DIR="${HOME}/src"
CT_ARCH_ARCH="armv6j"
CT_ARCH_FLOAT_HW=y
CT_ARCH_arm=y
CT_TOOLCHAIN_PKGVERSION="Raspberry Pi"
CT_TARGET_VENDOR="rpi"
CT_KERNEL_linux=y
CT_KERNEL_V_3_12=y
CT_BINUTILS_V_2_22=y
CT_LIBC_EGLIBC_V_2_13=y
CT_CC_GCC_SHOW_LINARO=y
CT_CC_V_linaro_4_8=y
CT_CC_LANG_CXX=y

For reference, these are the toolchain versions on my Pi:

$ ldd --version
ldd (Debian EGLIBC 2.13-38+rpi2+deb7u1) 2.13

$ gcc --version
gcc (Debian 4.6.3-14+rpi1) 4.6.3

$ ld --version
GNU ld (GNU Binutils for Debian) 2.22

$ uname -a
Linux raspberrypi 3.12.33+ #722 PREEMPT Sat Nov 22 12:03:51 GMT 2014 armv6l GNU/Linux

Building

After configuring it, try to build via `ct-ng build`, and see what happens.

Fixing a build problem

When trying to build eglibc on my machine, crosstool-ng ran into a bug in eglibc’s configuration scripts where my make was “too new”, and the configuration for eglibc borked. While the eglibc INSTALL text says use make 3.79 or newer, the actual configure file limits it to 3.79 or 3.89 (or something like that, I’m not entirely sure on the matching syntax). You can fix that by changing one line in it’s configuration script. It took me a while to find a solution. It was in French, and it didn’t mention which file! I knew it was a configure script so I grep’d all the configure scripts in .build. The file you need to change is:

.build/src/eglibc-2_13/configure

Here’s the patch file from the linked post:

--- a/configure    2014-01-03 14:08:59.027618540 +0100
+++ b/configure    2014-01-03 14:10:24.897615610 +0100
@@ -4936,7 +4936,7 @@
ac_prog_version=`$MAKE --version 2>&1 | sed -n 's/^.*GNU Make[^0-9]*\([0-9][0-9.]*\).*$/\1/p'`
case $ac_prog_version in
'') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    3.79* | 3.[89]*)
+    3.79* | 3.[89]* | 4.*)
ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
*) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;

In my case, the relevant line was around line 5000 in the actual file, in my case. So the patch wouldn’t have worked anyway.

Building (Round 2)

So, now building should work. Try `ct-ng build` again if you had this problem.

It took over 30 minutes (not including download time) on my Core i5, but it eventually finished:

[INFO ]  Build completed at 20141205.163716
[INFO ]  (elapsed: 34:41.97)
[INFO ]  Finishing installation (may take a few seconds)...

Compiling Libraries

Next up were the libraries I wanted to use. I have just to for my project:

  • bcm2835 - A C library for easy access to the GPIO pins
  • ncurses - For writing anywhere to the screen among other useful I/O things

bcm2835 is pretty much required on the Pi, although there are other ways to access the pins. Ncurses is just for pleasant output. If you’re not familiar with it, you can easily write out text anywhere on the terminal screen. You can also create “windows” and GUI controls, all using terminal characters. It’s what `ct-ng menuconfig`, and lots of other projects (including the Linux kernel configuration) use.

Building bcm2835

Download the latest version of the library and extract it. I extracted it in my `~/dev/rpi` directory. I installed it to the same directory as well. You could put it in the cross-tools sysroot (default is ~/x-tools/[system tuple]/sysroot or something like that), but I’d leave that be.

./configure --build=arm-linux --host=arm-rpi-linux-gnueabi --prefix=/home/nick/dev/rpi

`-build=arm-linux` - This will just set the build argument, so the default is not used. It may not be needed.

`-host=arm-rpi-linux-gnueabi` - This, in combination with a non-default build value, will allow for cross-compiling. I think the build value can be whatever you want as long as it is defined manually. Ncurses didn’t seem to need it at all.

`-prefix=/home/nick/dev/rpi` - Where to install the resulting files when doing a make install. It installs into lib/ and include/, which aren’t used by crosstool-ng so it works for me. This way my ~/dev/rpi can be used as the lib and include folder for other pi projects later on as well.

After configure runs, just `make && make install`. No `sudo` needed since your installing under your home.

Building ncurses

Acquire the latest version: https://ftp.gnu.org/pub/gnu/ncurses/ and extract it. Again I extracted and installed it in my `~/dev/rpi` directory. Run configure:

./configure arm-linux --host=arm-rpi-linux-gnueabi --prefix=/home/nick/dev/rpi --disable-big-core --enable-termcap --with-shared --without-manpages

The additional switches here enable low-memory usage, terminal capability detection, skips the manpages, and I’m not sure why `-with-shared` is there, since this should not, ideally, be a shared library. Then again my Pi already has ncurses installed so it might not be so bad after all.

There, done! It took a while, but now you should be able to `make` the rpi-drd project.