Cross compiling
Compiling directly on the Raspberry Pi (working under Raspbian) is possible, and in fact, some things are easier this way. But using a complete IDE on the Raspi will be really slow.
If we want to write a small tool with a few C files, the native gcc on the Raspi will be sufficient. And we do not have to care about different versions of glibc or else. Compiling the kernel or some larger project can take hours or even more than one day.
So using a cross compiler will be the solution.
In the following sections we assume that we either need a cross compiler for :
- compiling the kernel / kernel module (add LCD module to Raspi)
- use Wt (Web Toolkit) together with Qt creator
Both were my personal requirements for a cross toolchain. Using Wt on the Raspi is a bit special and of course not a requirement which many will have. More to Wt and it’s usage later (on a separate post).
Cross compiling under Linux
It should be clear that the used CPU is the main key parameter for a cross compiler. In the case of a Raspberry Pi, we compile under Intel for the target architecture ARM.
Luckily, the OS is the same here, but there are some more things that need to be considered.
It is not sufficient to just have a compiler which produces ARM instructions instead of i386.
The compiler must know the calling conventions on the target and the ARM instruction version.
And: you need the libraries available to link against.
If we search the web, there are many different suggestions for a Raspbian cross compiler:
HOWTO: cross-compile for raspberry pi on Ubuntu 12.04
Development Environment for the Raspberry Pi using a Cross Compiling Toolchain and Eclipse
Cross compilation for Raspberry Pi
Beginner’s guide to cross-compile Qt5 on RaspberryPi
Cross-Compiling Qt for Embedded Linux Applications
how to work with external libraries when cross compiling?
Cross-compiling for the RaspberryPi
I did a hard job of trying most of these instructions and find the best way for me. One of the problems I encountered was, that a specific instruction may be of some age and today some parts of the instruction are either not needed anymore, or just do not work with current versions of some of the prerequisites.
In the end, I found the best way for me. This was done around June 2014. So some parts of this post may be already outdated if you read these lines. Nevertheless, I hope you will find this of any use, and possibly you comment on this.
Linaro toolchain
When I heard about the Linaro toolchain first, I thought this was a commercial company, and I was not sure if this is the right way to go, how “official” this is and so on. I found out that Linaro is the offical and probably best way to install a cross compiling toolchain for the Raspberry Pi.
Wikipedia writes about Linaro:
…Linaro is a not-for-profit engineering organization that works on free and open-source software such as the Linux kernel, the GNU Compiler Collection (GCC), ARM power management, graphics and multimedia interfaces for the ARM family…
So, how do we install this Linaro thing ?
Since there are many adjustment screws for the compiler, we best download the already tuned
toolchain for Raspi.
We could get this via “git clone“, but I prefer the direct download.
But which version ?
Latest version:
♦ Go to: https://github.com/raspberrypi/tools
♦ “Download ZIP” (https://github.com/raspberrypi/tools/archive/master.zip)
There is a good chance that this version will run perfectly with the newest Raspbian, downloaded from the Raspberry Foundation download page.
But – perhaps you may want a specific version, in match with a specific Rasbian.
See Specific version on github for an explanation of the backgrounds.
Specific version:
I used Raspbian 2014-06-20-wheezy for my own work. This can be found at the Images Archive
I used cross compiler toolchain from this specific commit.
Unpack the zip
We do not need all the files in the ZIP, so we just extract what we need. For me, I also archived this subdirectory, for having it at hand if I should need this version anytime later.
32 bit or 64 bit ?
There are 32 bit and 64 bit binaries in the ZIP. The difference is the host OS, both produce 32 bit code for the Raspi of course.
for 32 bit host Linux
unzip tools-master.zip tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/*
for 64 bit host Linux
unzip tools-master.zip tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/*
I recommend moving / renaming this to a more handy name.
I moved this into a “linaro” dir and created a new archive of it:
mv tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64 /home/user/linaro cd /home/user tar czf linaro.tar.gz linaro
For unpacking this (if we need it later):
tar xzf linaro.tar.gz
Then you have a linaro subdirectory in the current path with the tailor-made cross tools for you.
Usage
The first questions which I personally had before the actual usage:
- how will the compiler / bin tools be called ?
- how to specify header / library paths ?
We have to distinguish between the native gcc on the host and the cross compile.
This is done in this clever way:
The binary files can be found in the bin subdir:
arm-linux-gnueabihf-gcc arm-linux-gnueabihf-c++ ...
Every executable has a special prefix.
If we want, we can add the bin dir to the search path, or just use the absolute path.
For me, I use the absolute path.
There are, fortunately, many software source packages already support cross compiling.
For some, you just give the path and prefix, like
/home/user/linaro/bin/arm-linux-gnueabihf-
for other, the path to the gcc is given:
/home/user/linaro/bin/arm-linux-gnueabihf-gcc
The make system knows that it has to use the prefix for starting the executables.
So, first question answered.
Then how to specify header / lib paths ?
You do not need this. The trick is that all needed paths are already predefined in the executables.
First test
Obviously, we create a hello.c:
#include <stdio.h> int main(void) { printf("Hello Raspi\n"); return 0; }
/home/user/linaro/bin/arm-linux-gnueabihf-gcc -o hello hello.c file hello hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=fd464fd12dd3690996062052164c6bc90b132cd6, not stripped
We transfer the hello file to the Raspberry and start it there:
./hello Hello Raspi
Library versions
In some instructions we can read about copying the native header and libraries from the Raspberry to the cross compile host.
For me, this was not necessary. Of course, we have to ensure that the glibc and other shared libraries should match in their versions.
I successfully compiled a complete kernel, all Wt (Web Toolkit) files, and the complete Qt library successfully with this method.
Summary and next steps
During reading of these lines, it looks easy in my own retrospective, and in fact, if you know how to do it, it is fairly easy.
What was a bit more complex was the building of Wt, Qt and the kernel.
If you ask about the backgrounds:
The idea of writing web apps in C++ sounds a bit weird at first, but I found Wt the ideal solution for me and the following project:
I wanted to use a Raspi as a mini server which periodically logs into a Fritzbox, reads out the phone caller list and displays this on a small LCD
Beeing Wt as the main service behind and an easy way to configure this and be able to query more detailed information.
See more on Building Web apps with Wt for Raspberry Pi