Multiarch Cross Toolchains

Cross Toolchains can be built using multiarch mechanisms. Specifically they need the ability to build-depend on foreign-arch packages. (arm-linux-gnueabi-gcc needs libc:armel and linux-libc-dev:armel to build).

This page documents the state of work to make this a useful reality, integrated into Debian.

How is this different from before

There have been binary cross-toolchains built for Debian for a decade or so now, using various schemes. (toolchain-source, buildcross). The Emdebian project has provided these, and currently builds them using buildcross, which relies on there already being a suitable glibc package for the target architecture, which is transformed using dpkg-cross so that everything exists in one architecture. The buildcross process is not designed for use on normal buildds due to the cross-arch buildd-deps so these packages have never been available in Debian proper. Hector Oron wrote buildcross and maintained

Ubuntu (with Linaro sponsorship) took a different approach in order to get toolchains into the archive. armel-cross-toolchain-base is a package which uses binary source packages from binutils, eglibc, linux-kernel and gcc (binutils-source, eglibc-source, linux-<ver>-source, gcc-<ver>-source) to run a 3-stage bootstrap on a normal buildd and thus generate in-archive toolchains. It works, but it's not pretty. This package has support for doing builds on Debian too, although it is only occasionally maintained.

Multiarch, combined with staged builds, lets us simplify the build process by using the normal source packages, but building them for specified targets and stages, with cross-arch dependencies. (or at least it should...)

Initial work on this was done as a 2012 GSOC project (by Thibaut Girka), and has recently (Dec 2012) been merged into gcc, with all the important bits included by gcc-4.7.2-17.

Credits:

Repository and patches

The sources and binaries from this process are being uploaded to Wookey's bootstrap repos. The multiarch toolchain bootstrap is being done in Debian using packages from unstable and experimental.

GCC patches have been fully merged into gcc-4.7.2-17. Old GCC patches are available for 4.7.2-4, 4.7.2.-11, 4.7.2-12, 4.7.2-14 and 4.7.2-16 at time of writing.

Building multiarch cross-toolchains

Where the target architecture already exists as a Debian port this is simple as you already have a suitable libc:<arch> on which to depend and libc-dev:<arch> and linux-libc-dev:<arch> on which to build-depend.

You need gcc-4.7.2-17 or later or ThibG's multiarch toolchain patches or the source from Wookey's bootstrap repository as detailed in Repository and patches.

And this binutils patch: 695595, also already applied in the bootstrap repo.

First you need a multiarch dpkg environment (as root/with sudo):

dpkg --add-architecture armel
apt-get update

Binutils:

apt-get build-dep binutils
apt-get source binutils
pushd binutils-2.*/
DEB_TARGET_ARCH=armel TARGET=armel dpkg-buildpackage -d -T control-stamp
DEB_TARGET_ARCH=armel TARGET=armel dpkg-buildpackage -b
popd

GCC 4.7:

apt-get build-dep gcc-4.7
apt-get source gcc-4.7
pushd gcc-4.7-4.7.*/
DEB_TARGET_ARCH=armel DEB_CROSS_NO_BIARCH=yes with_deps_on_target_arch_pkgs=yes dpkg-buildpackage -d -T control
DEB_TARGET_ARCH=armel DEB_CROSS_NO_BIARCH=yes with_deps_on_target_arch_pkgs=yes dpkg-buildpackage -b
popd

Bootstrapping the toolchain MA-style

This is the process of building the cross-toolchains using multiarch mechanisms for multiarch use, but when the target architecture doesn't yet exist. So things are complicated by not having libselinux-dev:arm64 or libc6-dev:arm64 or libgcc1:arm64 when starting off.

Manual full bootstrap toolchain build

Get suitable binutils source (2.23.1 or later), unpack, install build-deps, then build a BUILD_ARCH package with a specified TARGET_ARCH.

DEB_TARGET_ARCH=arm64 dpkg-buildpackage -b

which should produce: binutils-aarch64-linux-gnu_2.23.1-1~exp2_amd64.deb

