How to build a cross compiler for your Raspberry Pi

A cross compiler is a compiler that runs on one platform/architecture but generates binaries for another platform/architecture. With devices like the Raspberry Pi, where you really don’t have much CPU or memory to work with, if you’re doing any heavy compiling (like when working on the kernel) a cross compiler is the only way to go. For example, I build all my Raspberry Pi kernels on my nice Sandy Bridge Xeon E3 home server where they compile in only a fraction of the time they would on the Pi.

While there are a lot of different methods for building cross-compilers, by far the quickest and easiest is to use crosstool-ng. This is a set of scripts that bring up a menuconfig-like interface to choose your compiler settings, then goes off and downloads what it needs, patches it, configures it, builds it and installs it all for you. Here’s how to get started:

  1. Download crosstool-ng from the project web site. I’ve used version 1.15.2 as that was the latest when I wrote this.
  2. Unpack the tarball and cd into the unpacked directory, then run ./configure --prefix=/opt/cross. You can pick somewhere else instead of /opt/cross but that’s where I like to keep it.
  3. Run make and sudo make install.
  4. Make sure /opt/cross/bin is in your $PATH.

Right, so that’s crosstool-ng installed and ready to build a toolchain for you. Next, to actually create your Raspberry Pi toolchain:

  1. Create a directory somewhere in your home directory that crosstool-ng will use as a staging ground. This will contain your toolchain configuration, downloaded files, and intermediary build results. This is not where your final toolchain will end up, and does take up quite a lot of space (3.5GB and up for me). cd into your chosen directory.
  2. Run ct-ng menuconfig. You should see the ct-ng configuration menu.
  3. Go into Paths and misc options. Enable Try features marked as EXPERIMENTAL. This is important.
  4. While you’re there you may want to change your Prefix directory. I like to put all my toolchains in /opt/cross/x-tools/${CT_TARGET} instead of ${HOME}/x-tools/${CT_TARGET}.
  5. Go back to the main menu and select Target options.
  6. Change the Target architecture to arm. Leave Endianness set to Little endian and Bitness set to 32-bit.
  7. Go back to the main menu and select Operating system (skip Toolchain options, the defaults are fine).
  8. Change Target OS to linux.
  9. Go back to the main menu and select Binary utilities.
  10. Change binutils version to 2.21.1a or whichever is the latest that isn’t marked as experimental. Probably unnecessary but I prefer this.
  11. Go back to the main menu and select C compiler.
  12. Enable the Show Linaro versions (EXPERIMENTAL) option.
  13. In the gcc version field, choose the linaro-4.6-2012.04 (EXPERIMENTAL) compiler. You’re free to choose a different one but I know this one works well. I do recommend the Linaro versions over the vanilla ones for the RPi.
  14. All the other settings are fine left at their default values. Exit the configuration tool and save your changes.
  15. Run ct-ng build.
  16. Go away and make a coffee, etc… This bit will take some time.
  17. You should end up with a freshly baked arm compiler ready for building kernels (and other things) for your Raspberry Pi in your Prefix directory you chose above.
  18. Just add your compiler directory to your $PATH and start compiling. If you used my preferred prefix directory, you would want to add /opt/cross/x-tools/arm-unknown-linux-gnueabi/bin.

Now give your compiler a quick sanity check:

bootc@tarquin ~ $ arm-unknown-linux-gnueabi-gcc --version
arm-unknown-linux-gnueabi-gcc (crosstool-NG 1.15.2) 4.6.4 20120402 (prerelease)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

bootc@tarquin ~ $ cat > test.c
#include <stdio.h>
int main() { printf("Hello, world!\n"); return 0; }
^D
bootc@tarquin ~ $ arm-unknown-linux-gnueabi-gcc -o test test.c
bootc@tarquin ~ $

Copy over the newly compiled test program to your Raspberry Pi and run it. You should see:

bootc@raspberrypi:~$ ./test
Hello, world!
bootc@raspberrypi:~$

That’s it! Enjoy.

