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
export PATH="$PATH:~/arm-none-eabi/bin"
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.
Execuse me. When i try to Build binutils, it says
”
zhuoyuzhen@ubuntu:~/arm-none-eabi-src/build/binutils-2.22$ make all install
make: *** No rule to make target `all’. Stop.
zhuoyuzhen@ubuntu:~/arm-none-eabi-src/build/binutils-2.22$ export PATH=”$PATH:~/arm-none-eabi/bin”^C
”
can you help me?
Did the previous step (the configure) complete successfully?
I am having the same problem with zlib. This bug report looks promising: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45174
Nice article, thank you. Just a quick note: you assume that some libraries are already installed (namely GMP, MPFR and MPC). On Linux systems, they can be installed using the standard package manager. On FreeBSD systems, you need the additional options “–with-mpc=/usr/local –with-mpfr=/usr/local –with-gmp=/usr/local” due to the layout of the system – beside using gmake instead of make. Just in case another FreeBSD fan hits this page 😉
That’s quite helpful, thanks for taking the time to comment.
remove the –enable-multilib option and you will not have to specify the –with-system-zlib option. Since multilib is enabled by default, this will not change the actual build process other than to solve the problem you saw. Something about the parsing of the –enable-multilib breaks things so simply not putting on the command line resolves it.
See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43328
Thanks! I’ll try that next time I compile them.
I savor, cause I discovered just what I used to be having a look for. You’ve ended my four day lengthy hunt! God Bless you man. Have a nice day. Bye