Notes

Programs Speedtouch Project Snoopy Project eciadsl Project The bread recipe Source Mage BeOS My resume My blog Notes Donation
Programs
Speedtouch Project
Snoopy Project
eciadsl Project
The bread recipe
Source Mage
BeOS
My resume
My blog
Notes
Donation
en fr

Building a GNU cross compiler

Benoît Papillault, 2005-02-08

Introduction

A cross compiler is like a normal compiler. It takes source code as input and produces a binary executable as output. The only difference is that the resulting binary cannot be run on the same machine. For instance, on an x86 machine, you can cross compile binaries for PowerPC® processor.

This document is not yet another howto on building a cross compiler. There are already some documents on this topic, see the References section. Its goal is to explain what are the required steps and how it is supposed to work in an ideal world. We will not talk about patches here (or just for reference). Of course, INSTRUCTIONS HERE DO NOT WORK.

Versions used

  1. linux-libc-headers-2.6.8.1
  2. binutils-2.15
  3. glibc-2.3.4
  4. glibc-linuxthreads-2.3.4
  5. gcc-core-3.4.3
  6. gcc-g++-3.4.3
  7. tar-1.15.1

Build steps

In those explanations, we will try to build a PowerPC® (powerpc-unknown-linux-gnu) cross compiler on an x86 machine (i686-pc-linux-gnu). We will try to build a PowerPC® chroot in one directory called $SYSROOT (/opt/powerpc-unknown-linux-gnu-root here) and a PowerPC® cross compiler in another directory called $PREFIX (/opt/powerpc-unknown-linux-gnu-gcc here).
  • $BUILD will be the build system, i.e. the system on which we are compiling, here i686-pc-linux-gnu
  • $HOST will be the host system, i.e. the system on which we will run the resulting binaries, here powerpc-unknown-linux-gnu
  1. Installing Linux® kernel headers

    Linux® kernel headers are needed to compile glibc. However, we need the same Linux® kernel headers as they would be on the host system. For instance, the asm symlinks should point to the proper directory. Another way to cope with this situation and which is needed on multi-arch system is to have multi-arch Linux® kernel headers.

    Since we already use multi-arch Linux® kernel headers, this step is simply a directory copy.

    mkdir -p $SYSROOT/usr/include &&
    cp -a /usr/include/asm* /usr/include/linux $SYSROOT/usr/include
    
  2. Installing binutils

    binutils provides two important tools: the GNU assembler and the GNU linker which are both used as backends by the GNU C compiler. We need here a cross binutils, i.e. a GNU assembler and a GNU linker that will run on the build system and produces binaries suitable for the host system.

    The --with-sysroot flag is quite important. It will be hardcoded in the resulting binary, i.e. $HOST-ld. It is used at runtime to locate libraries when the library search path includes a path starting with the = sign. This is the case for the default library search path which is : =/usr/local/lib:=/lib:=/usr/lib. This might seem quite complex at first but it allow libraries to be found by the linker as if we were compiling on the host system itself.

    tar jxf binutils-2.15.tar.bz2 &&
    mkdir binutils-build &&
    cd binutils-build &&
    ../binutils-2.15/configure --prefix=$PREFIX \
      --target=$HOST \
      --with-sysroot=$SYSROOT &&
    make all &&
    make install
    
  3. Installing glibc headers

    We need the glibc headers for building gcc. We have used the linuxthreads add-ons instead of nptl since nptl was not working in this step. We specify both the build and host system on the configure command line to force the cross compilation mode. BUILD can be determined by running the config.guess script in the binutils sources.

    tar jxf glibc-2.3.4.tar.bz2 &&
    (cd glibc-2.3.4 &&
      tar jxf glibc-linuxthreads-2.3.4.tar.bz2) &&
    mkdir glibc-build &&
    cd glibc-build &&
    ../glibc-2.3.4/configure --prefix=/usr \
      --build=$BUILD --host=$HOST \
      --with-headers=$SYSROOT/usr/include \
      --without-cvs --disable-profile --disable-debug --without-gd \
      --enable-add-ons=linuxthreads --with-tls --without-__thread \
      --enable-kernel=2.4 &&
    make install-headers install_root=$SYSROOT
    
  4. Installing bootstrap gcc

    At this step, we can compile a first cross compiler. It will not be able to produce shared libraries since shared libraries need glibc shared libraries.

    Like with binutils, the --with-sysroot flag is quite important too. It will be used at runtime to handle the default headers search path as if we were compiling on the host system. The default headers search path is : /usr/local/include:/usr/include. Some internal gcc directories might be added as well ($PREFIX/lib/gcc/$HOST/3.4.3/include here)

    tar jxf gcc-core-3.4.3.tar.bz2 &&
    mkdir gcc-build &&
    cd gcc-build &&
    ../gcc-3.4.3/configure --prefix=$PREFIX \
      --target=$HOST \
      --with-sysroot=$SYSROOT --with-headers=$SYSROOT/usr/include \
      --disable-threads --disable-shared --enable-language=c &&
    make &&
    make install
    
  5. Installing glibc

    We now have a basic cross compiler/assembler/linker. We will use it to build a host glibc. We need to add the correct directory to PATH so that the configure script could find our cross compiler.

    export PATH=$PREFIX/bin:$PATH &&
    tar jxf glibc-2.3.4.tar.bz2 &&
    (cd glibc-2.3.4 &&
      tar jxf glibc-linuxthreads-2.3.4.tar.bz2) &&
    ../glibc-2.3.4/configure \
      --prefix=/usr \
      --build=$BUILD --host=$HOST \
      --with-headers=$SYSROOT/usr/include \
      --without-cvs --disable-profile --disable-debug --without-gd \
      --enable-add-ons=linuxthreads --with-tls --without-__thread \
      --enable-kernel=2.4 &&
    make &&
    make install install_root=$SYSROOT &&
    
  6. Installing gcc

    Since we now have a host glibc, we can rebuild our cross compiler to include C++ support (this requires building a shared library and can not be done in the former step).

    tar jxf gcc-core-3.4.3.tar.bz2 &&
    tar jxf gcc-g++-3.4.3.tar.bz2 &&
    mkdir gcc-build &&
    cd gcc-build &&
    ../gcc-3.4.3/configure --prefix=$PREFIX \
      --target=$HOST \
      --with-sysroot=$SYSROOT --with-headers=$SYSROOT/usr/include \
      --enable-threads=posix --enable-languages=c,c++ &&
    make &&
    make install
    