29 thoughts on “How to build a cross compiler for your Raspberry Pi

  1. thanks for this. Tried setting it up as per your suggestions but it crashes out during the ct-ng build with

    [DEBUG] Trying ‘ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-ppl-0.15.11’
    [DEBUG] ==> Executing: ‘wget’ ‘–passive-ftp’ ‘–tries=3’ ‘-nc’ ‘–progress=dot:binary’ ‘-T’ ’10’ ‘-O’ ‘/home/patrick/Downloads/pidev/.build/tarballs/cloog-ppl-0.15.11.tmp-dl’ ‘ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-ppl-0.15.11’
    [ALL ] –2012-05-31 22:33:31– ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-ppl-0.15.11
    [ALL ] => `/home/patrick/Downloads/pidev/.build/tarballs/cloog-ppl-0.15.11.tmp-dl’
    [ALL ] Resolving gcc.gnu.org… failed: Connection timed out.
    [ALL ] wget: unable to resolve host address `gcc.gnu.org’

    any suggestions?

    Also I want to compile panda3d for the rPi and the compile and make is all done through their python script. Presumably it’s possible to get that to use the new arm cross compiler??

    Paddy

    • Sounds to me like a temporary connectivity issue. I just tried that download a second ago and it worked.

      Unfortunately I have no idea if it’s possible to cross-compile panda3d, sorry.

  2. I found I needed to select softfp during menu configuration to get the OpenGL ES example to work.

  3. Hey,
    nice howto, tyvm for that!
    Works perfectly for C files, I just wondered if it’s possible to compile C++ files, too. Just executing:
    fred@virtualbox:~$ arm-unknown-linux-gnueabi-gcc -o test test.cpp
    produces this error:
    C++ compiler not installed on this system

    Is it actually possible to compile C++?

    Fred

    • Crosstool-Ng doesn’t build a C++ compiler by default. You’ll have to go back into the ct-ng menuconfig and go into C-compilerAdditional supported languages and enable C++, then re-run ct-ng build. You also probably want to use arm-unknown-linux-gnueabi-g++ instead of the -gcc version for C++ source files.

  4. Hi Chris

    Thanks for taking the time to put these instructions up there. Unfortunately for me, the “ct-ng build” always fails for me with

    Installing C library headers & start files
    [ERROR] configure: error:
    [ERROR]
    [ERROR] >>
    [ERROR] >> Build failed in step ‘Installing C library headers & start files’
    [ERROR] >> called in step ‘(top-level)’
    [ERROR] >>
    [ERROR] >> Error happened in: CT_DoExecLog[scripts/functions@172]
    [ERROR] >> called from: do_libc_backend_once[scripts/build/libc/glibc-eglibc.sh-common@347]
    [ERROR] >> called from: do_libc_backend[scripts/build/libc/glibc-eglibc.sh-common@143]
    [ERROR] >> called from: do_libc_start_files[scripts/build/libc/glibc-eglibc.sh-common@60]
    [ERROR] >> called from: main[scripts/crosstool-NG.sh@598]
    [ERROR] >>
    [ERROR] >> For more info on this error, look at the file: ‘build.log’
    [ERROR] >> There is a list of known issues, some with workarounds, in:
    [ERROR] >> ‘/opt/cross/share/doc/crosstool-ng/ct-ng.1.15.2/B – Known issues.txt’
    [ERROR]
    [ERROR] (elapsed: 16:40.79)
    [16:41] / make: *** [build] Error 1

    I’ve tried using both 32 bit & 64 bit Ubuntu 12.04 Virtual Machines under VMPlayer, and always the same result. Selecting GLIBC gives similar results 🙁

    Any ideas what I’m doing wrong please ?

    Very many thanks

    Peter

    PS I haven’t included the build.log because it’s 4.8 MByte in size

  5. Thank you very much for this. I did not known crosstool-ng.

    Currently eglibc 2.15 would not compile due to an undefined macro. You have to apply a patch:

    cd .build/src/eglibc-2_15
    wget http://crosstool-ng.org/hg/crosstool-ng/raw-file/252ade1e9e17/patches/eglibc/2_15/110-aclocal-LIBC_TRY_CC_OPTION.patch

    patch –verbose -p1 <110-aclocal-LIBC_TRY_CC_OPTION.patch

    You can read further in:
    http://crosstool-ng.org/hg/crosstool-ng/file/252ade1e9e17/patches/eglibc/2_15/110-aclocal-LIBC_TRY_CC_OPTION.patch

    Regards,
    moh

  6. Might be worth mentioning the dependencies that you need. On a clean Ubuntu 12.04, you need to install bison, flex, texinfo (to get makeinfo), libtool, automake and libncurses5-dev.

    • Thank you! Figured out the first few but didn´t know the others and it was doing my head in!

  7. Also note that, following your instructions, the user building the toolchain must have read-write access to /opt (or root can mkdir /opt/x-tools; chown /opt/x-tools).

  8. Another suggestion – it might save a lot of people quite a bit of time and effort if you mentioned up-front that working cross-compilers are easily available. Ubuntu, for instance, provides gcc-4.6-arm-linux-gnueabi and related packages which work out of the box.

    • Possibly, though the Ubuntu cross-compiler is not necessarily a good example. Particularly when compiling userspace code, it defaults to targeting ARM7 while the Raspberry Pi is ARM6, so you can get illegal instruction errors. Crosstool-ng not only gives you finer grained control over compiler switches like that, but also allows you access to newer versions of tools to get access to fixes for the all-too-common toolchain bugs.

  9. I was trying this on an OpenSUSE x64 VM and had to fix 2 things. The menu.h file was not getting found and fixed it using this method: http://old.nabble.com/Re%3A-Can%27t-compile-crosstool-ng-1.15.2-on-OpenSuse-Linux-p34120780.html

    Then I ran into the [ERROR] Static linking impossible on the host system ‘x86_64-build_unknown-linux-gnu’ problem. For some reason the menuconfig was forcing CT_WANTS_STATIC_LINK=y in the .config file even though it was not set in the menuconfig. I changed that to =n and things started working.

  10. Any chance of a blog post on using cross compiling and Windows? perhaps using Eclipse and the gdpserver?

    thanks,
    Nathan

  11. Thanks for this, finally got it to build the test.c at the end and runs successfully on the Pi. While there may be other ready-made ways of doing it (and I am not qualified to judge) the effort of getting this to work (and finding all the dependencies and pitfalls) has been useful in understanding much. Incidentally, this took 57minutes to build on one core of an i970 running Windows Server 2012RC.

    As someone that came to Linux ‘in anger’ 4 weeks ago when I got my Pi I’ve learnt a lot by ‘doing it the hard way’. That included running out of disc space on a 10Gb VHD (HyperV/Debian) and having to create a new 25Gb VHD, move everything across, get stuff mounted, reGRUB’d, etc. just so i could get the tool chain built.

    Now to get on with the next bit – creating a device driver/interrupt handler. Been there/done that under Windows, but still, another learning curve…

    • I am happy to read about your success. I am currently looking at my build.log file as ct-ng does its building. Its been 15 mins of building and many many stumbling blocks already, which I have crossed luckily. But now I have no idea of what kind of error log awaits at the 50 minute mark. As I was reading through all the post in hopes caution or danger signs your post of wanting to write device drivers for pi attracted me.

      I am in the same boat now. Calling myself a novice in Linux or OS world might be an overstatement. My ultimate goal when purchasing my pi was to write device drivers for it and to get to learn something, not to watch HD movies. Pretty much like most Pieple that I know. But still I have not found a good source to learn how to set up the Pi for kernel building. So I was wandering if you or Chris have already gotten it working and could help me out with understanding the procedure.

      things I understand:
      1. The kernel src and the system kernel binary must be the same: My Pi OS is Raspbian and it looks like it is using 3.1.9+ kernel. So, in order for me to compile any kernel on borad i need the kernel source 3.1.9+.

      2. Once I find the right kernel I can put it in say /usr/src dir of my Pi. Create a symlink to it from my /lib/modules/3.1.9+ directory and then start build off of it.

      I tried that with some source from git hub hoping that it was the same kernel source but when compile a module using it I get a bagillion errors warning about all sorts of things missing or not defined.

      So now I am thinking about using a new kernel src like 3.2.XX to build a kernel.img. Load that kernel image on to the SD card and also its source. then use that source to build kernel modules on my Pi.

      What am I doing wrong? If you’ve gotten it, what did you do to get it working?

      Any sort of help will be greatly appreciated.

      Thanks
      Jabeer

  12. Successfully ran the cross-compiled test.c app on my PI, awesome!

    To make it work on my CentOS 6.3 install, I had to:
    1. yum install gmp-devel.
    2. Select version 4.3.1 of GMP (in menuconfig).
    3. Select version 0.8.2 of MPC (in menuconfig).
    4. Manually set CT_WANTS_STATIC_LINK to “n” rather than “y” in .config.

  13. i am a windows user and find the instructions less than straight forward. first four steps for getting ng i think i managed. but the step 1 that follows basically says create new folder, enter it (ok, just a new folder) then step 2 is to run ‘ct-ng menuconfig’ which does not work. i tried to see what is going on and it looks like ct-ng does not run, even if i change to that folder (/opt/cross/bin). i can see the content by ‘cat ct-ng’ for example but this scrip does not run. when i issue ‘ls -l’ i see that flags are
    -rwxr-xr-x and if i recall x is for executable so it should run but i get ‘bach: ct-ng: command not found’. what can be done here?

    • I’m currently falling over at the first hurdle here. I’m try this with cygwin and when i use the ./configure –prefix=/opt/cross i also just get the error about no acceptable C compiler being found.

      In the log I can see it checks for gcc, then cc and then cl.exe – all of which it doesn’t find. If i crack it I’ll let this excellent blog know 🙂

      Mat

      • I reckon crosstool-ng is going to be a non-starter for cygwin.

        Following Chris’s steps, I cant get past the initial ones:-

        1. Download crosstool-ng from the project web site. I’ve used version 1.15.2 as that was the latest when I wrote this.
        OK – that was good.

        2. Unpack the tarball and cd into the unpacked directory, then run ./configure –prefix=/opt/cross. You can pick somewhere else instead of /opt/cross but that’s where I like to keep it.
        OK – that seemed to go ok.

        3. Run make and sudo make install.
        make had a bunch of zconf… ‘undefined reference errors’ and a final link failed error. So, put /opt/cross/bin in $PATH (PATH=”${PATH}:/opt/cross/bin”; export PATH) and tried again. Same errors and so ignored them.

        sudo make install – just falls over saying ‘sudo command not found.’ There is no such thing as sudo in cygwin as the rights are the rights of whatever windows user launched the terminal. So, closed the terminal and reopened as administrator (IE. ‘run as…’). retried ‘make install’ after changing to the users folder (IE. cd ./Mat/crosstool-ng-1.16.0). Still fails. When i say ‘make install’ the LD ‘conf’ has a load of zconf.tab.o:zconf.tab.c:(.text+0xnnnn): undefined reference to `_libintl_gettext’ errors. Reading a number of posts about this (web searched on _libintl_gettext cygwin) it is a common issue and I’ve not found a fix.

        So. Conclusion (which I’d be delighted to be proved wrong on! :-)) is that cygwin & crosstrool-ng cant be used to build r-pi executables. Back to square one…

  14. Could you sched some light how you create such kernels ? I mean do you get latest one from kernel.org and simply compile it ? What about architecture BCM2…. that is not present is official kernel ?
    What should I do if I have original RPI kernel 3.1.9 from gitbut/raspberrypi/linux and want to go higher to ie. 3.2.27 ?
    I use cross compile tools in Debian i386

  15. Can give another document to teach how to us crosstool compile your kernel source?

  16. I followed the steps but when i try to run the hello world on my raspberry i get that :
    pi@raspberrypi:~ $> ./test
    -bash: ./test: Aucun fichier ou dossier de ce type
    Which means “No such file or directory”

    And no i did not forget to upload it 🙂

    • Are you using Raspbian, which is armhf? In which case the cross-compiler will need a different configuration for userspace programs, which I haven’t looked at yet. It will still be fine for building kernels with.

      • I’m using debian, the latest version available on the raspberry’s wiki. How do i know what armhf i use ?

        What compiler’s option should i look at ?

  17. Very good tutorial.
    I compiled the hello.c with these changes for Raspbian (2012-07-15-wheezy-raspbian.img )
    – in C Compiler => Show Linaro versions I choose linaro-4.7.0-2012.04
    – C Compiler => Additional support C++
    – Debug facilities => ltrace (tried with strace too, but it fails downloading it, so i gave up)
    and it ran properly (showing the output):
    user@raspberrypi:~$ ./test
    Hello, world!

    However, there is a weirdness that will prevent some larger projects to build:
    user@desktop:~$ arm-unknown-linux-gnueabi-gcc -dumpmachine
    arm-unknown-linux-gnueabi

    but
    user@raspberrypi:~$ gcc -dumpmachine
    arm-linux-gnueabihf

    For example, the configure step of qt5 building will look for the headers like

    user@raspberrypi~$ ls /usr/include/arm-linux-gnueabihf/bits/predefs.h
    /usr/include/arm-linux-gnueabihf/bits/predefs.h
    in the non-existant path:

    user@raspberrypi~$ ls /usr/include/arm-unknown-linux-gnueabi/bits/predefs.h
    ls: cannot access /usr/include/arm-unknown-linux-gnueabi/bits/predefs.h: No such file or directory

    So: is it possible to change the target name (CT_TARGET) in ct-ng menuconfig from arm-unknown-linux-gnueabi to arm-linux-gnueabihf ?

    Thanks, Ribamar

Comments are closed.