|
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
-
linux-libc-headers-2.6.8.1
-
binutils-2.15
-
glibc-2.3.4
-
glibc-linuxthreads-2.3.4
-
gcc-core-3.4.3
-
gcc-g++-3.4.3
-
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
- 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
- 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
- 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
- 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
- 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 &&
- 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
- 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!
- 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
- 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.
-
Autoconf 2.57 manual explains how to use
./configure
script argument to properly enable cross compilation. The details are
in
section 15.6.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.
- 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).
- 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
|