Friday, February 10, 2012

ARM-GCC Toolchain How-To

Once in a wile I have to compile the GCC Toolchain (Binutils, GCC, GDB) for a new platform, either because I want to have some new feature, or due to a bug correction, and also after installing a new operating system. As I don't do this often, I always have trouble remembering some steps. That's why I'm posting it here.

Before you go any further I want to point out that we will not cover here how to compile the C++ compiler (g++) - this will require the compilation of a runtime library, and is a little more challenging. Only the C language will be supported, and no C library (libc) will be generated as well. This will be, for sure, a limiting factor for almost everybody except those who are developing system software.

This tutorial will explain how to compile a cross GCC toolchain for ARM processors on a Ubuntu 10.04 LST host machine. It will probably work fine on other Ubuntu releases as well, but please be aware that there is a good chance of these procedures failing if you intend to use a different set of OS and source code (other versions of GCC, binutils or GDB).
So there we go. First of all, let's get the packages:

Downloading the source code

cd /tmp

Now lets prepare the environment to compile and install. I usually install the tools in a subdirectory over the /opt directory. In this case we will be installing in the /opt/arm-none-eabi directory. The binaries (programs, gcc, gdb and such) will be located in the /opt/arm-none-eabi/bin
subdirectory and will be prefixed by "arm-none-eabi" (arm-none-eabi-as,, arm-none-eabi-gcc,...) .

Installing development libraries

sudo apt-get install libmpfr-dev libgmp3-dev libmpc-dev
sudo apt-get install libz-dev

The first line install the MPFR, GMP and MPC development libraries, which are required to compile GCC since version 4.3.
The last line adds the zlib development package, as you may get an error when compiling the zlib provided with GCC.

Creating a build tree

Assuming that all the source code files where downloaded in the /tmp directory, ad we will compile in our home directory:

mkdir gcc-toolchain
cd gcc-toolchain
bzip2 -dc /tmp/binutils-2.22.tar.bz2 | tar -vxf -
bzip2 -dc /tmp/gcc-core-4.6.2.tar.bz2 | tar -vxf -
bzip2 -dc /tmp/gdb-7.4.tar.bz2 | tar -vxf -
mkdir arm-none-eabi
cd arm-none-eabi
mkdir binutils-2.22
mkdir gcc-4.6.2
mkdir gdb-7.4
export PATH=/opt/arm-none-eabi/bin:/bin:/usr/bin

The last line will set-up the PATH for the compilation. Notice that the first entry (/opt/arm-none-eabi/bin) does not exist yet, but it will be crated when installing the binutils and will be necessary for compiling the GCC.

Compiling GNU binutils

First let's do the basics: assembler, archiver, linker and object files utilities.

cd binutils-2.22
../../binutils-2.22/configure --prefix=/opt/arm-none-eabi --target=arm-none-eabi --disable-nls
make -j 8
sudo make install
cd ..

Compiling GCC

If everything went well, we are good to compile the cross-compiler. To make sure check the /opt/arm-none-eabi/bin directory, all the "arm-none-*" family of binutils must be there.

cd gcc-4.6.2
../../gcc-4.6.2/configure --prefix=/opt/arm-none-eabi --target=arm-none-eabi --disable-nls --disable-libssp --disable-zlib --enable-languages="c"
make -j 8
sudo make install
cd ..

GCC is up, let's see if it's running:
$ arm-none-eabi-gcc
arm-none-eabi-gcc: fatal error: no input files
compilation terminated.

If you got that message your compiler is fine.

Compiling GDB
As an optional step, you can compile the GDB. This will allows you, with the right tool, to remotely debug your embedded application.

cd gdb-7.4
../../gdb-7.4/configure --prefix=/opt/arm-none-eabi --target=arm-none-eabi --disable-nls
make -j 8
sudo make install
cd ..

Update your PATH

You have to include the newly created toolchain bin directory into your PATH environment. Edit .bashrc, in your home directory, and add the following line:

export PATH=$PATH:/opt/arm-none-eabi/bin

For the changes to take effect you will have to restart the terminal or source your .bashrc with:

$ source ~.bashrc

/!\ Attention: the -j 8 parameter in the make line, allows for parallel building, which will speed-up the compilation process quite a lot. But, from my experience, I recommend not to use -j alone, as this may result in a non-responsive computer and sometimes the compilation itself or some other applications may crash. For that reason always set the number of tasks to match the number of cores or threads your machine has. For example I'm using a Intel Core 7 with 4 cores and 2 threads per core (Intel Hyper Threading), so I use -j 8.

Other tips


In some operating systems the GMP and MPFR libraries required to compile the GCC are outdate, to solve this we download source code and tell the configure script where to find them:

bzip2 -dc /tmp/gmp-4.3.2.tar.bz2 | tar -vxf -
bzip2 -dc /tmp/mpfr-3.1.0.tar.bz2 | tar -vxf -


Depending on what your projects are you most probably will need a C library. NewLib is a good option and you can compile it along with GCC.
Quoting from the Newlib's website: "Newlib is a C library intended for use on embedded systems. It is a conglomeration of several library parts, all under free software licenses that make them easily usable on embedded products."

cd / tmp
cd ~/gcc-toolchain
gzip -dc /tmp/newlib-1.20.0.tar.gz | tar -vxf -

In the GCC compilation step you need to inform you want to use the NewLib as your default C library: --with-newlib
 As the NewLib provides support for building the run-time elements of C++ we can enable the C++ in the GCC compilation as well: --enable-languages="c,c++"

cd gcc-4.6.2
../../gcc-4.6.2/configure --prefix=/opt/arm-none-eabi --target=arm-none-eabi --disable-nls --disable-libssp --disable-zlib --enable-languages="c,c++" --with-newlib --with-headers=../../newlib-1.20.0/newlib/libc/include 
make -j 8
sudo make install
cd ..

Now you can compile the library:

mkdir newlib-1.20.0
cd newlib-1.20.0
../../newlib-1.20.0/configure --prefix=/opt/arm-none-eabi --target=arm-none-eabi
make -j 8
sudo make install
cd ..

NewLib Notes

If you want to use the NewLib to do I/O, dynamic memory, file operations and some other other functions, you will need to create a OS adaptation layer. I may write a tutorial on the subject one of these days.


I've tried the compilation sequence in my netbook running Lubuntu 12.04 and it worked like a charm. If you have a resource limited, old computer, or simply don't swallow the new Gnome/Ubuntu interface I really recommend LUbuntu:

No comments:

Post a Comment