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.
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.
$ mkdir avr-toolchain-build$ cd avr-toolchain-build$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.20.1.tar.bz2$ 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$ tar jxf binutils-2.20.1.tar.bz2$ cd binutils-2.20.1$ patch -p0 < ../patch-newdevices$ cd ..$ mkdir binutils-build$ cd binutils-build$ ../binutils-2.20.1/configure --target=avr --prefix=/opt/toolchains/ --disable-werror$ make -j2$ make install$ 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).
$ brew install gmp libmpc mpfr$ wget http://ftp.gnu.org/gnu/gcc/gcc-4.5.0/gcc-core-4.5.0.tar.bz2$ wget http://benno.id.au/drop/patch-gcc-4.5.0-avr-new-devices$ tar jxf gcc-core-4.5.0.tar.bz2$ cd gcc-core-4.5.0$ patch -p1 < ../patch-gcc-4.5.0-avr-new-devices$ mkdir gcc-build$ cd gcc-build$ ../gcc-4.5.0/configure --target=avr --prefix=/opt/toolchains$ make -j2$ make install$ 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.
$ wget http://mirror.veriportal.com/savannah/avr-libc/avr-libc-1.7.0.tar.bz2$ tar jxf avr-libc-1.7.0.tar.bz2$ mkdir avr-libc-build
$ cd avr-libc-build
$ ../avr-libc-1.7.0/configure --prefix=/opt/toolchains --host=avr --build=$ make$ make installThis 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.