HOWTO Build a Cross Toolchain in Brief
Most of the time you're better off using one of the PrebuiltToolchains, however if for some reason they are insufficient for your needs, or you just want to get a better idea of how things work, this document is for you. Some attemps at automating the process have been made over in GNU Toolchain Projects at http://www.handhelds.org/projects/toolchain/index.html , and a generic GNU Toolchain for ARM targets HOWTO is at http://www.armlinux.org/docs/toolchain/ . See also the generic toolchain build-and-test script at http://kegel.com/crosstool .
There also exist some tips and tricks on [Porting Software to ARM Linux].
I think this document is accurate. Some testing has been done and all tests were successful. However, this is a very complex system and testing it in it's entirety is difficult at best. Feel free to use this document, but use care. If you find any problems (especially ones you can fix) please let us know. KenCausey*
On 5-Feb-2004, I followed these instructions to build a toolchain using gcc-3.3-cvs, binutils-031031, and glibc-2.3.2, from the handhelds ftp site with kernel2419 from handhelds CVS. With minor tweaks that I've added to the instructions (and the hacks on the CrossToolchainHacksPage) I made it work.
Building a new tool chain is easy:
Note: In the examples in this HOWTO we are going to build an ARM cross tool chain using /usr/src/ as the source directory, /usr/src/build/ as the build directory, and /skiff/local/ as the installation prefix.
All of the following source code can be found in ftp://ftp.handhelds.org/projects/toolchain/source
-
Get the source code for the Bin Utilities - binutils-2.9.5.0.22
-
Get source code for GCC - gcc-2.95.2
-
Get source code glibc - glibc-2.1.2
-
Unpack the above programs in your source directory, we'll use /usr/src.
-
Get gcc difference for Arm - gcc-2.95.2-diff-991022 (apply this with patch -p0 <../gcc-2.95.2-diff-991022 from the gcc source directory assuming the patch is in the parent directory.)
-
If using gcc-3.3-cvs from the handhelds site, you do not need this patch.
-
Get the gcc patch for fold-const.c - gcc-fold-const.patch (apply this patch with 'patch -p0 <../../gcc-fold-const.patch' from the gcc subdirectory of the gcc source directory assuming that the patch is in the parent directory of the gcc source directory)
-
You can skip this patch too if you are using gcc-3.3
-
Get glibc-crypt-2.0.111 and glibc-linuxthreads-2.1.2.tar.gz and extract each in the glibc source directory.
-
If using glibc-2.3.2, you do not need the crypt stuff.
-
Build gcc with glibc using the new Bin Utilities - I'm almost certain that this step is identical to the next one.
-
Be Happy. Every thing should work except for CHILL.
Create the Build directories
I highly recommend that the Tool Chain be built into a separate directory other than the sources and that that directory not reside within the source tree. Building the Tool Chain where srcdir == objdir could still work, but doesn't get extensive testing; building where objdir is a subdirectory of srcdir is unsupported:
cd /usr/src mkdir build cd build mkdir binutils-2.9.5.0.22 mkdir gcc-2.95.2 mkdir glibc-2.1.2
Build the Bin Utilities
-
Choose the prefix for the new tool chain. This is a fixed directory where the tool chain will forever reside, unless you re-build to tool chain. For example: /usr/local or /skiff/local. We will use /skiff/local in this document.
-
Choose the target for the new tool chain. We will us arm-linux, there are other options but you will know if you need them.
-
Choose the host, if you wish. If you do not choose, then the bin utils will use the machine type of your machine. For example, if you are creating the bin utils on an i586 then you will need an i586 or better to use the new bin utils.
-
In the 'binutils' build directory (/usr/src/build/binutils-2.9.5.0.22/) type::
/usr/src/binutils-2.9.5.0.22/configure --target=arm-linux --prefix=/skiff/local --host=i386 make make install
You will find a new set of bin utils at /skiff/local/bin. Be sure to add this directory to your PATH.
Build gcc (the hard way) without glibc
-
Make your Kernel headers available to the new compilers:
-
If you have an existing and working ARM Kernel that you have cross compiled. We will assume that your existing ARM kernel is in /usr/src/arm-linux.
Make the Kernel headers available to the new compiler by typing:
cd /skiff/local/arm-linux mkdir include cd include ln -s /usr/src/arm-linux/include/asm-arm asm ln -s /usr/src/arm-linux/include/linux linux
-
If you have not compiled a working Arm Kernel:
-
Get a copy of your Linux ARM kernel source with updated patches. The http://Handhelds.org version can be retrieved via anonymous CVS, see http://handhelds.org/sources.html for more information.
-
Apply the patches (if you are not using the Handhelds CVS sources)
-
You may need to modify the ARCH variable found in the Makefile in the top-level of the kernel source directory for the architecture you are targetting. If you use the http://handhelds.org CVS version of the kernel source, this modification has already been done, resulting in ARCH := arm.
Next 2 steps unnecessary in this example
-
In the top-level kernel source directory modify the file Makefile with your favorite text editor. You will find a line that looks like:
ARCH := $(shell uname - m | sed -e s/i.86/i386 -e s/sun4u/sp....
-
Under this line insert:
ARCH := arm
-
Type:
make menuconfig
-
Go to the section on system and processor type and select a system consistent with what you are building. Again, if you are using the http://handhelds.org CVS sources, this has already been done for you.
-
Save your changes and exit the config program
-
Type
make dep
(Issuing "make dep" failed for me when using the kernel2419 source from the handhelds.org CVS. I just skipped it and things "worked" anyway.)
This will guarantee that your headers are up to date.
-
If you don't already have the directory /skiff/local/arm-linux/include, type:
mkdir /skiff/local/arm-linux/include
-
Type:
cp -dR /usr/src/arm-linux/include/asm-arm /skiff/local/arm-linux/include/asm
-
Type:
cp -dR /usr/src/arm-linux/include/linux /skiff/local/arm-linux/include/linux
Now gcc should have its headers.
-
Type:
cd /usr/src/gcc-2.95.2/gcc/config/arm
-
Use your favorite editor to modify the file t-linux. Append -Dinhibit_libc -D__gthr_posix_h to the line that starts TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC. Which should result in:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
-
Type:
cd /usr/src/build/gcc-2.95.2
-
Add /skiff/local/bin to your PATH. If you are using the bash shell type: export PATH=/skiff/local/bin:$PATH
-
Type:
/usr/src/gcc-2.95.2/configure --target=arm-linux --host=i386-pc-linux-gnu --prefix=/skiff/local --disable-threads --with-cpu=strongarm110 --enable-languages=c
At this point, only the gcc portion can be built and installed. Later once gcc and glibc have been installed, the rest can be built.
-
Type:
make
(Note that it may error when configuring libiberty - this is ok, just continue..) (Note you need autoheader to make this work, autoheader is in the package autoconf) (If you get an error on "crti.o", try doing make -i LANGUAGE=c, and then make -i LANGUAGES=c install)
-
Type:
make install
-
In the /skiff/local/bin directory you should now find a program arm-linux-gcc this is the new c compiler from an i386 host to an arm4l target without threads or glibc.
-
In the final 2 steps we need to configure arm-linux-gcc for arm4l targets, type:
cd /skiff/local/lib/gcc-lib/arm-linux/2.95.2
-
Use your favorite editor to modify the file specs, to get the correct behaviour from gcc. If you are using gcc-2.95.2 from ftp://ftp.handhelds.org then this change has probably already been made, but check that the *link section of your specs file is as follows:
*link: %{h*} %{version:-v} %{b} %{Wl,*:%*} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} %{rdynamic:-export-dynamic} %{!dynamic-linker: -dynamic-linker /lib/ld-linu*so.2} -X %{mbig-endian:-EB} %{mapcs-26:-m armelf_linux26} %{!mapcs-26:-m armelf_linux} -p
Building glibc
-
Type:
cd /usr/src/build/glibc-2.1.2
-
Type:
/usr/src/glibc-2.1.2/configure arm-linux --build=i386-pc-linux-gnu --prefix=/skiff/local/arm-linux --enable-add-ons=linuxthreads,crypt
For later versions of glibc, you'll want to add --host=arm-linux.
-
Type:
make
If you get: error: asm-specifier for variable _a1 conflicts with asm clobber list, then apply the glibc_a1 hack on the CrossToolchainHacksPage.
If you get: error: va_start used in function with fixed args, then apply the va_start hack on the CrossToolchainHacksPage.
If you get: Error: garbage following instruction ldr lr,[sp],#4 ldr ip,=__libc_multiple_threads, then apply the sysdep hack on the CrossToolchainHacksPage.
-
Type:
make install
Building GCC with threads and additional languages
-
Type:
cd /usr/src/gcc-2.95.2/gcc/config/arm
-
Use your favorite editor to modify the file t-linux to remove -Dinhibit_libc -D__gthr_posix_h from the line that starts TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC. The result should be:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer - fPIC
-
Type:
cd /usr/src/gcc-2.95.2/libchill
(If you do not have the libchill directory, then presumably you can skip this step.)
-
Use your favorite editor to modify the file basicio.c by inserting after line 40 a new line #define PATH_MAX 4095.
(This file (basicio.c) is not present in gcc-3.3.)
-
Type:
cd /usr/src/build/gcc-2.95.2
-
Type:
rm -rf *
-
Type:
/usr/src/gcc-2.95.2/configure --target=arm-linux --host=i386-pc-linux-gnu --prefix=/skiff/local --with-cpu=strongarm110
(For kicks, I added --with-cpu=xscale, but I'm not sure it matters Anyone?)
If you get an error on libc.so: file format not recognized; treating as linker script, then apply the arm_lib hack from the CrossToolchainHacksPage.
-
Type:
make
If you're using a newer version of gcc (>=3) and get an error like this: storage class specified for parameter `type name', apply the __thread hack from the CrossToolchainHacksPage.
-
Type:
make install
Look in the /skiff/local/bin directory everthing should be there. At this time the GCC testsuite is not supported.
That's all folks.
Author: GeorgeFrance
Editor: KenCausey (you can blame me for all the typos and errors )
Notes
I tried using the toolchain script but couldn't get it to compile without errors (2006-06-18). As it's not that easy to spot the problem in that script, I reverted to compiling everything by hand.
Above procedure works for more recent versions of binutils, GCC and glibc with some minor modifications, too. Here are some hints if it doesn't work for you:
-
There seems to be a problem with the current binutils: If you get an error message complaining about missing __thread support in GCC while compiling glibc, try using the source code from binutils CVS. That fixed the problem for me.
-
GCC relies on some files you'll only have if you've already compiled glibc, but then again you'd need GCC to do that. So if you start from scratch you won't have these files and GCC won't compile without errors (if at all; and the above hint with using make -i LANGUAGES="c" just made it worse for me).
One possibility to circumvent this is to take one of the prebuilt toolchains and copy the relevant include and lib directories to your own toolchain. That way GCC finds everything it needs and gives less trouble. The files from the prebuilt toolchain will then be automatically overwritten with the new version when you make install
Good luck!
-- WolfgangKempin 2006-06-19 10:17:01