Get suitable linux kernel source (from bootstrap repo or see 695241 ), unpack. Source has been modified to allow a stage1 build of just linux-libc-dev using minimal build-deps.

DEB_BUILD_PROFILE=stage1 apt-get build-dep linux-3.6.4

Then build the package for the target arch:

DEB_BUILD_PROFILE=stage1 dpkg-buildpackage -aarm64

which should get you linux-libc-dev_3.6.4-1~experimental.1_arm64.deb (i.e. linux-libc-dev:arm64)

(Note: in ubuntu raring with linux-3.7.0 you need to use either DEB_STAGE=stage1 or DEB_BUILD_PROFILE=bootstrap - this needs sorting)

Now on to the gcc/eglibc 3-stage bootstrap dance: Using a little bit of BUILD_PROFILE support:

Index: gcc-4.7-4.7.2.MAquilt/debian/rules.defs
===================================================================
--- gcc-4.7-4.7.2.MAquilt.orig/debian/rules.defs        2012-12-10 04:48:11.000000000 +0000
+++ gcc-4.7-4.7.2.MAquilt/debian/rules.defs     2012-12-10 18:08:30.000000000 +0000
@@ -214,7 +214,19 @@
 endif

 # -------------------------------------------------------------------
-# stage options
+# stage/build_profile options
+
+ifneq (,$(findstring stage1,$(DEB_BUILD_PROFILE)))
+  DEB_STAGE := stage1
+  DEB_CROSS_NO_BIARCH := yes
+endif
+
+ifneq (,$(findstring stage2,$(DEB_BUILD_PROFILE)))
+  DEB_STAGE := stage2
+  DEB_CROSS_NO_BIARCH := yes
+endif
+
+
 ifdef DEB_STAGE
   with_cdev := yes
   separate_lang := yes

we should be able to build with: GCC_TARGET=arm64 DEB_BUILD_PROFILE=stage1 debuild --preserve-env but it fails with -12 because that version doesn't build libgcc1 any more but does try to package it.

Then eglibc stage1: Get suitable eglibc source

DEB_BUILD_PROFILE=bootstrap apt-get build-dep -aarm64 eglibc
DEB_BUILD_PROFILE=bootstrap dpkg-buildpackage -aarm64

Slick apt-driven bootstrap

