Cross-compiling for the Nokia 770

The Nokia 770 has limited processing power: a 220MHz ARM-based CPU, 64MB RAM, and 128MB of non-volative storage (flash). Using the Cyclone compiler on such a limited system would be painful, maybe impossible. Instead we’ll use a special Cyclone compiler on a more powerful machine, and compile the programs there before transferring them to the 770 to run. The process is about the same regardless of whether you want to compile for the 770, the Nintendo DS, the iPod, or even more limited platforms.

The hardest part of this is getting a cross-compiling gcc. Fortunately, Nokia is using standard open source tools for their development environment, and binary distributions and good documentation are easily available.

Installing the cross-compiler

The basic development environment is Scratchbox. Scratchbox is a set of cross-compilers and emulators that let you simulate working on one processor architecture, while in fact running on a completely different architecture. In our case, we’ll be able to compile and execute ARM code while running on an x86 machine.

You can install Scratchbox and Maemo (the Nokia-specific devkit) using these instructions. Due to our particular needs, we’ll use a different set of packages than those mentioned in those instructions. Here’s the complete list of tarballs that I used:

scratchbox-core-1.0.4-i386.tar.gz
scratchbox-libs-1.0.3-i386.tar.gz
scratchbox-toolchain-arm-gcc3.4-glibc2.3-1.0.2-i386.tar.gz
scratchbox-toolchain-host-gcc-1.0.5-i386.tar.gz

The tarballs are available here. I didn’t bother to install any Scratchbox devkits, or the Maemo SDK, as these aren’t necessary to cross compile simple command-line applications.

After following the instructions you should have a working Scratchbox with ARM target. This means that when you are logged in to the Scratchbox in the ARM target, you are running ARM binaries via emulation. We also need a HOST target, where you can run x86 binaries natively. The setup for HOST is about the same as for ARM:

Using sb-menu, choose “Setup” to create the HOST target.

  1. Name the target HOST
  2. Select host-gcc compiler
  3. Select debian and perl devkits
  4. Select “none” for CPU transparency method
  5. Select “no” for installing files
  6. Select “yes” for selecting the target
  7. Exit sb-menu.

You should now be running inside the HOST target in Scratchbox.

Installing Cyclone

Now, on to Cyclone. Download the distribution; you’ll need to use the CVS version to be sure it works with Maemo. Place the distribution in your Scratchbox home directory and cd to the toplevel directory. Configure and build:

./configure --target=arm-maemo-elf
make
make install

Now, create the canonical first program:

cat > hello.cyc <<ZZZ
#include <stdio.h>
int main () { printf("Hello, world!\n"); return 0; }
ZZZ

Compile it with

cyclone hello.cyc -nogc -b arm-maemo-elf

Transfer the resulting a.out to your 770. On most Linux systems you can simply plug in the 770 over USB and drag the file over; this will put the program on the memory card. Be sure to move the program off of the memory card to your home directory, because it won’t run from the memory card.

Finally, run it from an xterm:

Hello world on a 770

Under the covers

A couple of details. When you did

./configure --target=arm-maemo-elf

you set Cyclone up so that both a native (x86) compiler and a cross (ARM) compiler would be built. Because Cyclone uses gcc and associated tools as its back end, the difference between the two is just that the ARM version invokes a cross gcc toolchain instead of the native toolchain. If you examine the generated Makefile.inc, you’ll see these lines:

TARGET_CC=/scratchbox/compilers/arm-linux-gcc3.4.cs-glibc2.3/bin/arm-linux-gcc
TARGET_CFLAGS=
TARGET_RANLIB=/scratchbox/compilers/arm-linux-gcc3.4.cs-glibc2.3/bin/arm-linux-ranlib
TARGET_AR=/scratchbox/compilers/arm-linux-gcc3.4.cs-glibc2.3/bin/arm-linux-ar

If you are cross-compiling for a different architecture, or you have gotten a different version of the Scratchbox toolchains, you will need to adjust these variables.

A second detail: note that when we compiled hello.cyc, we used the -nogc flag. This means that the garbage collector will not be linked in. In fact, the normal build process will not cross-compile the garbage collector at all, so the compile will fail if you do not use -nogc.

It is possible to cross-compile the garbage collector, but I don’t have much experience with it. If you are using Scratchbox, then you can compile the garbage collector in the ARM target, and hello.cyc will run on the 770 with the garbage collector linked in. It does not run in the ARM target itself, though.

To cross-compile the garbage collector in the ARM target, do this:

cd gc
./configure --enable-threads=no --enable-shared=no --enable-cplusplus=no
make
mv .libs/libgc.a /usr/local/lib/cyclone/cyc-lib/arm-maemo-elf/gc.a

Now you should be able to compile programs to use the garbage collector as usual, by leaving off the -nogc flag.

15 May 2006 by trevor #