March 20, 2013

Cross-compiling applications for ARM

Recently I had to develop a project for an ARM device and the first big problem I found during the development process was cross-compiling. There are some tutorials in Google, but most of them are old or simply won't run. Other tutorials suggest the use of big projects like Angstrom, Yocto Project or SHR.

While all those projects deserve my kudos, I really don't want to use any of those projects because
  • I don't want to waste time and energy setting up something that big 
  • It's not as flexible as I wish
  • Neither of those projects seem to have up-to-date packages for the device I'm working for
That's why I spent some time reading docs and I finally came up with (IMHO elegant) solution to my problem. ScratchBox2!

It's a shame that the README is the best doc you'll find inside the project, but luckily I was able to get everything working on a trial and error basis, searching in Google and bugging annoying stalking people in IRC. My sincere apologies to all of you! Your patience is making this post possible :)

First of all, you'll need a few things:
  • Basic developer tools (gcc, make, etc...)
  • QEMU
  • Git (and basic knowledge about how to use it, mainly how to clone repositories and switch to branches) or a distro that already packages sb2
  • A clean system (you don't want something broken in your system messing up with the whole process, so, if you know there's something fishy with your system fix it before going on!)
  • Patience
First clone sb2 and switch to the latest stable branch/release (or use the really latest revision if you're brave enough). If you're on a distro that packages sb2, install it with your package manager. It shouldn't matter either way.

Note: I'm on Arch x86_64 and I got sb2 via my package manager.

Now you need to get buildroot, just download it somewhere and untar it. Once untared, go to that directory and run make menuconfig

You should see something like this:

Now you should change what you need for your device. I'm going to set mine to little endian ARM architecture, generic arm variant.
I suggest you not changing anything in Build options unless you know what you're doing. In Toolchain maybe you'd like to change some of the options. I changed the Toolchain type to External toolchain and then I selected Sourcery CodeBench ARM.
But as I said, maybe you have some specific needs so adjust buildroot to your needs.

Once you're done you should be looking at something like this:

I didn't changed anything in System configuration nor Package Selection, but maybe you'd like to change something (busybox version, add/remove applications, etc) so check all the options.

You'll probably want to select something in Filesystem images as that's what you'll use for your device's rootfs. Anyways, this post is about cross-compiling, so I'll try to stay on topic.

Check the remaining options and once you're done move to the Exit option. You'll be prompted to store the changes you just did, so save them. Now run make and buildroot should start downloading and building everything you selected.

The process will take more or less according to your internet connection and your CPU speed. On my i7-3820 and my 950KB/s connection it took around 2 minutes.

Once done you'll like to see what's inside the output/images and output/target folders. 

The first one contains the real rootfs that you'll probably want to use with your device while the second one contains a nearly-usable rootfs. The main difference between the files from the first folder and the second folder is that the rootfs in the first folder isn't untared and completely usable. This is done because buildroot doesn't run with root privileges, hence it's able to create some special files only inside a tared file.

As I said, I'm trying to stay on topic, but as you can see both things (cross-compiling and deploying) are related.

The output/target folder is the one you'll be using with sb2, so go to that folder. You also need to know where is qemu's binary that you'll be using for your device and the toolchain that buildroot prepared for you, so look for them.

This is how it should be looking (note that paths can change depending on what toolchain you selected):

You need to use sb2-init to create a session with which you'll be compiling.
Also, as you can see I'm inside output/target and I'm using readlink because sb2 needs absolute paths.

If everything is ok you'll see a wonderful message saying: sb2-init completed successfully, have fun!

I'm not sure about this, but sometimes sb2 gives false hopes, as in, it didn't actually setup your session but it says it did, so check the last ~20 lines for any errors, just to be sure.

From now on, unless you change sb2's session, every command prepended with sb2 will run with your device's configuration inside the toolchain buildroot made for you!

I'll make another post about how to cross-compile everything from little Hello World examples to huge projects with tons of dependencies, so just stay tuned :)