Using Debian Multiarch for cross-compiling

I’ve recently acquired a [Raspberry Pi](http://www.raspberrypi.org/), and was considering using it for SNES
emulation. However, as it turns out that [Zsnes](http://www.zsnes.com/) is
x86-only, and that [Snes9x](http://www.snes9x.com/) got kicked out of Debian a
while back for having an annoying “no-commercial use”
[license](http://en.wikipedia.org/wiki/Snes9x#License), so we’re into the
compile-it-yourself options. As Snes9x is a configure/makefile-type project, I
should in theory be able to just compile in on the Pi directly, but then we hit
the problem that it hasn’t got enough RAM to be able to do all the compiling…
fine, fine, I’ll go back into the messy world of cross-compiling.

Actually, it turns out that things are in a good place these days if you’re
running a recent Debian system. First off, follow the [Emdebian install
instructions](http://wiki.debian.org/EmdebianToolchain#Get_the_binaries) and get
the armel compiler mentioned in the example. Snes9x needs bits of the X
libraries and other things, so if you’re feeling sensible then just use xapt and
dpkg-cross (also [on the Emdebian
page](http://wiki.debian.org/EmdebianToolchain#Get_all_the_libraries_you_need))
to get the packages you need.

xapt/dpkg-cross have a couple of problems though

– No aptitude or other tools integration. xapt wraps around apt, so you’ve at
least got that.
– It needs to install new copies of *everything*, even if they’re
arch-independent.

These are minor issues, and I probably should have picked that option over the
problems I had later on, but they were enough to persuade me away from it. Also
in theory, I could have just gone with using
[Qemu](http://wiki.qemu.org/Main_Page) and build the package on a pseudo-Pi but
[that also appears to have
issues](http://www.raspberrypi.org/phpBB3/viewtopic.php?f=2&t=3149) and my
little netbook would probably start screaming.

Instead, I went with something completely different: *Multiarch*. I’d been hearing
about this for a while but this is the first time I’ve actually used it. To
quote the [HOWTO](http://wiki.debian.org/Multiarch/HOWTO):

Multiarch lets you install packages from multiple architectures on the same
machine. This is useful in various ways, but the most common is installing
both 64 and 32-bit software on the same machine and having dependencies
correctly resolved automatically.

This is an upgrade slowly working it’s way through the Debian package
repositories, as it requires some changes to packaging. More specifically, in
order to have the multiple architecture packages not clash,
architecture-specific files now get [installed in architecture-specific
paths](https://wiki.ubuntu.com/MultiarchSpec#Filesystem_layout). In addition,
packages that can supply cross-architecture dependencies (i.e. removing the
problem noted before of having to install multiple copies of
architecture-independant packages), need to add a [Multi-Arch
field](https://wiki.ubuntu.com/MultiarchSpec#Binary_package_control_fields) to
note this.

Given all of that, you’re going to need a few bits of very up-to-date packages, as
this is still pretty bleeding-edge stuff. libc6-dev should be [at least
2.13-33](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666760), dpkg at least
[1.16.2](http://wiki.debian.org/Multiarch/HOWTO#Availability), and apt [at least
0.8.13, but ideally 0.9.4+](http://wiki.debian.org/Multiarch/HOWTO#Availability). If
you’re an Aptitude user, [you’ll need
0.6.6-1](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=651748) which
apparently is causing
[lots](http://askubuntu.com/questions/106203/why-do-some-packages-conflict-with-themselves)
[of problems](https://bugs.launchpad.net/ubuntu/+source/aptitude/+bug/831768)
for Ubuntu users right now…

After that for snes9x, I can do the following:

1. Add the armel architecture to dpkg

> dpkg –add-architecture armel

and update your package sources

> apt-get update

This may well fail if you’re using any 3rd party archives that are i386 specific
(or amd64 specific, or whatever other arch you’re on) e.g. Opera. If so, then
you’re going to need to add a “[arch=i386]” after the “deb” bit to make those
work again, i.e.

> deb http://deb.opera.com/opera/ stable non-free

becomes

> deb [arch=i386] http://deb.opera.com/opera/ stable non-free

as otherwise the default assumption is that all your existing sources are
suitable for all your architectures (both i386 and armel now!), and they’ll
break if that’s not true.

2. [Get the source of the last Debian version of snes9x](http://packages.debian.org/source/squeeze/snes9x)
3. Use
[dh-builddep-metapackage](https://www.lshift.net/blog/2010/04/12/debian-build-depends-metapackages)
to make sure we get the right set of build dependencies

> dh-builddep-metapackage -b -w -aarmel

and then install the resulting .deb. If it hadn’t been kicked out of Debian,
then

> aptitude build-dep snes9x:armel

would also work, but not any more. Now, one of the interesting problems with
Multiarch is that anything marked “Multiarch: same” will conflict with anything
other than exactly the same version of that package on other architectures. In
other words, if you need both the i386 and armel versions of something like
libc6, they must have precisely the same version number, and can only be both
upgraded together, which may cause a few delays if your system is a tad out of
date, as mine was.
4. Ok, so here we go. In theory,

> dpkg-buildpackage -aarmel -b

should do the trick. It doesn’t however, as the emdebian packages are looking
for everything in the dpkg-cross-style locations, not the Multiarch-style ones.
If however you add:

to the LDFLAGS, then everything seems to work out ok. Those of you with a C
background may be noting big warning signs about *-rpath-link*, having been
informed about the [evils of
-rpath](http://lists.debian.org/debian-devel/2004/06/msg00840.html), but [let me assure
you](http://www.delorie.com/gnu/docs/binutils/ld_3.html):

> The difference between `-rpath’ and `-rpath-link’ is that directories
> specified by `-rpath’ options are included in the executable and used at
> runtime, whereas the `-rpath-link’ option is only effective at link time. It
> is for the native linker only.

This is purely because our host system has things in a weird location, but the
target will all be ok, and the executables will be built without the extra path
data.

Tada, you now have a Multiarch-using cross-built package, which you can happily
install on your Pi!

This was quite a difficult process, and the obvious question
is: why was it so hard, and will it get easier? It was hard because Multiarch
doesn’t actually support cross-building yet. The focus so far has been on
machines with [multiple
architectures](http://wiki.debian.org/Multiarch/TheCaseForMultiarch#A32.2BAC8-64_Architectures)
with the side aim of [mixed instuction
sets](http://wiki.debian.org/Multiarch/TheCaseForMultiarch#Mixed_instruction_sets).
Cross-compiling isn’t supported yet properly, but there’s [a
spec](https://wiki.ubuntu.com/MultiarchCross) and a [GSoC student working on the
problem](http://gsoc.sitedethib.com/), whose [first
post](http://gsoc.sitedethib.com/posts/Multiarch_Cross-toolchains/) touched on
one of the big problems, which is the lack of cross-arch dependencies. Most
normal, sane packages require only stuff from one architecture. Cross-compilers
need stuff from at least two (host and target), and the Emdebian dpkg-cross
stuff works around the problem by repackaging a target-arch package as a
host-arch package with different paths, so they’d need to be re-done once this
is properly supported.

Now, I was hoping to be able have a “money shot” here i.e. a picture of the
cross-compiled snes9x running Super Mario World to demo here. As it turns out,
there’s [no accelerated X
drivers](http://www.raspberrypi.org/phpBB3/viewtopic.php?f=63&t=6768) for the Pi
yet, so getting anything to run at a reasonable speed is very hard currently…
The cross-compiled package installs and runs ok, but the graphics speed leaves
something to be desired for the moment, even with heavy use of compiler flags.
At least I know all of the above worked, even if the end system leaves something
to be desired at the moment. As it is, this is the best I can show you, but hopefully there will be improvements later on…