Building GCC for Cortex

This tutorial explains how you can create a GCC+Newlib toolchain that can be used to compile programs for the Cortex (Thumb2) architecture, thus making it possible to use GCC to compile programs for the increasingly number of Cortex CPUs out there (Luminary Micro, i ST, with new Cortex CPUs being announced by Atmel and other companies). I am writing this tutorial because I needed to work on a Cortex CPU for the eLua project and I couldn't find anywhere a complete set of instructions for building GCC for this architecture. You'll need such a toolchain if you want to compile eLua for Cortex-M3 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.

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:

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-cortex for this tutorial. To save yourself some typing, set this path into a shell variable:

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

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. They are fully capable of handling Thumb2.

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-cortex/bin:$PATH
# make install-gcc
# exit
$ cd ../..

Step 3: Newlib

Some modifications are in order before we start compiling. Namely, we need to tell Newlib to skip some of its libraries when compiling (I'm using vim to edit, feel free to use your editor of choice instead):

$ tar -xvzf newlib-1.17.0.tar.gz
$ cd newlib-1.17.0
$ vim configure.ac

Find this fragment of code:
  arm-*-elf* | strongarm-*-elf* | xscale-*-elf* | arm*-*-eabi* )
    noconfigdirs="$noconfigdirs target-libffi target-qthreads"
    libgloss_dir=arm
    ;;

And add "target-libgloss" to the "noconfigdirs" variable:
  arm-*-elf* | strongarm-*-elf* | xscale-*-elf* | arm*-*-eabi* )
    noconfigdirs="$noconfigdirs target-libffi target-qthreads target-libgloss"
    libgloss_dir=arm
    ;;

Save the modified file and exit the text editor.

$ autoconf

On one of the systems I ran the above sequence, it terminated with
errors, complaining that autoconf 2.59 was not found. I don't know why
that happens. 2.59 seems to be quite ancient, and the build ran equally
well with 2.61 (the version of autoconf on the system that gave the
error). If this happens to you, first execute autoconf --version to
find the actual version of your autoconf, then do this:
$ vim config/override.m4

Look for this line:
  [m4_define([_GCC_AUTOCONF_VERSION], [2.59])])

And replace [2.59] with your actual version ([2.61] in my case).
Save the modified file and exit the text editor. 

$ autoconf

Once again, now we're ready to actually compile Newlib. But we need to tell it to compile for Thumb2. As already specified, I'm not a specialist when it comes to Newlib's build system, so I chose the quick, dirty and not so elegant solution of providing the compilation flags directly from the command line. Also, as 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, I added the "-ffunction-sections -fdata-sections" flags to allow the linker to perform dead code stripping:

$ 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 -mcpu=cortex-m3 -mthumb -D__thumb2__ -D__BUFSIZ__=256" CCASFLAGS="-mcpu=cortex-m3 -mthumb -D__thumb2__"
$ sudo -s -H
# export PATH=/usr/local/cross-cortex/bin:$PATH
# make install
# exit 
$ cd ../..

Some notes about the flags used in the above sequence:

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, as long as you remember that we want to build our compiler support libraries for the Cortex architecture:

$ cd gcc-4.3.3/build
$ make CFLAGS="-mcpu=cortex-m3 -mthumb" CXXFLAGS="-mcpu=cortex-m3 -mthumb" LIBCXXFLAGS="-mcpu=cortex-m3 -mthumb" all
$ sudo make install

All Done!

Phew! That was quite a disturbing tutorial, with all that confusing flags lurking in every single shell line :) But at this point you should have a fully functional Cortex GCC toolchain, so enjoy it! If you need further clarification, or if the above instructions didn't work for you, feel free to contact us.