Blog for my various projects, experiments, and learnings

Building a Bare-Metal ARM GCC Toolchain from Source

The GCC toolchain is a nice way to get started with bare-metal ARM platforms because it is free, well-supported, and something that many C programmers are already familiar with. It is also constantly improving, and while most Linux distributions include a version of the arm-none-eabi GCC toolchain in their default package managers, those versions are sometimes old enough that I run into bugs with things like multilib/multiarch support.

So after trying and failing a few times to build and install this toolchain, I thought I would share what eventually worked for me. If you are building this on a system without much free disk space, this did take about 16GB of disk space when I ran it – but you shouldn’t need to keep more than ~500MB of that. I ended up building it on an ext3-formatted 32GB USB drive, and that seemed to work fine. You will probably run into errors if you try to run this on a FAT-formatted drive like a new USB stick, though, because the build process will run chmod and that will fail on a filesystem that doesn’t support file permissions. You might be able to make it work with an NTFS drive, but I digress.

Anyways, the first step is downloading the code, so let’s get started!

Step 1: Download the Source Code

The first step is to download the arm-none-eabi-gcc source code from ARM’s website – you want the “Source Invariant” version. If you are using a common architecture such as x86_64, you can also download a pre-built version of the latest release, but you probably want to build the thing yourself if you are reading this guide. If you want to make sure that the file you downloaded was not corrupted or tampered with, you can check it against the MD5 checksum listed under the file’s name on the download page:

> md5sum gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2
d6071d95064819d546fe06c49fb9d481 gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2

That looks like it matches as of the time of writing. The archive contains build scripts and code for the whole toolchain, so create a new directory to build the toolchain in – I’ll use ~/arm_gcc/ as an example. Once it finishes downloading, move the archive to that folder and extract it:

> mkdir ~/arm_gcc
> cd ~/arm_gcc
> mv [Your_Downloads_Folder]/gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2 .
> tar -xvf gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2

The file that I downloaded was called gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2, but yours will depend on where you are in time. The extracted archive will make a new directory with a similar name – take a look inside, and you’ll see a few scripts and a ‘how-to’ document alongside the source code:

> cd gcc-arm-none-eabi-8-2018-q4-major/
> ls release.txt How-to-build-toolchain.pdf license.txt readme.txt src

Step 2: Build the Toolchain

The How-to-build-toolchain.pdf file contains instructions for setting up and running the build – it’s almost as simple as installing the prerequisites and running a few scripts in sequence, but there are a few things worth calling out. First, read the ‘how-to-build’ document. It’s short, and if you read it you won’t go looking for a Makefile in the src/ directory like I did.

The prerequisites are easy to install; if you are using a Debian-based Linux distribution like Ubuntu, this command should work with the version of GCC that I wrote this guide for (don’t forget to use sudo or be root):

apt-get update
apt-get install build-essential autoconf autogen bison dejagnu flex flip gawk git gperf gzip nsis openssh-client p7zip-full perl python-dev libisl-dev scons tcl texinfo tofrodos wget zip texlive texlive-extra-utils libncurses5-dev

If you are building a newer version of the toolchain than the “2018-Q4” release, double-check the ‘how to build’ document to make sure those are the only dependencies that you need. And some of these packages might be fairly large, but I think you can probably omit the texlive packages if you tell the build system to skip creating manuals and documentation in the final step (mentioned below).

Once the dependencies are installed, proceed to step 1.3 in the ‘how-to-build’ document (titled, “Build GNU Tools for Arm Embedded Processors”). Note that I haven’t built the toolchain on Mac OSX, and it looks like there are some extra steps for that environment.

The first step after un-zipping the source files is to run the script, which extracts the source code for each part of the toolchain. It also downloads some supporting libraries, so you’ll need internet access for this step as well as the previous one:

./ --skip_steps=mingw32

The --skip_steps=mingw32 option tells the build system not to create a Windows-compatible toolchain. Since I only plan to run this on the Linux host it was built on, this option saves time and space. If you do need to build a Windows toolchain, I guess you can skip the ‘skip_steps’ step for all of these scripts.

