Building your own toolchain

A brief note on how to prepare all the toolchain yourself, instead of using ones from Aboriginal's or Linaro's.


A cross-compiler is a compiler that runs on one platform (e.g. x86_64) and generates code for another platform (e.g. ARM). This would be the first step that we have to do if we want to do development on a new platform.

Once we have this cross-compiler, we can build various software targets for the new platform: the kernel, the shell, the utilities, and others, including the native compiler for that platform.

A native compiler is a compiler that generates code for the same platform that it runs on. A native compiler is usually called just as "the compiler" - without the prefix cross- it is understood that a compiler is native. To build a native compiler on a new platform, one needs to have a cross-compiler first.

So it seems obvious that any new platform development effort must start at creating the first compiler. In the FirstBoot page, this was short-circuited by using a ready-made cross-compiler from Aboriginal and Linaro. In the NativeCompiler page, again this was short-circuited by using the Aboriginal's native compiler.

And the reason for that is because it is easy to make unnoticeable mistakes during the compiler build; mistakes which won't show any effect until you build important software (e.g. kernel). And when your kernel won't boot - the question is, did I configure the kernel wrongly, or was the compiler botched?

That's why I started with a known good compiler. Once that works and we can be sure indeed that the configuration etc is correct, then we can build our own compiler at ease, knowing that any failure later would be the problem at the compiler level and not because software configuration.

So now that we have a working system using those shortcuts, in this page I will go ahead and explain those steps that I have previously skipped.

Building the Cross Compiler

Nowadays, there are many ways to build your own cross-compiler. There are many scripts and environments that will do that for you, for example (in no particular order of preference):

and I'm sure there are many others that I'm not aware of. These are toolchain builders: you tell them what to build (e.g. which version of gcc, which version of binutils, glibc, etc) and they will build the toolchain for you while you go and have coffe or something - and when they finish you'll get your shiny, new cross-compiler.

And if that's all that you want to know, that's great - go and grab and use them. They are very useful tools indeed.

But except for Aboriginal Linux, these tools have two problems:

The second deficiency is especially problematic, because sooner or later we want to get a native compiler going. To know about these things, there is no substitute to doing it the LinuxFromScratch (LFS) way. In fact, LFS has subproject called Cross LFS (CLFS) that does exactly that.

To build a cross-compiler using the CLFS, follow Chapter 5 (after doing the preparation in Chapter 4 and reading the earlier chapters). By the end of Chapter 5, you will get a working cross-compiler located in /cross-tools .

There is no instruction for building CLFS for the ARM platform, but you can use other non-x86 platform as a template (suitably modifying the platform reference to ARM). For example, I used the MIPS CLFS successfully. Follow the CLFS for MIPS; the only change you need to do is CLFS_TARGET: instead of mips-unknown-linux-gnu, change that to arm-lfs-linux-gnueabi. Obviously you can skip building MIPS-specific packages (like the Colo bootloader).

This native compiler is as good as Aboriginal's or Linaro's one, although for making static binaries (e.g. static busybox) I still recommend to use Aboriginal cross compiler as it uses uClibc and thus creates smaller static binaries.

Building the Staging Native Compiler

Once you've gotten the cross-compiler, the next step would be to prepare the native compiler. In (C)LFS, there are two native compilers:

Follow CLFS Chapter 6; by the end of Chapter 6 you would get a working staging native compiler hosted in /tools, which you can copy into your bootable root filesystem and use it on the real ARM machine.

If you are going to follow the FirstBoot method and you build a static busybox with all applets enabled, then you don't need to build all the packages listed in Chapter 6; as some of those are provided by busybox and are adequate for building the full system later. Other than the toolchain (binutils, gcc and eglibc), the ones you need to build are: file, flex, bison, make, m4 (these aren't provided busybox), patch (patch from busybox is buggy), and bash/ncurses (some GNU tools explicitly require bash for building) . If you wish you can build gettext and texinfo. If you don't use busybox you need to build all of them.

This staging native compiler is as good as Aboriginal's one, and it is as handy too - you can put it to SD Card anywhere, and symlink /tools to the directory that contains the tool, and you can use it when you use the SD Card to boot your platform.

Building the Final Native Compiler

Once you have the native compiler, you can boot as described in FirstBoot page. From there, you have two options to go on and create the final native compiler:

They are (almost) identical from that point onwards.

Final Notes

The default instructions in CLFS will create default compilers and libraries; and in this case, it will be soft-float toolchain. If you want to make a hardfloat toolchain instead, use the modifications I've put in NativeCompiler page. Basically it is about adding some --with-xxx settings when building the compiler, and adding CFLAGS=-mfloat-abi settings when building glibc.