Cross compiling uClibc and busybox

There are a few articles from this blog that are old, but still known an read – even outside the small area of people speaking German. Thus this article written in English. My intention is to show how to cross compile uClibc and a BusyBox that is statically linked with this uClibc. The resulting BusyBox can be used to build some minimal Linux system. Around three or four Megabytes if you keep it really small. Nearly five years ago I wrote a tutorial on this topic (in German) on which I still receive feedback quite often. Since this tutorial is very outdated (module loading, initrd vs. initramfs, multiple initramfs), I plan to update it. This tutorial will show a quick alternative to get a working cross compiled BusyBox.

The content of this blog entry is partially based on the “semi official tutorial” how to cross compile BusyBox and partially on my experience with Linux from Scratch, especially Chapter 5 – Constructing a temporary system. At the time of this being written, I tried to make sure that very few patches are necessary – this will not always be the way, maybe GCC 4.7 will need more patches or BusyBox 1.19 does. uClibc 0.9.32 does not yet build cleanly on x86, thus I stay with uClibc for this time:

Needed files

Sources and patches:

Configuration files:

1. Setting up the environment

Very few modifications to the environment are necessary. We just need three variables:

    export TGTARCH=i486 
    export INSTDIR=/usr/local/crosstools
    export PATH=${INSTDIR}/bin:${PATH}

$TGTARCH is the targeted architecture, it should be either i486, i586, i686 or x86_64. Of course it is possible to build for several ARM or MIPS targets if you need a statically linked BusyBox for a rooted Android device or a DSL router. There is one drawback however: My configs for uClibc and BusyBox are very x86 specific. For the first build I recommend using the same target architecture as the machine you are building:

    export TGTARCH=` uname -m `

$INSTDIR is the location of the resulting toolchain. When building for different target architectures, you might also include the name of the target arch into the path. This makes deinstallation easier – you just have to delete a branch in the file system. For example:

    export TGTARCH=i486 
    export INSTDIR=/usr/local/uclibc-crosstools-${TGTARCH}
    export PATH=${INSTDIR}/bin:${PATH}

2. Building binutils

Unpack the binutils and create a directory binutils-build on the same level of the file system, then configure binutils:

    tar xvjf binutils-2.21.tar.bz2
    mkdir binutils-build
    cd binutils-build
    ../binutils-2.21/configure \
        --target=${TGTARCH}-linux-uclibc \
        --prefix=${INSTDIR} --disable-nls \

Now build and install binutils:

    make && make install

3. Building GCC

As far as I tested, GCC needs a small patch to result in a properly working cross compiler. Besides this, GMP, MPFR and MPC must be present:

    tar xvjf gcc-4.6.0.tar.bz2
    tar xvjf mpfr-3.0.1.tar.bz2
    tar xvjf gmp-5.0.2.tar.bz2
    tar xvzf mpc-0.9.tar.gz
    mv mpfr-3.0.1 gcc-4.6.0/mpfr
    mv gmp-5.0.2 gcc-4.6.0/gmp
    mv mpc-0.9 gcc-4.6.0/mpc
    mkdir gcc-build
    cd gcc-4.6.0
    cat ../gcc-4.6.0-cross_compile-1.patch | patch -p1
    cd ../gcc-build

Now configure, build and install GCC:

    ../gcc-4.6.0/configure \
        --target=${TGTARCH}-linux-uclibc \
        --prefix=${INSTDIR} \
	--disable-nls --disable-shared --disable-multilib \
        --disable-libmudflap --disable-libssp --disable-libgomp \
        --disable-libquadmath --disable-target-libiberty \
        --disable-target-zlib --disable-decimal-float \
        --disable-threads --enable-languages=c \
	--without-ppl --without-cloog
    make && make install

4. Installing kernel headers

The kernel headers used should ressemble the version you intend to run the BusyBox on. Unpack and install them – the sanitizing step is taken from Linux from Scratch:

    tar xvjf linux-
    cd linux-
    make INSTALL_HDR_PATH=dest headers_install
    find dest/include \( -name .install -o -name ..install.cmd \) -delete
    mkdir -p ${INSTDIR}/${TGTARCH}-linux-uclibc/include
    cp -rv dest/include/* ${INSTDIR}/${TGTARCH}-linux-uclibc/include

In the next steps ${INSTDIR}/${TGTARCH}-linux-uclibc will become more populated with headers, libraries and other development files for our build target.

5. Installing uClibc

Unpack uClibc and copy the config into the resulting directory. Since uClibc uses the same configuration scheme as the Linux kernel, some parameters in the config have to be changed with sed, and a run of make oldconfig is needed if you do not run my exact version of uClibc:

    unxz -c uClibc- | tar xvf -
    cp uClibc- uClibc-
    cd uClibc-
    # This fixes the path of the linux headers
    sed -i 's%/usr/local/crosstools/i486-linux-uclibc/include%'${INSTDIR}/${TGTARCH}-linux-uclibc/include'%g' .config
    # This fixes the path to GCC and binutils:
    sed -i 's%/usr/local/crosstools/bin/i486-linux-uclibc-%'${INSTDIR}/bin/${TGTARCH}-linux-uclibc-'%g' .config
    make oldconfig

When building for x86_64 instead of i486-i686, replace the target as well:

    sed -i 's%TARGET_i386=y%#TARGET_i386 is not set%g' .config
    sed -i 's%# TARGET_x86_64 is not set%TARGET_x86_64=y%g' .config
    make oldconfig

Now build and install uClibc:

    make install PREFIX=${INSTDIR}/${TGTARCH}-linux-uclibc/

Everything is in place now. In the next step we are building the statically linked BusyBox:

6. Building BusyBox

Our BusyBox will be statically linked. Since BusyBox also uses the configuration scheme from the Linux kernel, configuration is done by copying the .config file:

    tar xvjf busybox-1.18.5.tar.bz2
    cp busybox-1.18.5.config busybox-1.18.5/.config
    cd busybox-1.18.5
    make oldconfig CROSS_COMPILE=${TGTARCH}-linux-uclibc-

Build BusyBox and install it to the subdirectory _install:

    make CROSS_COMPILE=${TGTARCH}-linux-uclibc-
    make install CROSS_COMPILE=${TGTARCH}-linux-uclibc-

If your build system is x86_64, any i486 to i686 or x86_64 can be directly run. There will be no hassle with libraries since our binary is statically linked:

    # Should result in: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped
    file _install/bin/busybox
    # Should print the BusyBox applets contained

That’s it. Have fun with your BusyBox. In a short time I will tell you how to configure and build a minimal Linux system that just consists of a kernel, BusyBox and Dropbear for SSH logins – that is just enough Linux to do imaging and restoring tasks.

3 thoughts on “Cross compiling uClibc and busybox

  1. Bob Campbell

    .. oh, I might mention this for anyone else having problems.. my tool chain for an x86 was built with GCC 4.2.4 and Binutils 2.18..

    >> Cross-Compiled Linux From Scratch – Version 1.1.0-x86
    Chapter 5. Constructing Cross-Compile Tools <<

    I used uClibc- for this example. I realize these sources are a little older but when trying to learn the "ropes" when compiling packages it seems to have less problems..

    getting ready to "add" the busybox application now..


Comments are closed.