Building a cross-toolchain from scratch

Dan Kegel
Mon Jun 2 21:50:00 GMT 2003

Hi Nick!
I don't think you posted your recipe to crossgcc, so I'm forwarding it there
from where I found it (in on Sat, 10 May 2003 01:02:58 +0000 (UTC)
archived at )

I wish I'd seen this before I updated Bill Gatliff's scripts to gcc-3.3;
it looks like you ran into the same sort of things I did.
(My scripts are at, and I'm slowly updating
them as I learn more.)
- Dan

------------------- Begin nick's recipe --------------------------------

Initially I wrote the following---quite longish---text for my own
reference, by I think it could be usefull to others too.

I'm no way a GCC guru, or any such thing, so there may be any amount
of errors and misconceptions in it. At least there are no lies :)

** Athens, 10 May 2003
** Send comments, suggestions, and corrections to:
** Nick Patavalis (

These are detailed instructions on how to build *from scratch* a cross
GNU-toolchain hosted on ix86-based linux machines and targeting
sparc-based embedded systems, plus a GNU standard library for the
target architecture. Very similar procedures can be derived from this
text for building cross toolchains and standard libraries for other
host and target architectures. In order for these instructions to be
valid, recent versions of the GNU development tools (GCC, Binutils),
and the GNU standard library (GLIBC), must be used. Specifically the
cross-toolchain described here, and actually built by the author,
comprises of the latest packaged versions available on the day of this
writing; namely of the following packages:

   GNU binutils, v2.13.2
   GCC v3.2.3 with the C and C++ front-ends enabled
   GLIBC v2.3.2

The underlined term "from scratch" above refers to the fact that
absolutely no sparc cross-development tools, no pre-compiled sparc
system libraries, and no native sparc development environment, of any
kind, are assumed already available. Apart from the host-native (ix86)
tools, everything else will be built from sources. This is a very
common case if the cross-toolchain is to be used for embedded-systems

** The "xdvl" package

Instead of performing manually the procedure described bellow you can
instead download the package:



This package contains a set of simple scripts that automate the whole
cross-toolchain building process. A README file is included in the
top-level directory of the xdvl package giving instructions on how to
use it. *IMPORTANT* This package is designed to contain everything
required to build the cross-toolchain including the source-packages
themselves. In the version available online---in order to minimize
download time---the actual source packages have been replaced by
0-sized dummies; remember to replace them with the real ones before
attempting to use the package.


** Installation locations

This discussion will assume the following installation locations for
the resulting standard library and GNU toolchain (of course other can
be used if so desired):

The standard library will be installed in:


The cross-toolchain will be installed in:


where <lver> is the version of the GLIBC package (e.g. "2.3.2"),
<cver> the version of the GCC package (e.g. "3.2.3"), <bver> is the
version of the Binutils package, and <arch> is the target architecture
("sparc-linux" in our example). Notice that the toolchain installation
directory name does not contain a target-architecture substring
("sparc-linux"). This is because the same directory can be used for
toolchains targeting different systems, provided that all toolchains
installed under the same directory are based on the same packages
(i.e. the exact same binutils and gcc versions). The version of glibc
is appended to the name of the toolchain's installation directory to
indicate the fact that the toolchain (by default) produces binaries
linked against this specific glibc version. While this
installation-directory naming scheme is certainly not the only
possible, it has proved quite useful to the author who has to maintain
multiple toolchain and standard library versions, as well as
toolchains and standard libraries for multiple target architectures.

To facilitate reference to these installation directories (who
admittedly have quite longish names) lets define the following shell
variables that will be used to refer to them:


** Acquiring the packages.

First make a sandbox directory to do all the dirty work into, and also
make a subdirectory where the tools's source packages will be
downloaded and kept. Define a shell variable to facilitate reference
to the sandbox directory:

   mkdir ./xdvl-build
   mkdir ./xdvl-build/dist
   sbx_prefix=/path/to/xdvl-build   # absolute reference

Download the following packages from a GNU mirror near you (put them
in "xdvl-build/dist"):


** Getting kernel headers

In order to build GCC and GLIBC, kernel headers are required. For a
reason that escapes me, GCC actually needs the kernel headers in order
to build "libgcc" for certain target architectures (*** can someone
explain why? ***); for example it does need the headers for the
"arm-linux" target, while for "sparc-linux" it does not! GLIBC also
needs access to the kernel headers in order to build, but this is
perfectly reasonable, considering that GLIBC provides interfaces to
all the kernel's system calls. The kernel headers can be extracted
form the kernel source distribution like this.

Download a recent kernel-sources package and put it in

   cd "$sbx_prefix"/dist
   wget -P.

Unpack the kernel sources in "xdv-build", and enter the top-level

   cd "$sbx_prefix"
   tar -xzvf linux-2.4.19.tar.gz
   cd linux

Edit the top-level Makefile, and replace the line:

   ARCH := $(shell uname -m | sed -e s/i.86/i386/ ...

with a hard-coded name for the *target* architecture. Like this:

   ARCH := sparc

Now run:

   make menuconfig

Leave all settings as they are by default, and exit (i.e run "make
menuconfig" and immediately exit).


   make include/linux/version.h

This creates the file "version.h" which contains CPP macros expanding
to kernel version strings and codes. It is required by GLIBC. The
kernel headers should now be ready. All you have to do is remove the
irrelevant architectures from the headers's collection and pack the
headers up for latter use.

   cd include/                      # now in xdvl-build/linux/include
   rm -rf asm-<every other architecture>
   cd ../../                        # now in xdvl-build
   mkdir linux-headers
   mv linux/include linux-headers/
   tar -czvf dist/sparc-linux-headers-2.4.19.tar.gz linux-headers
   rm -rf linux

** Building binutils

The most straightforward part is building binutils. First unpack the

   cd "$sbx_prefix"
   tar -xzvf dist/binutils-2.13.2.tar.gz

As suggested (though not explicitly required) in the installation
instructions, binutils will be configured and built in a separate
build directory. First create the build directory and enter it:

   mkdir binutils-build
   cd binutils-build

Then configure binutils:

   ../binutils-2.13.2/configure \
     --prefix="$tc_prefix" \

Then build them:


And finally install them:

   make install

** Building a minimal GCC

Before building the full-featured, fully-operational, compiler
collection it is necessary to build a minimal C-only version of
GCC. This is because some features of GCC require standard library
headers, and perhaps the standard library *itself* in order to build
correctly (*** is this true? are there library dependencies apart from
just header dependencies, and if so for which parts of gcc?
***). These header- and library-dependent features are mostly related
to languages other than C and the respective runtime libraries. Having
a minimal cross GCC we will cross-compile the standard library (GLIBC)
with it, and only then we can proceed to build a full-featured GCC.

Sadly this is not the whole story! It turns out that there is no
"proper" way to build, even a minimal, C compiler without having at
least some standard-library headers. Even for the most basic C-only
setup, some parts of GCC depend on (i.e. "#include") standard library
headers. Fortunately these dependencies are purely superficial; all
that is required are the prototypes of a couple of standard functions
(like, for example, "abort"). Also all the C source files that require
these prototypes can be coerced to provide them themselves (instead of
#include'ing library headers) by defining the macro
"inhibit_libc". This means we have to patch GCC's build system to
define this macro when compiling the offending files. For GCC v3.2.3
targeting "sparc-linux", all you have to do is use the following

******************* gcc-3.2.3-inhibit_libc.patch *******************

diff -urN gcc-3.2.3/gcc/config/sparc/t-linux gcc-3.2.3-inhibit_libc/gcc/config/sparc/t-linux
--- gcc-3.2.3/gcc/config/sparc/t-linux	Thu Jan  1 02:00:00 1970
+++ gcc-3.2.3-inhibit_libc/gcc/config/sparc/t-linux	Fri Apr 25 02:29:29 2003
@@ -0,0 +1,4 @@
+# inhibit_libc
+T_CFLAGS = -Dinhibit_libc
+TARGET_LIBGCC2_CFLAGS = -fPIC -Dinhibit_libc
diff -urN gcc-3.2.3/gcc/config.gcc gcc-3.2.3-inhibit_libc/gcc/config.gcc
--- gcc-3.2.3/gcc/config.gcc	Fri Feb 28 20:38:19 2003
+++ gcc-3.2.3-inhibit_libc/gcc/config.gcc	Fri Apr 25 01:55:20 2003
@@ -3102,7 +3102,7 @@
  sparc-*-linux*)		# Sparc's running GNU/Linux, libc6
  	tm_file="${tm_file} dbxelf.h elfos.h svr4.h sparc/sysv4.h sparc/linux.h"
tmake_file="t-slibgcc-elf-ver t-linux sparc/t-crtfm"
tmake_file="t-slibgcc-elf-ver t-linux sparc/t-crtfm sparc/t-linux"
  	extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"


You can do it like this:

   cd "$sbx_prefix"
   tar -xzvf ../dist/gcc-3.2.3.tar.gz
   cd gcc-3.2.3
   patch -p1 < gcc-3.2.3-inhibit_libc.patch

If you are building for another target architecture, then you have to
make the modifications manually: First search for the file
"gcc-3.2.3/gcc/config/<arch>/t-linux" if it is not there, create a new
one containing just the lines:

   # inhibit_libc
   T_CFLAGS = -Dinhibit_libc
   TARGET_LIBGCC2_CFLAGS = -fPIC -Dinhibit_libc

be careful to include not only the "-Dinhibit_libc" flag in the
variable definitions, but also whatever other flag were already
defined (here "-fPIC").

If the file "<arch>/t-linux" is already there, then either extend the
T_CFLAGS, and TARGET_LIBGCC2_CFLAGS definitions found therein to
include "-Dinhibit_libc", or add them anew if they are not
present. Again be careful to include not only the "-Dinhibit_libc",
but also whatever other flags were already defined.

Make sure that the file you have modified is considered when building
a cross compiler for your target architecture. Look in the file
"gcc-3.2.3/gcc/config.gcc", and search for your target name. You will
find something like this:

   sparc-*-linux*)  # Sparc's running GNU/Linux, libc6
     tm_file="${tm_file} dbxelf.h elfos.h svr4.h sparc/sysv4.h sparc/linux.h"
     tmake_file="t-slibgcc-elf-ver t-linux sparc/t-crtfm sparc/t-linux"
     extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"

The file you have modified or created ("<arch>/t-linux"), must be
listed in the "tmake_file=" line. If not, then add it. Make sure that
the new definitions of "T_CFLAGS" and "TARGET_LIBGCC2_CFLAGS" in
"<arch>/t-linux" are exactly the same as they were before, plus the
"-Dinhibit_libc" flag. To find what their previous definitions were
look in the files listed in the "tmake_file=" line, above.

Now that you have taken all the necessary steps, and you have
*patched* gcc-3.2.3 sources in "xdvl-build/gcc-3.2.3", the remaining
steps required for building a minimal GCC are quite straightforward:

First make sure that the location where you installed the fresh
cross-binutils comes first in your path (or at least before any other
"sparc-linux" binutils installation):


Then configure the minimal gcc:

   cd "$sbx_prefix"
   mkdir gcc-build
   mkdir gcc1
   cd gcc-build
   ../gcc-3.2.3/configure \
     --prefix="$sbx_prefix"/gcc1 \
     --target=sparc-linux \
     --with-local-prefix="$sbx_prefix"/gcc1 \
     --disable-threads \
     --with-gnu-as --with-gnu-ld \
     --with-as="$tc_prefix"/bin/sparc-linux-as \
     --with-ld="$tc_prefix"/bin/sparc-linux-ld \
     --disable-shared \
     --with-headers="$sbx_prefix"/linux-headers/include \

Observe that we install this minimal GCC withing the sandbox directory
under "xdvl-build/gcc1". This is because this compiler will only be
used to build GLIBC, and then thrown away.

Another thing that looks strange is the value given at
"--with-local-prefix". According to the GCC installation instructions
setting "--with-local-prefix" to a value equal to the value of
"--prefix", has the effect of disabling the special behavior related
to it. If you omit "--with-local-prefix" altogether, then GCC will
examine the headers in "/usr/local/include", fixinclude them, and copy
the fixed versions to its installation directory. This is definitely
*not* what you want.

"--disable-shared" indicates that we do not wish the runtime library
(libgcc) to be built as a shared object (.so), but an ordinary static
archive (.a).

Now proceed to build and install the minimal compiler:

   make install

After the minimal GCC has been built and installed, you can reset your
PATH to its original value:


** Building GLIBC

First unpack the library sources

   cd "$sbx_prefix"
   tar -xzvf dist/glibc-2.3.2.tar.gz

Then unpack the "linuxthreads" module

   cd glibc-2.3.2
   tar -xzvf glibc-linuxthreads-2.3.2.tar.gz
   cd ..

Fix you PATH so that the directory where you installed the minimal GCC
comes first in it (and certainly before any other "sparc-linux" GCC


Make sure that it works

   which sparc-linux-gcc

Create a separate build directory and configure glibc:

   mkdir glibc-build
   cd glibc-build
   ../glibc-"$libv"/configure \
     --prefix="$lc_prefix" \
     --enable-shared \
     --enable-add-ons \
     --enable-kernel=2.4.19 \
     --build=i386-linux --host=sparc-linux \

The directory specified with "--with-headers" is the directory where
you have put the linux kernel headers; the ones prepared in the
previous step.

The kernel version specified by "--enable-kernel" need not be the same
as the one you got the headers from, but it better not be a latter
one. What you should actually set "--enable-kernel" to, is the
earliest target kernel version under which you want to be able to run
the resulting GLIBC. The latest the version you specify with
"--enable-kernel" is, the less compatibility cruft will be included in
the library code.

Build the library (this could take several hours):


And then install it:

   env LANGUAGE=C LC_ALL=C make install

Copy the kernel headers in the library installation directory:

   cp -a "$sbx_prefix"/linux-headers/include/asm-sparc \
   cp -a "$sbx_prefix"/linux-headers/include/linux \

Your standard library is ready.

Now that you have compiled and installed the standard library, you no
longer need the minimal GCC. Remove it like this:

   cd "$sbx_prefix"
   rm -rf gcc1

also reset your path to its initial value


** Build full GCC

First remove the gcc source and build directories surviving from the
minimal GCC build, reopen the GCC source package, create a fresh build
directory, and enter it:

   cd "$sbx_prefix"
   rm -rf gcc-3.2.3
   rm -rf gcc-build
   tar -xzvf dist/gcc-3.2.3.tar.gz
   mkdir gcc-build
   cd gcc-build

Fix you path to include the directory where you installed the new
cross-binutils, first (or at least before any other "sparc-linux"
binutils installation):


Now configure GCC:

   ../gcc-3.2.3/configure \
     --prefix="$tc_prefix" \
     --target=sparc-linux \
     --with-local-prefix="$tc_prefix" \
     --enable-threads=posix \
     --with-gnu-as --with-gnu-ld \
     --with-as="$tc_prefix"/bin/sparc-linux-as \
     --with-ld="$tc_prefix"/bin/sparc-linux-ld \
     --with-headers="$lc_prefix"/include \
     --with-libs="$lc_prefix"/include \

Check the GCC installation instructions for other options you might
want to include, if you are building for another target.

As with the minimal GCC build, "--with-local-prefix" is set to a value
equal to the value of "--prefix", and therefore the special behavior
related to it is disabled. Were "--with-local-prefix" to be omitted
altogether, GCC would examine the headers in "/usr/local/include", it
would fixinclude them, and then copy the fixed versions to its
installation directory. This is definitely *not* what we want.

Also observe that we now make "--with-headers", and "--with-libs"
point to the "real" standard library headers and objects. This is what
we should have done anyhow, but we had to take the "minimal GCC"
detour because we had no target standard library, and no standard
library headers available.

Using the configuration shown above (there *are* other possible
configurations), during the build process, GCC will actually *copy*
all target standard library headers, as well as the target standard
library objects themselves, and put these copies under its own
installation directory. This way the resulting installed toolchain
will be totally independent from the target-GLIBC installation. After
the build and install steps show below, you could (and can if you
wish) rmrf the installed target standard library, since GCC has
"private" copies of whatever it might need from GLIBC. If you are not
too pressed for space, though, just leave it there for reference.

Build the full gcc like this:


and then install it:

   make install

Reset you PATH to its original value


Keep the source packages somewhere for reference:

   mv "$sbx_prefix"/dist /opt/xdvl/packages

Remove the sandbox directory

   rm -rf "$sbx_prefix"

Happy cross-compiling!

------------------------ end nick's recipe ---------------------------------------

- Dan

Want more information?  See the CrossGCC FAQ,
Want to unsubscribe? Send a note to

More information about the crossgcc mailing list