Small reminder for Linux user very keen of embedded system.
We will detail the design of a cross-toolchain "From Scratch".
The purpose of this webpage is to understand the design method of a cross-toolchain of a pedagogical perspective.
1°) Obtaining a cross-toolchain for ARM architecture
There are several ways to obtain a cross-toolchain. First, the most tedious requiring one to one to compile the sources is commonly called "From Scratch". Another method, more comfortable, is the one requiring the implementation of a tool to generate a string. There crosstool ( http://www.kegel.com/crosstool/ ) which is obsolete but is still able to produce beautiful though somewhat veillotte chains. Crosstool is replaced by crosstool-ng (ng: New Generation) ( http://crosstool-ng.org ). It is maintained and managed by a French. Its setting is kind of like the nucleus (ncurses menu to the sauce). There are chains of cross-made compilations and downloadable on the website of the German company DENX Software Engineering ( http://www.denx.de/en/News/WebHome ). Finally, there are also tools for creating complete embedded Linux distribution (kernel + file system + toolchain cross) as Buildroot, OpenEmbedded, PTXdist. Disadvantage, in many cases, these chains are specific to cross-compilation tool for creating distribution.
A cross toolchain consists of different elements as follows:
- The file header of a Linux kernel,
- A set of software development tools: binutils (binary utilities),
- A Compiler: GCC,
- A C library: glibc
- For more recent versions of GCC: a set of libraries for scientific computing: MPFR and GMP.
All these elements are vital to achieving a toolchain. Their various combinations can generate a cross-toolchain with the help of a few patches or not at all be compatible with each other. It should be to experiment with different versions of each element before reaching a channel without too much difficulty. The library used in the following examples is glibc. It is mainly used in the Linux world. This library contains the main C library system. Glibc provides a set of routines (opening / - closing file; memory allocation etc ...) necessary for the proper functioning of the system based on GNU Linux kernel. It acts as an interface between the kernel and operating system calls with these systems it provides. However, there are other C library that are much lighter and more suitable for embedded systems, for example, the library uClibc, dietlibc library or library newlib.
2) What you need to know or own
Base for a cross toolchain fully functional, it should obviously have:
- Preferably a fast machine (reduced build time),
- A Linux operating system,
- A GCC compiler,
Whichever method of designing the cross-toolchain, it should also have prior program "autoconf" installed in the host machine. This program is responsible for producing a file (called make) that automates the compilation of all sources of a package. To generate such a file, the "configure" script has the mission to inspect the system to ensure that sources can find all dependencies set on the system to properly compile the sources. It should also clarify some terms passed as parameters to the configure script:
- build : refers to the machine where the source code is compiled,
- host : is the machine where the compiler is running,
- target : is the machine for which code is generated.
In all cases the name of the chain will be final type arm-none-linux-gnueabi . The four values mean:
- arm : information on the processor name. It can be mips, i686, x86_64 etc. ...
- none : provides information on additional information. Sometimes this field does not exist. In the case of its presence, the field type is unknown or none,
- linux : information about the operating system,
- gnueabi : information on the type of libc. There are other gnuabi, gnulibc, uclibc.
3) The common steps of creating a chain
1. Obviously obtaining sources is essential. Downloading them from an official website can be done either by hand (systematic use of the wget command for each package), or automatically by script (this is the case with crosstool-ng and crosstool). You can download the sources from CVS (Concurrent Versions System). The latter is a version control system client-server that allows multiple people to work simultaneously on a single set of files. This method allows for the latest update sources. In our case, since we will work with a little packet of old and whose changes are included in the next higher versions, CVS is not used.
2. The first package to be compiled because the compiler is GCC binutils depends on the tools of it to create executables. Indeed, this is binutils which assembles the object files generated by GCC in an executable image,
3. We need the functions header of the Linux kernel specifically for the ARM architecture. They contain essential functions such as system calls to interact with the kernel. These headers are used to produce the C library (glibc) for ARM,
4. Formal credit We will compile a GCC compiler depleted basic functions. Often called "bootstrap GCC", the compiler is still able to produce a library for ARM using Glibc functions of the kernel headers from the previous step,
5.t We use our "bootstrap GCC" to produce the file header of Glibc,
6, We get a C library function for ARM.
6. We have all the tools to start designing our next GCC compiler for ARM,
4. We compile the GMP and MPFR math libraries for ARM,
9. Finally, we compile the final GCC with previous libraries.
4) The alchemy of different versions of components of a cross toolchain
For the generation of a chain "from scratch", you have to hand all the previous steps. Versions of the various components work well with only a few patches:
- The Linux kernel 2.6.28.3 in its version, downloadable from the address http://www.kernel.org/pub/linux/kernel/v2.6/ ,
The other ingredients are downloadable from the address: http://ftp.gnu.org/gnu/ ,
- Binutils in its version 2.20,
- GCC version 4.3.3,
- Glibc in version 2.9,
- Glibc-ports in its version 2.9,
- GMP version 4.3.2,
- MPFR version in 3.0.1:
5) Get a cross-toolchain "From Scratch"
a) Introduction
This procedure is inspired by the book "Pro Linux Embedded Systems" by Gene Sally by Apress. There is also here and there web sites more or less serious that get a toolchain smoothly and without patch. I confess to being very cautious about getting a chain smoothly and without a shadow of one patch. Here is detailed, with patch, all the compiler options and each step is discussed.
The compilation of the chain was performed in a PC which is running a 64 bit Ubuntu 4.11. The elements of the host system interfere little in the construction of the chain, but it should be clarified version of the various components installed:
- Binutils in its version 2.21,
- GCC version 4.5.2,
- Glibc in version 2.13,
- Glibc-ports in the version 2.13,
- GMP version 4.3.2,
- In its MPFR version 3.0.0.
For reasons of convenience, we will use two terminals to generate our cross toolchain. These terminals can be called T1 and T2. Both terminals have similar environment variables. However, the terminal T2 advantage of environment variables to facilitate the compilation. In each terminal, enter the following common environment variables:
export SRCDIR=/root/chaine/sources
This directory home all sources downloaded.
export BUILDDIR=/root/chaine/build
It is in this directory that will compile all source packages.
export TARGETMACH=arm-none-linux-gnueabi
This variable specifies the type of target architecture.
export BUILDMACH=x86_64-pc-linux-gnu
This variable specifies the type of architecture in which the package is compiled.
export INSTALLDIR=/opt/arm
This variable provides information about the folder hosting the cross-toolchain.
export SYSROOTDIR=/opt/arm/sysroot
This variable provides information on the directory hosting the libraries and header files the kernel of the target system.
T2 to add more environment variables as follows:
export CROSS=arm-none-linux-gnueabi
Indicates that we use the variable fields CROSS with arm-none-linux-gnueabi.
export CC=${CROSS}-gcc
Indicates that we use the GCC compiler for the ARM architecture.
export LD=${CROSS}-ld
Indicates that we use the dynamic library of the ARM architecture.
export AS=${CROSS}-as
Indicates that we use the assembler of the ARM architecture.
b) Compilation of Binutils
The first package to be compiled is Binutils. Its compilation is not a problem and is fast. From the terminal T1, let's type the following lines:
mkdir $BUILDDIR/binutils
cd $BUILDDIR/binutils
../../sources/binutils-2.20/configure \
--disable-werror \
--build=$BUILDMACH \
--prefix=$INSTALLDIR \
--with-sysroot=$SYSROOTDIR \
--target=$TARGETMACH
make
make install
-> A few explanations:
Parameters | Fonction |
--disable-werror |
Disabling "warning": avoid blocking the compilation |
--build=$BUILDMACH |
Architecture of the host PC which is the compilation |
--prefix=$INSTALLDIR |
Home directory of the executable |
--with-sysroot=$SYSROOTDIR |
Home directory of booksellers |
--target=$TARGETMACH |
Target architecture |
c) kernel header files
Compiling the kernel header files generates an error due to a function name reused by different codes when compiling. Open the file linux-2.6.28.3/script/unifdef.c
by an editor like vim. Change the function name by removing the letter "e" of the name of the function getline()
in getlin()
. You can complete the transaction by directly applying the patch unifdef.c.patch . It simply copy this patch into the directory linux-2.6.28.3/script/
, to go to that directory and apply it by typing: patch < unifdef.c.patch
Now, the compilation and installation is done without hassle.
From the terminal T1, let's type the following lines:
cd $SRCDIR/linux-2.6.28.3
make mrproper
make ARCH=arm kb9202_defconfig
make ARCH=arm headers_check
make ARCH=arm INSTALL_HDR_PATH=$INSTALLDIR/sysroot/usr headers_install
-> A few explanations:
Option ARCH=arm
accurate, of course, the type of target architecture. We will use this string for the card (a little older, I admit) KwikByte KB9202C which is, unfortunately, more for sale on the manufacturer's website http://www.kwikbyte.com
That is why we specify its use by the entrance kb9202_defconfig
. This file includes all the options for the Linux kernel map. To map a generic ARM: Option integrator_defconfig
brings together all the common options of the kernel for all ARM. In the kernel directory linux-2.6.28.3/arch/configs/
, we can see all cards natively taken into account by the kernel.
d) Bootstrap GCC
Before proceeding with the compilation and installation of primer GCC (bootstrap GCC), ensure that the GMP and MPFR math libraries are installed in your Linux system.
The GMP library (download at: http://gmplib.org ), contains arithmetic functions to multi-particulars. It is used mainly in research in cryptography and algebraic. GMP is defined as a Debian / Ubuntu as the package to download / install via the Synaptic package manager. The packages are:
- libgmp3c2
(C library),
- libgmp3-dev
(C libraries and C + +),
- lib32gmp3-dev
(C libraries and C + + in 32-bit)
- libgmpxx4ldbl
(C + + library).
The MPFR library (download at: http://www.mpfr.org ), contains mathematical functions that can perform calculations multi clarification floating point with rounded accurate. It is maintained by Laurent Fousse ( laurent@komite.net ) professor at Grenoble.
The library is downloadable and installable under Debian / Ubuntu, in the form of package via Synaptic:
- libmpfr4
(Main Library)
- libmpfr-dev
(header functions needed for compiling)
- lib32mpfr4
(32-bit version)
- lib32mpfr-dev
(header functions required to compile in 32-bit version).
From the terminal T1, let's type the following lines:
mkdir $BUILDDIR/amorce-gcc
cd $BUILDDIR/amorce-gcc
../../sources/gcc-4.3.3/configure \
--build=$BUILDMACH \
--host=$BUILDMACH \
--target=$TARGETMACH \
--prefix=$INSTALLDIR \
--without-headers \
--enable-bootstrap \
--enable-languages=c \
--disable-threads \
--enable-__cxa_atexit \
--disable-libmudflap \
--with-gnu-ld \
--with-gnu-as \
--disable-libssp \
--disable-libgomp \
--disable-nls \
--disable-shared
make all-gcc install-gcc
make all-target-libgcc install-target-libgcc
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a \
/opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc_sh.a
-> A few explanations:
Most settings entered on the command line disable a number of options not required for the design of a standard library.
Parameters | Fonction |
--without-headers |
not compile with the headers in comment |
--enable-bootstrap |
mode activation "bootstrap" |
--enable-languages=c |
we compile for the C language and it is also possible to compile the C + + |
--disable-threads |
Disabling include files multithreaded because they have not yet been created for the target architecture. GCC will be able to find information on multi-threaded after the headers are created Glibc library |
--enable-__cxa_atexit |
option describing the implementation of the function atexit () |
--disable-libmudflap |
library used for complex débuger errors in a userspace program. Not necessary here. |
--with-gnu-ld |
Compiling with native linker |
--with-gnu-as |
Compiling with native assembler |
--disable-libssp |
deactivation of the bookstore that specializes in memory or stack overflow |
--disable-libgomp |
Disabling the OpenMP API specialized in parallel computing |
--disable-nls |
Disabling all local languages except English (POSIX) |
--disable-shared |
native compiler (GCC bootstrap) will not support dynamic libraries time to design the final GCC compiler. |
Command |
Explanation |
make all-gcc install-gcc |
created the basic compiler and installs it in the directory specified by the variable $ INSTALLDIR |
make all-target-libgcc install-target-libgcc |
Construction of a core library used by GCC to produce code. This library must be built before the final because it depends entirely on it. |
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc_sh.a |
By this symbolic link, we force the design of the library of static toolchain. |
e) Creation of header files from glibc
configure.patch
(applicable in the root of glibc-2.9
).gen-sorted.awk.patch
. (Applicable in the directory glibc-2.9/scripts/
).mkdir $BUILDDIR/libc-header
cd $BUILDDIR/libc-header
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" » config.cache
export PATH=$INSTALLDIR/bin:$PATH
../../sources/glibc-2.9/configure \
--build=$BUILDMACH \
--host=$TARGETMACH \
--prefix=$SYSROOTDIR/usr \
--with-headers=$SYSROOTDIR/usr/include \
--config-cache \
--enable-add-ons=glibc-ports-2.9,nptl \
--enable-kernel=2.6.0
make -k install-headers cross_compiling=yes install_root=$SYSROOTDIR
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a \
/opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc_eh.a
Parameters | Fonction |
--prefix=$SYSROOTDIR/usr |
Home directory of the executable. |
--with-headers=$SYSROOTDIR/usr/include |
Use of the headers of the core of step c). |
--config-cache |
Force the executable configure to read the instructions file config.cache |
--enable-add-ons=glibc-ports-2.9,nptl |
Using the additional library glibc-ports for ARM (our case). Also valid for MIPS and PowerPC. |
--enable-kernel=2.6.0 |
Design of the library to the Linux kernel 2.6.0 kind. |
Command | Explanation |
echo "libc_cv_forced_unwind=yes" > config.cache |
The file config.cache contains these two lines that prevent the execution of code compiled for ARM toolchain with cross installed on the host which is the x86. |
make -k install-headers cross_compiling=yes install_root=$SYSROOTDIR |
The header files are cross-compiled and installed into the $SYSROOTDIR |
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a \ |
Same here: by this symbolic link, we force the design of the library of static toolchain. |
mkdir $BUILDDIR/glibc
cd $BUILDDIR/glibc
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" » config.cache
../../sources/glibc-2.9/configure \
--build=$BUILDMACH \
--host=$TARGETMACH \
--prefix=/usr \
--with-headers=$SYSROOTDIR/usr/include \
--config-cache \
--enable-add-ons=glibc-ports-2.9,nptl \
--enable-kernel=2.6.0
make -k install-headers cross_compiling=yes install_root=$SYSROOTDIR
make
make install_root=$SYSROOTDIR install
mkdir $BUILDDIR/gcc
cd $BUILDDIR/gcc
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" » config.cache
export CC=gcc
../../sources/gcc-4.3.3/configure \
--build=$BUILDMACH \
--target=$TARGETMACH \
--prefix=$INSTALLDIR \
--with-sysroot=$SYSROOTDIR \
--enable-languages=c \
--with-gnu-as \
--with-gnu-ld \
--disable-multilib \
--with-float=soft \
--disable-sjlj-exceptions \
--disable-nls \
--enable-threads=posix \
--enable-long-longx
make all-gcc
make install-gcc
Parameters | Fonction |
export CC=gcc |
The environment variable forces the compiler for ARM GCC compiler of the host. |
--disable-multilib |
Different variants for different library arhitecture different is not designed. |
--with-float=soft |
Support for floating point numbers emulated by the software because the ARM have no FPU (Floating Point Unit) |
--disable-sjlj-exceptions |
Exceptions specific to C + +, they should be seen off our string only supports C. |
--enable-threads=posix |
Threads are POSIX format |
--enable-long-longx |
C, support for long integers |
/opt/arm/lib
mkdir $BUILDDIR/gmp
cd $BUILDDIR/gmp
export CFLAGS=-static
../../sources/gmp-4.3.2/configure \
--build=$BUILDMACH \
--host=$TARGETMACH \
--prefix=$INSTALLDIR \
--disable-shared
make
make install
mkdir $BUILDDIR/mpfr
cd $BUILDDIR/mpfr
../../sources/mpfr-3.0.1/configure \
--build=$BUILDMACH \
--host=$TARGETMACH \
--prefix=$INSTALLDIR \
--with-gmp=$INSTALLDIR
make
make install
CC=gcc
). This is a rather long operation.mkdir $BUILDDIR/gcc-final
cd $BUILDDIR/gcc-final
export CC=gcc
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" » config.cache
../../sources/gcc-4.3.3/configure \
--build=$BUILDMACH \
--target=$TARGETMACH \
--prefix=$INSTALLDIR \
--with-sysroot=$SYSROOTDIR \
--enable-languages=c \
--with-gnu-ld \
--with-gnu-as \
--disable-multilib \
--with-float=soft \
--disable-sjlj-exceptions \
--disable-nls \
--enable-threads=posix \
--disable-libmudflap \
--disable-libssp \
--enable-long=longx \
--with-shared \
--with-gmp=$INSTALLDIR \
--with-mpfr=$INSTALLDIR
make
make install
/opt/arm/arm-none-linux-gnueabi/lib
. The cross toolchain is in the directory /opt/arm/bin
. In the terminal T1, we can add the executables of cross-toolchain in the environment variable PATH
by typing: export PATH=$INSTALLDIR/bin:$PATH
6) Test of the cross-toolchain "From Scratch"
Do a test build with our newly installed chain. We will compile the program celebrates Helloworld that just prints a terminal in the message "Hello World".arm-none-linux-gnueabi-gcc -o helloworld helloworld.c
file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped