I do a lot with embedded systems. Each new platform needs a compiler. Normally gcc is used for this, being a pretty good and very free compiler; unfortunately, building it for a particular target is annoyingly and needlessly hard.
(Rant follows: stupidly hard. The installation instructions are difficult to find and lousy, there are usually bugs that cause it to fail to build out of the box, and there's no assistance available.)
Here's a brief walk through rebuilding gcc to target an embedded platform with an ARM processor.
Firstly, you need a copy of both GNU binutils (which contains an assembler, linker, etc) and GNU gcc itself. You can get them here.
I recommend 2.19.1, which is known to work.
I recommend 4.3.3, which is known to work. Get the gcc-core version, which just contains the C compiler, and not things like Fortran or Ada.
(Important note: as of writing this article, the automatic mirror selector that I link to above would occasionally send me to a compromised web site. Idiots. If your web browser complains about this, hit BACK and try again --- you'll get a proper mirror.)
The next thing you need to do is to decide on the target you want to build
for. gcc uses, of course, a needlessly complex naming scheme for targets that
distinguishes between all the various slightly different ABIs. For embedded
systems, this is all irrelevant. All you need to know is that the target name
is usually processor-format
. Our platform is going to be
arm-elf
. The following processors are available in gcc 4.3.3:
alpha
arc
arm
avr
bfin
cris
crx
fr30
frv
h8300
i386
ia64
iq2000
m32c
m32r
m68hc11
m68k
mcore
mips
mmix
mn10300
mt
pa
pdp11
rs6000
s390
score
sh
sparc
spu
stormy16
v850
vax
xtensa
format
is nearly always going to be elf
, although
occasionally you might want coff
.
Now the prerequisites. Apart from the usual toolchain and development sets for your platform,
Right, now you're ready to build them. First, decompress them. (Change the version numbers in the following examples to match whatever you downloaded.)
$ cd /tmp $ mkdir build $ cd build $ tar xjf binutils-2.19.1.tar.bz2 $ tar xjf gcc-core-4.3.3.tar.bz2
Now here's the cunning trick without which you are lost: both binutils and gcc are designed to be built from a different directory. gcc, in particular, will not build if you try to do it from its own directory --- and if you try it will subtly poison its own source and fail to build ever again. The documentation does not mention this.
First, binutils:
$ mkdir binutils-obj $ cd binutils-obj $ ../binutils-2.19.1/configure --target=arm-elf --prefix=/usr/local [output] $ make CFLAGS="-Os -w" [output] $ sudo make install $ cd ..
Note the argument to --prefix
--- this indicates where you
want to install everything. /usr/local
is common. If you don't
have sudo privileges you'll need to install into your home directory;
$HOME
is perfectly acceptable, but be aware that gcc tends to
spew stuff all over the place.
What's the CFLAGS setting for? Well, the binutils authors decided to use the compiler option that causes warnings to be treated as errors. For development, this is a good idea, because it forces people to fix warnings. For release code, it's a really bad idea, because different compilers emit different warnings. Newer versions of gcc have added more warnings, and so binutils won't compile out of the box on it. Changing CFLAGS like this works around the problem.
Hopefully now binutils should be compiled and installed. Let's move on to gcc.
$ mkdir gcc-obj $ cd gcc-obj $ ../gcc-4.3.3/configure --target=arm-elf --prefix=/usr/local --enable-multilib --disable-libssp [output] $ make CFLAGS="-Os -w" [output] $ make install $ cd ..
Pretty much the same procedure as for binutils, and deceptively simple-looking...
--enable-multilib
tells gcc to build versions of its run-time
library for all different configurations of the target. In particular, for ARM
this means you'll get a libgcc for both ARM and Thumb. For embedded use, this
is what you want.
--disable-libssp
disables the stack-smashing protection
library. This is because it doesn't build.
And now, if all that worked... you should be ready to go. Test it:
$ cat > test.c int foo(void) { return 42; } ^D $ arm-elf-gcc -Os -S test.c $ cat test.s .file "test.c" .text .align 2 .global foo .type foo, %function foo: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. mov r0, #42 bx lr .size foo, .-foo .ident "GCC: (GNU) 4.3.3"
And if it didn't work... well, sorry. Probably you've hit one of the known fails-to-build bugs; try the error message in Google and with luck you'll get a workaround. The above recipe works for me, most of the time, and so I'm sticking with it. Why the gcc team don't clean up their act and produce something that works a bit more reliably I don't know.