This process can be made very slick by using apt-get --build, as that gets sources, unpacks them, and builds them. apt-get build-dep will get all the build-deps needed (but does only work on deps listed in a Sources file so if you've changed them locally it doesn't do what you want.

This could be the basis for automation of the process.

First add the target architecture

dpkg --add-architecture arm64

Binutils: (no source changes)

 apt-get build-dep binutils
 TARGET=arm64 apt-get --build -oDpkg::Build-options="-k BEA7C52D -b" source binutils

 apt-get build-dep binutils
 DEB_TARGET_ARCH=arm64  apt-get --build -oDpkg::Build-options="-k BEA7C52D -b" source binutils=2.23.1~bootstrap

Kernel-headers:

 DEB_BUILD_PROFILE=stage1 apt-get --only-source build-dep linux               
 DEB_BUILD_PROFILE=stage1 apt-get --only-source --build -oDpkg::Build-options="-aarm64 -k BEA7C52D -B" source kernel-3.6.4=3.6.4-1~experimental.1arm64

gcc stage 1 build: (needs version 4.7.2-13~multiarch)

 DEB_BUILD_PROFILE=stage1 apt-get --only-source build-dep gcc-4.7
 DEB_BUILD_PROFILE=stage1 DEB_TARGET_ARCH=arm64 apt-get --build -oDpkg::Build-options="-k BEA7C52D -B" source gcc-4.7=4.7.2-13~multiarch

What actually happens here is the equivalent of DEB_STAGE=stage1 DEB_CROSS_NO_BIARCH=yes BACKPORT=false DEB_TARGET_ARCH=arm64 dpkg-buildpackage

This was currently not working on arm64 due to the issue below, but gcc has since been updated:

/home/wookey/linaro/armv8/toolchain/raringnew/arm64-cross-toolchain-base-1.92/gcc/build/./gcc/xgcc -B/home/wookey/linaro/armv8/toolchain/raringnew/arm64-cross-toolchain-base-1.92/gcc/build/./gcc/ -B/usr/aarch64-linux-gnu/bin/ -B/usr/aarch64-linux-gnu/lib/ -isystem /usr/aarch64-linux-gnu/include -isystem /usr/aarch64-linux-gnu/sys-include    -g -O2 -O2  -g -O2 -DIN_GCC -DCROSS_DIRECTORY_STRUCTURE  -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition  -isystem ./include   -fPIC -g -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector -Dinhibit_libc  -fPIC -I. -I. -I../.././gcc -I../../../src/libgcc -I../../../src/libgcc/. -I../../../src/libgcc/../gcc -I../../../src/libgcc/../include  -DHAVE_CC_TLS  -o _fixsfdi.o -MT _fixsfdi.o -MD -MP -MF _fixsfdi.dep -DL_fixsfdi -c ../../../src/libgcc/libgcc2.c 
In file included from /usr/include/features.h:341:0,
                 from /usr/include/limits.h:26,
                 from /home/wookey/linaro/armv8/toolchain/raringnew/arm64-cross-toolchain-base-1.92/gcc/build/./gcc/include-fixed/limits.h:169,
                 from /home/wookey/linaro/armv8/toolchain/raringnew/arm64-cross-toolchain-base-1.92/gcc/build/./gcc/include-fixed/syslimits.h:7,
                 from /home/wookey/linaro/armv8/toolchain/raringnew/arm64-cross-toolchain-base-1.92/gcc/build/./gcc/include-fixed/limits.h:34,
                 from ../../../src/libgcc/libgcc2.c:1733:
/usr/include/stdc-predef.h:30:26: fatal error: bits/predefs.h: No such file or directory
compilation terminated.

make[5]: *** [_fixunsdfsi.o] Error 1
make[5]: *** Waiting for unfinished jobs.... 
make[5]: *** [_fixunssfsi.o] Error 1 
make[5]: Leaving directory `/home/wookey/linaro/armv8/toolchain/raringnew/arm64-cross-toolchain-base-1.92/gcc/build/aarch64-linux-gnu/libgcc' 

Despite the --without-headers option in ./configure it looks in the include-fixed headers, which recurse into the system /usr/include/limits.h which is for the BUILD_ARCH, which is wrong. It's not clear why these headers are being pulled in at this point.

eglibc stage 1 build: (needs version 2.16)

Consistent target specifications

Packages that are built for a target architecture (because they generate code) need a way to specify that. This has been a little haphazard to date. For this to be automatable by build tools which don't necessarily know the specifics of every package we need a bit more regularity.

binutils uses TARGET=<arch> or a file debian/target. (<arch here can be Debian or GNU name)

gcc uses DEB_GCC_TARGET (or GCC_TARGET)=<arch> or a file debian/target. (<arch> here is Debian name)

Using a consistent variable of the same form as the BUILD and HOST vars makes sense as a way of making this consistent. e.g. DEB_TARGET_ARCH=arm64

It should also be possible to set the target arch in dpkg-buildpackage, as is currently possible for the host arch. a --target-arch=<arch> seems the obvious way. An unfinished patch for this exists.

A bug for binutils to honour DEB_TARGET_ARCH has been filed.

Consistent BUILD_PROFILE specifications

DEB_STAGE=stage1, stage2 has historically been used in the toolchain builds. It makes sense to continue to use the 'stage1' 'stage2' labels for all staged builds with the more flexible DEB_BUILD_PROFILE mechanism. But we currently (Dec 2012) have some divergence. In Ubuntu raring both linux and eglibc use DEB_BUILD_PROFILE=bootstrap or DEB_STAGE=stage1 (but not DEB_BUILD_PROFILE=stage1). We need a proper spec for what profiles should be used when so that automated tools don't need to special-case packages.

There may be a case for having a 'cross' profile for when the build-deps change from native to cross. Discussion is needed on this.

Normal cross-toolchains builds

Normally we will already have a target_arch glibc so the first two stages can be skipped.