Note: This post serves mainly as a reminder to myself. I did not figure out everything myself and got the original instructions from here (many thanks to Adam Kunen). The steps here aren’t exactly the same, but they’re mostly similar. His posts also contain some explanations for the various configure options as well as a short explanation on the triplet (ie. “arm-none-eabi”).
The goal: To build the GCC toolchain for ARM suitable for bare-metal work, complete with gdb and libc (newlib). At the end of the day I used this to compile the LwIP sample projects (both “standalone” and FreeRTOS versions) for an STM32F4 evaluation board.
These are the versions of the various components I used:
- Host: Ubuntu 12.04 (actually Lubuntu)
- GNU GCC 4.7.1
- GNU GDB 7.4
- GNU binutils 2.22
- newlib 1.20.0
There should be no issues using newer versions of these components.
In this tutorial I’m going to install the tool-chain at ~/arm-none-eabi/ with with the sources in ~/arm-none-eabi-src. Do change this path if you prefer a different location. (On my own machine, I placed it in /opt/arm-none-eabi)
Update (6/9/2013): Some of the configure commands include “–with-cpu=cortex-m4”. This is because I was building for a ARM Cortex-M4 MCU. You should replace this with your target architecture. I had problems with an earlier build when I didn’t add this option in. It turns out that Cortex-M processors are picky about word alignment, and if you don’t configure this in before you build newlib and gcc, the libraries may not respect the word alignments and you may end up with hard faults.
Ok, first we create the directory skeleton:
cd mkdir arm-none-eabi arm-none-eabi-src cd arm-none-eabi mkdir src build
Now, download the the packages and extract them:
cd ~/arm-none-eabi-src/src wget ftp://ftp.gnu.org/gnu/gcc/gcc-4.7.1/gcc-4.7.1.tar.bz2 wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2 wget ftp://ftp.gnu.org/gnu/gdb/gdb-7.4.tar.bz2 wget ftp://sources.redhat.com/pub/newlib/newlib-1.20.0.tar.gz tar -xf gcc-4.7.1.tar.bz2 tar -xf binutils-2.22.tar.bz2 tar -xf gdb-7.4.tar.bz2 tar -xf newlib-1.20.0.tar.gz
Build binutils first:
cd ~/arm-none-eabi-src/build mkdir binutils-2.22 cd binutils-2.22 ../../binutils-2.22/configure --target=arm-none-eabi \ --prefix=~/arm-none-eabi --with-cpu=cortex-m4 \ --with-no-thumb-interwork --with-mode=thumb make all install export PATH="$PATH:~/arm-none-eabi/bin"
At this point you could also put the path “~/arm-none-eabi/bin” into your .bashrc file if you want.
After this, we will do the first part in building gcc.
Note: gcc relies on three bignum libraries: mpfr, mpc, and gmp. You should download the source code for those three libraries, rename them to mpft, mpc, and gmp respectively, and move them inside the gcc source tree. Do not compile these libraries separately.
The steps to build the first stage are:
cd ~/arm-none-eabi-src/build mkdir gcc-4.7.1 cd gcc-4.7.1 ../../src/gcc-4.7.1/configure --target=arm-none-eabi \ --prefix=~/arm-none-eabi ---with-cpu=cortex-m4 \ --with-mode=thumb --disable-multilib \ --with-no-thumb-interwork \ --enable-languages="c,c++" --with-newlib \ --with-headers=../../src/newlib-1.20.0/newlib/libc/include \ --with-system-zlib make all-gcc install-gcc
Here I deviate from Kunen’s tutorial a little. I could not get gcc 4.7.1 to compile without the “–with-system-zlib” flag. (The make process fails somewhere when it tries to do link tests. If anyone can explain why or knows why using the system zlib is disadvantageous, do leave a comment and let me know.)
Okay, now let’s build our newlib libc with our freshly compiled gcc cross compiler:
cd ~/arm-none-eabi-src/build mkdir newlib-1.20.0 cd newlib-1.20.0 ../../src/newlib-1.20.0/configure --target=arm-none-eabi \ --prefix=~/arm-none-eabi --disable-multilib \ --disable-newlib-supplied-syscalls make all install
Here there’s another configuration option which I added which Kunen doesn’t: –disable-newlib-supplied-syscalls. The reason is I want to supply the system call stubs myself so I can have a potentially fully functional stdin, stdout, etc. Also, if you’re using an RTOS, here is where you could make standard libc malloc work with your RTOS’ memory management. Even if you aren’t using an RTOS, supplying appropriate stubs will still give you a fully functional libc.
The catch is you’ll always need supply the system call stubs if you use printf, and friends, or malloc and friends. You can read more about it here and here.
Now, we can complete the gcc build:
cd ~/arm-none-eabi-src/build/gcc-4.7.1 make all install
And the final piece, gdb:
cd ~/arm-none-eabi-src/build mkdir gdb-7.4 cd gdb-7.4 ../../src/gdb-7.4/configure --target=arm-none-eabi \ --prefix=~/arm-none-eabi make all install
Alright! Now put
in your .bashrc or /etc/environment (if you haven’t already) and you have a fully functional ARM tool-chain suitable for bare-metal work.