Testing

  1. A simple example: compiling Hello World!

    We will use the following sample C program to test if our cross compiler is working. It's a very simple program.

    int main()
    { printf("Hello World!\n"); return 0; }
    
    We compile it with :
    $HOST-gcc -o main main.c
    
    We can now copy the main file over the host system and run it!
  2. A more complex example: compiling tar

    We will now use the proper configure syntax to enable cross compilation. DESTDIR is the proper argument to use for make install with all software using automake, which is the case of tar.

    tar zxvf tar-1.15.1.tar.gz &&
    cd tar-1.15.1 &&
    ./configure --prefix=/usr --host=$HOST &&
    make &&
    make install DESTDIR=$SYSROOT
    

    Other software might use the same convention even when not using automake. If no convention has been used, we could use make install prefix=$SYSROOT/usr instead, but it will not work for path that have been passed on the configure command line. Here is a more complex example that might apply in this case:

    ./configure --prefix=/usr \
    			--sysconfdir=/etc \
    			--localstatedir=/var \
    			--mandir="\${prefix}/share/man" \
    			--infodir="\${prefix}/share/info" &&
    make &&
    make install prefix="${SYSROOT}/usr" \
                 sysconfdir="${SYSROOT}/etc" \
                 localstatedir="${SYSROOT}/var"
    

References

  1. The main site for building a GNU cross compiler is http://kegel.com/crosstool/. It provides a nice script that can be used to produce a working cross compiler. The script also includes various patches that have been collected and apply them automatically.
  2. Autoconf 2.57 manual explains how to use ./configure script argument to properly enable cross compilation. The details are in section 15.6.3.
  3. Autobook manual explains how autoconf/automake framework can be used to simplify cross compilation, especially when your software needs to compile tools that will be run on the build machine. Details are in section 26.4.6.2.
  4. A working script implementing what has been descrire here: mk-cross-gcc. It can also be used to build an x86_64 bi-arch cross compiler (not described here).
  5. A glibc-2.3.4 patch needed to use the previous script: glibc-2.3.4-libeh-kludge.patch

Legal

  • Linux® is a registered trademark of Linus Torvalds
  • PowerPC® is a registered trademark of International Business Machines Corporation
Valid XHTML 1.0! CSS Valide !
Benoît Papillault