Friday, April 27, 2012

Cross Compiling with MultiArch

Congrats to the Ubuntu Folk for the new LTS release. Incidentally this is also the first release where our work on MultiArch bears fruit. We can now cross-compile relatively easily without resorting to hacks like scratchbox, qemu chroot or dpkg-cross/xdeb.

Lets show short practical guide on cross-building Qemu for armhf. The instructions refer to precise, but the goodiness is on the way to Debian as well. Biggest missing piece being the cross-compiler packages, which we have an Summer of Code project. The example is operated in a chroot to avoid potentially messing up your working machine. Qemu-linaro is not a shining example, as cross-building it doesn't work out of box. But that is educational, it allows me to show what kind of issues you can bump into, and how to fix them.

 $ sudo debootstrap --variant=buildd precise /srv/precise
Edit the /srv/precise/etc/apt.sources.list to the following (replace amd64 with i386 if you made an i386 chroot)
deb [arch=amd64] precise main universe
deb [arch=armhf] precise main universe
deb-src precise main universe
Edit the /srv/precise/etc/dpkg/dpkg.cfg.d/multiarch by adding the following line:
foreign-architecture armhf
Finally disable install of recommends by editing /srv/precise/etc/apt/apt.conf.d/10local:
APT::Install-Recommends "0";
APT::Install-Suggests "0";
Install the armhf crosscompiler the chroot
 $ sudo chroot /srv/precise/
 # mount -t proc proc /proc
 # apt-get update
 # apt-get install g++-arm-linux-gnueabihf pkg-config-arm-linux-gnueabihf
Get the sources and try to install the cross-buildeps:
 # cd /tmp
 # apt-get source qemu-linaro
 # cd qemu-linaro-*
 # apt-get build-dep -aarmhf qemu-linaro
As we see, the build-dep bombs out ugly, with a them of "perl" being unable to be installed. This is because apt-get can't figure out if we should install and armhf or amd64 version of perl. We don't use the required syntax yet in Build-Dep line, "perl:any", as dpkg and apt in previous released don't support it. Thus back porting would no longer be possible. One way to fix it, would be to drop perl build-dep, as perl is already pulled by other build-deps. But lets instead show howto install it the build-deps manually. First we build system build-deps, then target architecture ones:
 # apt-get install debhelper texinfo
 # apt-get install zlib1g-dev:armhf libasound2-dev:armhf libsdl1.2-dev:armhf libx11-dev:armhf libpulse-dev:armhf libncurses5-dev:armhf libbrlapi-dev:armhf libcurl4-gnutls-dev:armhf libgnutls-dev:armhf libsasl2-dev:armhf uuid-dev:armhf libvdeplug2-dev:armhf libbluetooth-dev:armhf
And try the build[1]:
 # dpkg-buildpackage -aarmhf -B
Which sadly errors out. Turns out the cross-build support in debian/rules is broken. Instead of --cc we need to feed an --cross-prefix to the ./configure of qemu. Edit the debian/rules with replacing
-  conf_arch += --cc=$(DEB_HOST_GNU_TYPE)-gcc --cpu=$(QEMU_CPU)
+  conf_arch += --cross-prefix=$(DEB_HOST_GNU_TYPE)-
Optional: Since we are cross-compiling from a multicore machine, lets also add parallel building support, by changing the override_dh_auto_build: rule to have --parallel flags in debian/rules as well:
        # system build
        dh_auto_build -B system-build --parallel
ifeq ($(DEB_HOST_ARCH_OS),linux)
        # user build
        dh_auto_build -B user-build --parallel

        # static user build
        dh_auto_build -B user-static-build --parallel

Try the build again:
 # export DEB_BUILD_OPTIONS=parallel=4 # I have dual-core hyperthreading machine, build with all four threads
 # time dpkg-buildpackage -aarmhf -B
dpkg-buildpackage: binary only upload (no source included)

real    18m53.425s
user    65m42.570s
sys     2m50.383s
The Native build of qemu-linaro took 4h 11min.

[1] You should not build as root - but to keep instructions short, I'm not explaining howto add and use a unprivileged user in a chroot. Do as I *say*, not as I *do*!