Once the sources are extracted (the larger archives might take a little while to unpack), you can set up the build system and supporting libraries with:

./ --skip_steps=mingw32

This step will also take a little while as it runs through a ‘configure/make’ cycle for each dependency that it needs to build. Once it is done, you can build the toolchain itself. And while I haven’t tried this, it looks like you can skip building the manuals and documentation if you didn’t want to install the large texlive packages by passing in --skip_steps=mingw32,manual instead:

./ --skip_steps=mingw32

This will take even longer than the previous step – it can easily run for several hours (or even longer on a slow machine,) and in my case the terminal output froze towards the end of the process; I had to guess when it finished by checking that there were no more compiler/linker/etc processes running and that the size of the build folder stopped changing.

When the build does finish, you should find a directory called install-native/ in the same directory that you ran the build scripts in. That folder will contain the finished toolchain which we will install in the next step.

And if you want to backup the toolchain so you don’t need to re-build it later, there should also be a directory called pkg/ which contains two tarballs. One contains the same final build as the install-native/ directory, and the other contains the toolchain’s source code as it was generated for your platform.

Step 3: Install the Toolchain

It looks like the toolchain’s build contains four directories: bin/, lib/, share/, and arm-none-eabi/. I’m not sure why it creates the extra arm-none-eabi/ directory, and you might be able to adjust this by using common command-line options like --prefix during the build stage, but I didn’t look into that too much. It might bother you if you really like having a clean filesystem though, because the process I used to install the toolchain is embarrassingly simple – just copy everything into the /usr directory:

cp -R install-native/* /usr/
sudo ldconfig

You can check that the program was installed and view some basic information about its path settings with basic diagnostic commands like which arm-none-eabi-gcc and arm-none-eabi-gcc -print-search-dirs.

To uninstall the toolchain, you should be able to just remove the directories which you copied – in my case those were:


I also ended up with a few files under the lib/ directory, but that looks like an already-reported bug. It may cause conflicts with avr-gcc, but I’m one of those people who can’t see any point to using an AVR core these days; it seems like you pay more for less when there are options like MSP430s or PICs on the cheap/low-power/simple end and Cortex-M0s on the cheap/high-power end.


That should be all there is to it – after running ldconfig, you should be able to use the arm-none-eabi toolchain normally. In my case, building and installing an up-to-date version of the toolchain fixed an issue where GCC tried to link a soft-float math library for a hard-float build. I got the project to build by using the -mfloat-abi=softfp option, but actually running a floating-point operation still caused the chip to crash. With this fresh toolchain, I can build with -mfloat-abi=hard and my Cortex-M4F chip can calculate an arctangent 🙂

So maybe I was mis-configuring things, maybe I was using new configuration flags that the older toolchain didn’t recognize, maybe I forgot to install some library from the package manager, or maybe (against all probability) it was actually a compiler bug. But sometimes it makes more sense to just re-install the latest stable version of something instead of trying to muddle through a tricky issue which you can’t find much information about. Sure you can write a bug report, but if updating to a newer version fixes the bug, there’s probably not much point.

Anyways, happy compiling! And corrections are always welcome; like I said, I wrote this guide mostly because I messed the process up so many times before getting it to work, so…what does that tell you?

Comments (4):

  1. John Sok

    February 22, 2019 at 4:31 am

    Perfect!! This is just barely above my current level of knowledge (for now), very helpful, thanks ! What direction are you thinking following this? Bottom => Up or Top => Down ? More project applications ? Good application topics indeed. Thanks..

  2. Jorgen Ordonez

    September 6, 2020 at 4:23 pm

    Where can I find the How-to-build-toolchain.pdf file.

    • Jorgen Ordonez

      September 6, 2020 at 4:34 pm

      I downloaded the wrong file.

      • Vivonomicon

        September 10, 2020 at 11:04 pm

        It should be contained in the source code archive that you download from ARM’s developer site; in this article that was “gcc-arm-none-eabi-8-2018-q4-major-src.tar.bz2”, but there’s probably a newer version out now.


Leave a Reply

Your email address will not be published. Required fields are marked *