Building an AVR toolchain on OS X

Fri, 09 Jul 2010 19:49:17 +0000
tech avr arduino gcc

I’ve recently got myself a couple of Arduino Duemilanove boards from Little Bird Electronics. Now the Arduino is a pretty cool bit of kit, and it comes with a great integrated development environment, which makes writing simple little programs an snap. Of course, I’m too much of an old curmudgeon to want to use and IDE and some fancy-schmancy new language, I want make, I want emacs, I want gcc. So I embarked on the task of building a cross-compiler for the AVR board, that will work on OS X.

Photo of my Arduino board

Now, my ideal solution for this would have been to create a package for Homebrew, my current favourite package manager for OS X. Unfortunately, that just isn’t going to happen right now. GCC toolchains pretty much insist in putting things in $prefix/$target. So, in a standard homebrew install, that would mean I need a directory /usr/local/avr, unfortunately, Homebrew insists your package only dump things in etc, bin, sbin, include, share or lib. Now, after wasting a bunch of time first fighting GCC’s autogoat build system to try and convince it to conform to Homebrew’s idea of a filesystem hierarchy, and then a whole other bunch of time trying to learn Ruby and convince Homebrew that other directories should be allowed, I took the corwads way out and decided /opt/toolchains is a perfectly respectable place for my cross-compilers to live.

And so, the cross compiler dance begins. We start with binutils, and as the code dictates, we start by trying with the latest version, which at time of writing is 2.20.1.

Of course, building a toolchain for a non-x86 based architecture wouldn’t be the same if you didn’t need to patch the source. The patches for the avr are mostly minimal; adding some extra device definitions, for devices you probably don’t have anyway. If you miss this step, expect some pain when you try to compile avr-libc. I got my patches from the FreeBSD AVR binutils patchset. I try to avoid patches I don’t need so have only applied the patch-newdevices patch. If things break for you, you might want to try the other patches as well.

  1. $ mkdir avr-toolchain-build
  2. $ cd avr-toolchain-build
  3. $ wget http://ftp.gnu.org/gnu/binutils/binutils-2.20.1.tar.bz2
  4. $ wget "http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/ports/devel/avr-binutils/files/patch-newdevices?rev=1.16;content-type=text%2Fplain" -O patch-newdevices
  5. $ tar jxf binutils-2.20.1.tar.bz2
  6. $ cd binutils-2.20.1
  7. $ patch -p0 < ../patch-newdevices
  8. $ cd ..
  9. $ mkdir binutils-build
  10. $ cd binutils-build
  11. $ ../binutils-2.20.1/configure --target=avr --prefix=/opt/toolchains/ --disable-werror
  12. $ make -j2
  13. $ make install
  14. $ cd ../

Fairly simple, the only gotcha is the --disable-werror, seems that binutils added the -Werror flag to the build, good move!, unfortunately, seems that the code isn’t warning free, so things barf (bad move!), but it comes with a free flag to disable the error... that’s good.

So, now we move on to GCC. Now, since I’m really only interested in compiling C code, (remember the bit about being a curmudgeon, none of this fancy C++ stuff for more, no siree!), we can just grab GCC’s core package.

Now GCC has some dependencies these days, so you need to get gmp, mpc and mpfr installed somehow. I suggest using Homwbrew. In fact it was this step with my old Mac Ports setup that forced me to switch to Homebrew; too many weird library conflicts with iconv between the OS X version and the ports version; but hey, you mileage may vary! (Note: make sure you have the latest version of Homebrew that includes my fix for building mpfr).

And of course, just like binutils, you need some patches as well. Unfortunately things here aren’t as easy. There doesn’t appear to be any semi-official patch for new devices for gcc 4.5.0! So, based on this patch, I managed to hack something together. The formats have changed a little, so I’m not 100% confident that it works, if you are actually trying to use one of the new devices in this patch, be a little skeptical, and double-check my patch. If you are using an existing supported AVR like the atmega328p, then the patch should work fine (well, it works for me).

  1. $ brew install gmp libmpc mpfr
  2. $ wget http://ftp.gnu.org/gnu/gcc/gcc-4.5.0/gcc-core-4.5.0.tar.bz2
  3. $ wget http://benno.id.au/drop/patch-gcc-4.5.0-avr-new-devices
  4. $ tar jxf gcc-core-4.5.0.tar.bz2
  5. $ cd gcc-core-4.5.0
  6. $ patch -p1 < ../patch-gcc-4.5.0-avr-new-devices
  7. $ mkdir gcc-build
  8. $ cd gcc-build
  9. $ ../gcc-4.5.0/configure --target=avr --prefix=/opt/toolchains
  10. $ make -j2
  11. $ make install
  12. $ cd ..

So, the final piece to complete the toolchain is getting a C library. You almost certainly want AVR Libc, or you can be really hard-core and go without a C library at all, your call.

  1. $ wget http://mirror.veriportal.com/savannah/avr-libc/avr-libc-1.7.0.tar.bz2
  2. $ tar jxf avr-libc-1.7.0.tar.bz2
  3. $ mkdir avr-libc-build
  4. $ cd avr-libc-build
  5. $ ../avr-libc-1.7.0/configure --prefix=/opt/toolchains --host=avr --build=
  6. $ make
  7. $ make install

This should work with out any problems, however, if you messed up the new devices patches when building GCC and binutils, you might get errors at this point.

So, now we have a working GCC toolchain for the AVR we can start programming. Of course, you really want to have a good reason to do things this way, otherwise I really recommend just using the Arduino development environment..

Next time I’ll be looking at getting some example C programs running on the Arduino.

References