Building the GNU ARM Toolchain for Bare Metal

This is a quick guide to building the GCC toolchain for the ARM architecture.  I wrote this to cleanup some other instructions that I've seen floating around the web, and to have instructions that are based of the newest releases of GCC, GDB and Newlib.

This is the build that I use to develop for the Stellaris LM3S1968 (a Cortex M3) processor, which is why I'm building arm-none-eabi.  This compiler sucsessfuly works at building the Luminary Micro LM3S development libraries, FreeRTOS and makes working binares for bare metal (no OS) software.

You are not going to be able to build for much other than bare-metal with this kind of toolchain.  If you want to develop for embedded Linux targets, you're going to have to build against the real GLIBC...  But the whole point here is for small target footprints, either running simple os-free apps, or with some kind of lightweight RTOS... This is why we're going with Newlib.  So keep in mind that while you don't get the "kitchen sink" you still get a very functional toolchain.

For building the GCC toolchain I am using the following:



what?  Nobody ever explained this naming convention to me.  So I had to figure that one out myself.  Basically this is what kind of toolchain we're building. It is what is called the Target Alias.  You will see all of your toolchain executables prefixed by this (like arm-none-eabi-gcc, etc.)  This distingues them from the native host compiler, and other target compilers that you may have.  There doesn't seem to be a concrete way that these names are dolled out, rather they follow a rather loose format something like "<architecture>-<something about OS/libraries>-<ABI>"... sometimes 3 tokens, sometimes 4.

Basically, "arm-none-eabi" means:

some other common ones for arm are:




Getting the Source

Keep in mind the package versions I'm using are not only the newest RELEASE versions of these packages, but they are shown to play nice with each other... If you use these versions, it should work for you too.   However, I would recommend that you try the newest releases to be current.  I don't really see there being any issues.  The newest releases of GCC, GDB and binutils should ALWAYS work together.  The newest release of newlib will probably work with them.

Ok, now we're going to setup a working folder.. i'm going to refer to it as ARM... so ARM/src should really be something like /home/yourname/arm/src.
So go ahead and make the following directories:

# make base dir
mkdir ARM
# original archives dir
mkdir ARM/orig
# unpackaged source dir
mkdir ARM/src
# path for building the sources (to keep them separate from the original sources)
mkdir ARM/build

Then figure out where you want your binaries and libraries to get installed to.  I would recommend building to a home directory like /home/yourname/site so that you end up having /home/yourname/site/bin, /home/yourname/site/lib, etc.  This provides a nice clean way to have your own tools and libraries build.  You would just need to add /home/yourname/bin and /home/yourname/sbin to your path.  This is the method I'm assuming your're using (which doesn't require root access).

Create your site path and setup and environment variable to point to it.

mkdir /home/yourname/site
export MYTOOLS=/home/yourname/site

Download all of the source files with wget, or web browser, etc. (Note: this is about 164MB to download)

# go to our originals path
cd ARM/orig

# Grab the GNU C Compiler source files

# Grab the GNU Debugger source files

# Grab the GNU binutils source files

# Grab the Newlib source files

Now we are going to unpack all of these files (Takes another 630MB of space)

# Goto our source path
cd ARM/src

# unpack the source archives
tar xzvf ../orig/gcc-4.3.3.tar.gz
tar xzvf ../orig/gcc-core-4.3.3.tar.gz
tar xzvf ../orig/gcc-g++-4.3.3.tar.gz
tar xzvf ../orig/gdb-6.8.tar.gz
tar xzvf ../orig/binutils-2.19.tar.gz
tar xzvf ../orig/newlib-1.17.0.tar.gz

That's it, we're now ready to build our ARM toolchain.


Building the toolchain

Building the toolchain is pretty simple.  It is more a matter of know the correct order in which to build it, and what options are needed to get a working compiler.  I will try and explain the order and the options that we're using as we go.

First we need to get the binutils built.  This will provide us with lots of useful tools needed in building ARM libraries and binaries (like objdump, ld, ranlib, etc.)

mkdir ARM/build/binutils-2.19
cd ARM/build/binutils-2.19
../../src/binutils-2.19/configure --target=arm-none-eabi --prefix=$MYTOOLS --enable-interwork --enable-multilib
make all install
export PATH="$PATH:$MYTOOLS/bin"

You will notice a few configure options that are really critical for getting things to work properly.

Next, we build the GCC compiler (but not the entire GCC package!)

mkdir ARM/build/gcc-4.3.3
cd ARM/build/gcc-4.3.3
../../src/gcc-4.3.3/configure --target=arm-none-eabi --prefix=$MYTOOLS --enable-interwork --enable-multilib --enable-languages="c,c++" \
--with-newlib --with-headers=../../src/newlib-1.16.0/newlib/libc/include
make all-gcc install-gcc

A couple of new options appear here:

Now build Newlib using our new cross-compiler

mkdir ARM/build/newlib-1.17.0
cd ARM/build/newlib-1.17.0
../../src/newlib-1.17.0/configure --target=arm-none-eabi --prefix=$MYTOOLS --enable-interwork --enable-multilib
make all install

Now that we have our runtime libraries, go back and finish the GCC build:

cd ARM/build/gcc-4.3.3
make all install

Okay, now we can build GDB:

mkdir ARM/build/gdb-6.8
cd ARM/build/gdb-6.8
../../src/gdb-6.8/configure --target=arm-none-eabi --prefix=$MYTOOLS --enable-interwork --enable-multilib
make all install


That's it!  You should now have an operational ARM toolchain.