ARM7 and ARM9

Building GCC for ARM

This tutorial explains how you can create a GCC+Newlib toolchain that can be used to compile programs for the ARM architecture, thus making it possible to compile programs for the large number of ARM CPUs out there. You'll need such a toolchain if you want to compile eLua for ARM CPUs. Please note that you can also use a pre-built toolchain to compile eLua (see toolchains for details) so building one yourself is not strictly required. This tutorial is similar to many others you'll find on the Internet (particulary the one from gnuarm, on which it's based), but it's a bit more detailed and shows some "tricks" (specifying parameters at compile time) you can use when compiling Newlib.

DISCLAIMER: I'm by no means a specialist in the GCC/newlib/binutils compilation process. I'm sure that there are better ways to accomplish what I'm describing here, however I just wanted a quick and dirty way to build a toolchain, I have no intention in becoming too intimate with the build process. If you think that what I did is wrong, inaccurate, or simply outrageously ugly, feel free to contact us and I'll make the necessary corrections. And of course, this tutorial comes without any guarantees whatsoever.

Prerequisites

To build your toolchain you'll need:

  • a computer running Linux: I use Ubuntu, but any Linux will do as long as you know how to find the equivalent of "apt-get" for your distribution. I won't be going into details about this, google it and you'll sure find what you need. It is also assumed that the Linux system already has a "basic" native toolchain installed (gcc/make and related).This is true for Ubuntu after installation. Again, you might need to check your specific distribution.
  • GNU binutils: get it from here. At the moment of writing this, the latest versions is 2.19.1, but it refuses to compile for ARM. Same goes for 2.19. In fact, the only newer version of Binutils that seems to work properly is 2.19.50, it can be downloaded from here. This is the version that we are going to use in this tutorial.
  • GCC:as I'm writing this, the latest GCC version is 4.3.3, which I'll be using for this tutorial. Download it from here after choosing a suitable mirror.
  • Newlib: as I'm writing this, the latest official Newlib version is 1.17.0, which I'll be using for this tutorial. Download it from here.
  • The tutorial assumes that you're using bash as your shell. If you use something else, you might need to adjust some shell-specific commands.

You need some support programs/libraries in order to compile the toolchain. To install them:

$ sudo apt-get install flex bison libgmp3-dev libmpfr-dev autoconf texinfo build-essential

Next, decide where you want to install your toolchain. They generally go in /usr/local/, so I'm going to assume /usr/local/cross-arm for this tutorial. To save yourself some typing, set this path into a shell variable:

$ export TOOLPATH=/usr/local/cross-arm

Step 1: binutils

This is the easiest step: unpack, configure, build.

$ tar -xvjf binutils-2.19.50.tar.bz2
$ cd binutils-2.19.50
$ mkdir build
$ cd build
$ ../configure --target=arm-elf --prefix=$TOOLPATH --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls
$ make all
$ sudo make install
$ export PATH=${TOOLPATH}/bin:$PATH
$ cd ../..

Now you have your ARM "binutils" (assembler, linker, disassembler ...) in your PATH.

Step 2: basic GCC

In this step we build a "basic" GCC (that is, a GCC without any support libs, which we'll use in order to build all the libraries for our target). Let's compile it (and note that the install step is a bit different from Newlib's):

$ tar -xvjf gcc-4.3.3.tar.bz2
$ cd gcc-4.3.3
$ mkdir build
$ cd build
$ ../configure --target=arm-elf --prefix=$TOOLPATH --enable-interwork --enable-multilib --enable-languages="c,c++" --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld
$ make all-gcc
$ sudo -s -H
# export PATH=/usr/local/cross-arm/bin:$PATH
# make install-gcc
# exit
$ cd ../..

Step 3: Newlib

Once again, Newlib is as easy as unpack, configure, build. But I wanted my library to be as small as possible (as opposed to as fast as possible) and I only wanted to keep what's needed from it in the final executable, so I added the "-ffunction-sections -fdata-sections" flags to allow the linker to perform dead code stripping:

$ tar -xvzf newlib-1.17.0.tar.gz
$ cd newlib-1.17.0
$ mkdir build
$ cd build
$ ../configure --target=arm-elf --prefix=$TOOLPATH --enable-interwork --disable-newlib-supplied-syscalls --with-gnu-ld --with-gnu-as --disable-shared
$ make CFLAGS_FOR_TARGET="-ffunction-sections -fdata-sections -DPREFER_SIZE_OVER_SPEED -D__OPTIMIZE_SIZE__ -Os -fomit-frame-pointer -D__BUFSIZ__=256"
$ sudo -s -H
# export PATH=/usr/local/cross-arm/bin:$PATH
# make install
# exit 
$ cd ../..

Some notes about the flags used in the above sequence:

  • --disable-newlib-supplied-syscalls: this deserves a page of its own, but I won't cover it here. For an explanation, see for example this page
  • -DPREFER_SIZE_OVER_SPEED -D__OPTIMIZE_SIZE__: compile Newlib for size, not for speed (these are Newlib specific).
  • -Os -fomit-frame-pointer: tell GCC to optimize for size, not for speed.
  • -D__BUFSIZ__=256: again Newlib specific, this is the buffer size allocated by default for files opened via fopen(). The default is 1024, which I find too much for eLua, so I'm using 256 here. Of course, you can change this value.

Step 4: full GCC

Finally, in the last step of our tutorial, we complete the GCC build. In this stage, a number of compiler support libraries are built (most notably libgcc.a). Fortunately this is simpler that the Newlib compilation step:

$ cd gcc-4.3.3/build
$ make all
$ sudo make install

Step 5: all done!

Now you can finally enjoy your ARM toolchain, and compile eLua with it :) If you need further clarification, or if the above instructions didn't work for you, feel free to contact us.