Toolchain ========= Vorkompilierte Cross-Compiler ----------------------------- Viele Distributionen bieten in ihren Paketverwaltungssystem bereits fertige Binärpakte mit allen möglichen Cross-Compilern an. Wir werden an dieser Stelle die Installation auf Ubuntu, Arch-Linux und Gentoo vorstellen: Installation auf Ubuntu: .. code:: bash apt-get install gcc-arm-linux-gnueabi make ncurses-dev Installation auf ArchLinux: .. code:: bash # arm-linux-gnueabi-gcc in AUR Repository # use --force to avoid the already exists error of glibc files # tested on 11.06.2015 - Ferdinand Saufler yaourt -S --force arm-linux-gnueabi-gcc Installation auf Gentoo: .. code:: bash crossdev -S -v -t arm-unknown-linux-gnueabi Cross-Toolchain mit crosstool-ng -------------------------------- Eine weitere gute Möglichkeit um an eine Cross-Toolchain zu gelangen ist die Verwendung von crosstool-ng. Am besten ist es eine aktuelle Version von crosstool-ng direkt aus den Github Quellen zu bauen: .. code:: bash git clone https://github.com/crosstool-ng/crosstool-ng.git cd crosstool-ng ./bootstrap ./configure make sudo make install ARM-Toolchain mit crosstool-ng ______________________________ Bevor wir beginnen, können wir uns alle verfügbaren Konfigurationen anzeigen lassen: .. code:: bash ct-ng list-samples Wir wählen nun **arm-unknown-linux-gnueabi** aus und bauen die Toolchain: .. code:: bash ct-ng arm-unknown-linux-gnueabi ct-ng build Nach Abschluss findet man die Toolchain unter ``~/x-tools/arm-unknown-linux-gnueabi``. Cross-Toolchain selbst bauen ---------------------------- Die Erstellung einer eigenen ARM-Cross-Toolchain erfordert ein hohes Wissen die über die Konfiguration und das Zusammenspiel verschiedenster Softwarepakete. Zuerst sollte man sich mit der Build-Host-Target Thematik auseinandersetzen: * **Build Machine** Auf diesem Rechner wird die Toolchain "gebaut" * **Host Machine** Auf diesem Rechner wird die Toolchain ausgeführt * **Target Machine** Für diesen Typ von Rechner erzeugt die Toolchain ausführbaren Code An dieser Stelle unterscheiden wir noch 4 verschiedene Toolchain typen: * **Native Toolchain** Die Art von Toolchain läuft nativ auf einem System was bedeutet: Sie wurde für eine Architektur kompiliert, läuft auf dieser Architektur und erzeugt Code für diesen Architekturtyp. * **Cross Compilation Toolchain** Dieser Typ ist am interessantesten für Embedded Systems. Eine solche Toolchain wird beispielsweise für x86 kompiliert, läuft auf einem x86 System und erzeugt Code die Target Architektur (ARM, MIPS, PowerPC). * **Cross Native Toolchain** Dieser Typ könnte auf einem x86 System erzeugt worden sein, läuft aber auf der Target-Architektur und erzeugt Code für diese. * **Canadian Build / Canadian Cross Toolchain** Hierbei handelt es sich um den ausgefallensten Typ, eine Canadian Cross Toolchain könnte auf einem x86 System kompiliert worden sein, auf einer ARM-Architektur laufen und dort Code für MIPS erzeugen. Grundlegende Komponenten einer Cross-Toolchain ---------------------------------------------- Allgemein besteht eine Toolchain immer aus vier grundlegenden Komponenten, so wird es auch bei unserer selbsterstellten Toolchain sein: * **Binutils** Die GNU-Binutils_. sind immer das erste Glied in der Kette. Sie beinhalten zwei wesentliche Komponenten: - *as*: den Assembler, der Assembler-Code in Maschinen-Code übersetzt - *ld*: den Linker, er linkt mehrere Objekte zu Bibliotheken oder ausführbaren Dateien zusammen. * **C, C++, Java, Ada, Fortran, Objective-C compiler** Die zweite Hauptkomponente einer Toolchain ist der Compiler. Ein möglicher Kandidat ist die GNU Compiler Collection, GCC_. Sie unterstützt als Input Programmierspachen wie C, C++, Java Fortran oder Objective-C und als Ausgabe eine Vielzahl von Architekturen. * **C-Bibliothek** Eine C-Bibliothek implementiert die POSIX-API die für Programme der Userspace-Ebene benötigt wird. Sie interagiert mit dem Kernel über System-Calls und stellt darüber hinaus weitere High-Level Funktionen bereit. Wichtige Vertreter bekannter C-Bibliotheken sind unter anderem: - GLibc_: Die am häufigigsten eingesetzte C-Bibliothek, die praktisch in jedem Desktop- und Server-System steckt. Sie bietet eine große Anzahl an Features ist dadurch aber auch etwas überladen. - uclibc_: eine glibc Alternative die den Fokus auf wenig Platz- und Speicherverbrauch legt. - newlib_: Die newlib ist eine speziell für Embedded Systms geschaffende Bibliothek, Sie wird von Redhat entwickelt und gewartet - musl_: Eine relativ junge c-Bibliothek. Motto: lightweight, fast, simple, free. * **Debugger** Der Debugger ist nicht zwingend zum Erstellen von Applikationen notwendig ist aber dennoch meist Teil der Toolchain. In der Embedded Linux Welt ist der gebräuchlichste Vertreter der GNU Debugger GDB_. Allgemeiner Ablauf ------------------ Im allgemeinen ist die Erstellung einer Toolchain ein wiederkehrender Ablauf, der die folgenden Punkte beinhaltet: 1. Verzeichnisstruktur anlegen 2. Quellen laden und entpacken 3. Spezifische Patches hinzufügen 4. Werkzeuge auf dem Hostrechner überprüfen 5. Für jedes ausgewählte Paket: Für den Host-/Targetrechner konfigurieren, kompilieren und installieren Reihenfolge der Paketkonfiguration ---------------------------------- Beim Bau einer Toolchain muss in der Regel eine bestimmte Reihenfolge eingehalten werden, da die resultierenden Komponenten auf einander aufbauen: 1. Binutils 2. GCC Stage 1 3. Linux API Headers 4. GCC Stage 2 5. C-Bibliothek (glibc, newlib, etc) 6. GCC Final Quellverzeichnis ---------------- Bevor wir uns den Paketen widmen legen wir uns ein Quellverzeichnis an das wir **tarballs** nennen. In dieses Verzeichnis werden alle \*.tar.gz Quelldateien der einzelnen Projekte geladen. .. code:: bash mkdir ~/tarballs export _tarballdir="${HOME}/tarballs" Binutils 2.25 ------------- Beginnen wir mit binutils, zuerst werden die Quellen heruntergeladen und entpackt: .. code:: bash cd _tarballdir wget http://ftp.gnu.org/gnu/binutils/binutils-2.25.tar.gz tar -xvf binutils-2.25.tar Nun fahren wir mit der Konfiguration und Installation fort: .. code:: bash export _target=arm-linux-gnueabi export _host=$(uname -m) export _basedir=$(pwd) export _pkgdir="${_basedir}/pkg" mkdir binutils-build cd binutils-build ../binutils-2.25/configure \ --prefix=/usr \ --with-lib-path=/usr/lib/binutils/${_target} \ --program-prefix=${_target}- \ --enable-shared \ --disable-multilib \ --with-local-prefix=/usr/lib/${_target} \ --with-sysroot=/usr/${_target} \ --disable-nls \ --target=${_target} \ --host=$_host \ --build=$_host \ --disable-werror make configure-host make tooldir=/usr rm -rf "$pkgdir" make prefix="$pkgdir/usr" tooldir="$pkgdir/usr" install rm -f "$pkgdir"/usr/bin/{ar,as,ld,nm,objdump,ranlib,strip,objcopy} rm -f "$pkgdir"/usr/lib/libiberty.a rm -rf "$pkgdir"/usr/{share,man} GCC 5.1.0 Stage 1 ----------------- Fahren wir fort mit der Gnu Compiler Collection - Phase 1 fort. .. code:: bash cd _tarballdir wget https://ftp.gnu.org/gnu/gcc/gcc-5.1.0/gcc-5.1.0.tar.gz tar -xvf gcc-5.1.0.tar.gz Konfiguration und Installation: .. code:: bash export _target=arm-linux-gnueabi export _host=$(uname -m) export CFLAGS="-O2 -pipe" export CXXFLAGS="-O2 -pipe" export _basedir=$(pwd) export _pkgdir="${_basedir}/pkg" mkdir gcc-stage1-build cd gcc-stage1-build ../gcc-5.1.0/configure \ --prefix=/usr \ --program-prefix=${_target}- \ --target=${_target} \ --host=$_host \ --build=$_host \ --disable-shared \ --disable-nls \ --disable-threads \ --enable-languages=c \ --enable-multilib \ --with-local-prefix=/usr/${_target} \ --with-sysroot=/usr/${_target} \ --with-as=/usr/bin/${_target}-as \ --with-ld=/usr/bin/${_target}-ld \ --enable-softfloat \ --with-float=soft \ --with-newlib \ --disable-libgomp \ --enable-interwork \ --enable-addons make all-gcc all-target-libgcc make DESTDIR="$pkgdir" install-gcc install-target-libgcc rm -rf "$pkgdir"/usr/share/man/man7/ rm -rf "$pkgdir/usr/share/info" cp -r "$pkgdir"/usr/libexec/* "$pkgdir/usr/lib/" rm -rf "$pkgdir/usr/libexec" # strip it manually strip "$pkgdir"/usr/bin/* 2>/dev/null || true find "$pkgdir"/usr/lib -type f -exec /usr/bin/${_target}-strip \ --strip-unneeded {} \; 2>/dev/null || true Linux 4.1.2 API Headers ----------------------- fahren wir mit den Linux API Headern fort: .. code:: bash cd _tarballdir wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.1.2.tar.xz tar -xvf linux-4.1.2.tar.xz Konfiguration und Installation: .. code:: bash export _basedir=$(pwd) export _pkgdir="${_basedir}/pkg" export _target_arch="arm" cd linux-4.1.2 make ARCH=${_target_arch} mrproper make ARCH=${_target_arch} headers_check make INSTALL_HDR_PATH="${_pkgdir}/usr/${_target}/" ARCH=${_target_arch} V=0 headers_install GCC 5.1.0 Stage 2 ----------------- Fahren wir fort mit der Gnu Compiler Collection - Phase 2 fort. .. code:: bash cd _tarballdir rm -rf gcc-5.1.0 tar -xvf gcc-5.1.0.tar.gz Konfiguration und Installation: .. code:: bash export _target=arm-linux-gnueabi export _host=$(uname -m) export CFLAGS="-O2 -pipe" export CXXFLAGS="-O2 -pipe" export _basedir=$(pwd) export _pkgdir="${_basedir}/pkg" mkdir gcc-stage2-build cd gcc-stage2-build ../gcc-5.1.0/configure \ --prefix=/usr \ --program-prefix=${_target}- \ --target=${_target} \ --host=$_host \ --build=$_host \ --disable-nls \ --enable-languages=c \ --enable-multilib \ --with-local-prefix=/usr/${_target} \ --with-sysroot=/usr/${_target} \ --with-as=/usr/bin/${_target}-as \ --with-ld=/usr/bin/${_target}-ld \ --enable-softfloat \ --with-float=soft \ --disable-libgomp \ --enable-interwork \ --enable-addons make all-gcc all-target-libgcc make DESTDIR="$pkgdir" install-gcc install-target-libgcc rm -rf "$pkgdir"/usr/share/{man/man7,info}/ cp -r "$pkgdir"/usr/libexec/* "$pkgdir"/usr/lib/ rm -rf "$pkgdir/usr/libexec" # strip it manually strip "$pkgdir"/usr/bin/* 2>/dev/null || true find "$pkgdir"/usr/lib -type f -exec /usr/bin/${_target}-strip \ --strip-unneeded {} \; 2>/dev/null || true Glibc 2.21 ---------- Fahren wir fort mit der Glibc fort. .. code:: bash cd _tarballdir wget http://ftp.gnu.org/gnu/glibc/glibc-2.21.tar.gz tar -xvf glibc-2.21.tar.gz Konfiguration und Installation: .. code:: bash export _target=arm-linux-gnueabi export _host=$(uname -m) export CFLAGS="-U_FORTIFY_SOURCE -mlittle-endian -msoft-float -O2" export CPPFLAGS="-U_FORTIFY_SOURCE -O2" unset LD_LIBRARY_PATH export BUILD_CC=gcc export CC=${_target}-gcc export CXX=${_target}-g++ export AR=${_target}-ar export RANLIB=${_target}-ranlib mkdir glibc-build cd glibc-build ../glibc-2.21/configure \ --prefix=/ \ --target=${_target} \ --host=${_target} \ --build=$_host \ --with-headers=/usr/${_target}/include \ --enable-add-ons \ --enable-obsolete-rpc \ --enable-kernel=2.6.32 \ --enable-bind-now \ --disable-profile \ --enable-stackguard-randomization \ --enable-lock-elision \ --enable-shared \ --with-tls \ --with-__thread \ --without-cvs \ --without-gd \ --disable-werror make make "install_root=${pkgdir}/usr/${_target}" install GCC 5.1.0 Final ----------------- Fahren wir fort mit der Gnu Compiler Collection - Final fort. .. code:: bash cd _tarballdir rm -rf gcc-5.1.0 tar -xvf gcc-5.1.0.tar.gz Konfiguration und Installation: .. code:: bash export _target=arm-linux-gnueabi export _host=$(uname -m) export CFLAGS="-O2 -pipe" export CXXFLAGS="-O2 -pipe" export _basedir=$(pwd) export _pkgdir="${_basedir}/pkg" mkdir gcc-final-build cd gcc-final-build ../gcc-5.1.0/configure \ --prefix=/usr \ --program-prefix=${_target}- \ --target=${_target} \ --host=$_host \ --build=$_host \ --enable-shared \ --disable-nls \ --enable-threads=posix \ --enable-languages=c,c++ \ --enable-multilib \ --with-sysroot=/usr/${_target} \ --with-build-sysroot=/usr/${_target} \ --with-as=/usr/bin/${_target}-as \ --with-ld=/usr/bin/${_target}-ld \ --enable-softfloat \ --with-float=soft \ --enable-interwork \ --disable-libgomp \ --enable-__cxa_atexit \ --enable-addons make all-gcc all-target-libgcc all-target-libstdc++-v3 make "DESTDIR=$pkgdir" install-gcc install-target-libgcc \ install-target-libstdc++-v3 rm -rf "$pkgdir"/usr/share/{man/man7,info}/ cp -r "$pkgdir"/usr/libexec/* "$pkgdir/usr/lib/" rm -rf "$pkgdir/usr/libexec" rm -rf "$pkgdir/usr/share/gcc-${pkgver}/python" # strip it manually strip "$pkgdir"/usr/bin/* 2>/dev/null || true find "$pkgdir"/usr/lib -type f -exec /usr/bin/${_target}-strip \ --strip-unneeded {} \; 2>/dev/null || true Vorgefertigte Toolchains ------------------------ Neben Toolchain-Baukästen und der Möglichkeit sich seine eigene Toolchain zusammenzustellen gibt es auch eine Handvoll vorgefertigter Toolchains, die man nur Installieren muss. * DENX ELDK_ (Embedded Linux Development Kit) Toolkit Sammlung der Firma Denx Software Engeneering * Scratchbox_ Scratchbox stellt Toolchains für ARM und x86 Target-Architekturen zu Verfügung. Es werden uClibc und glibc unterstützt. * CodeSourcery_ CodeSourcery stellt eine auf Eclipse basierende IDE zu Verfügung die mit GNU Toolchain ausgeliefert wird. * Linaro_ (ARM) Linaro Produkte sind optimierte Toolchains für diverse ARM CPUs Toolchain Baukästen ------------------- Mittlerweile gibt es eine beträchtliche Anzahl an Toolchain Baukästen, hier die wichtigsten Vertreter: * Buildroot_ Buildroot generiert Rootfile-System-Images fertig fürs Schreiben auf SD-Karte. Unter anderem stellt es auch eine Toolchain bereit um diese Pakete aus den Quellen zu kompilieren. * OpenADK_ OpenADK ist ein komplette Build System basierend auf dem Linux Kernel Konfigurations-System. Es unterstützt eine große Menge von Architekturen. * Crossdev (Gentoo) Crossdev ist ein Script, welches eine Toolchain generiert. Nur für Development-PCs auf denen Gentoo läuft. * Crosstool-NG_ Crosstool-ng ist ein gut geplegter Fork von crosstool. Leichte Konfiguration, unterstützt uClibc und glibc. * OSELAS.Toolchain()_ Die OSELAS.Toolchain benutzt PTXdist, ein Userland Build-System basierend auf Kconfig. Beides Produkte von Pengutronix. .. _GNU-Binutils: http://www.gnu.org/software/binutils/ .. _GCC: https://gcc.gnu.org/ .. _Glibc: http://www.gnu.org/software/libc/ .. _uclibc: http://www.uclibc.org/ .. _newlib: https://sourceware.org/newlib/ .. _musl: http://www.musl-libc.org/ .. _GDB: http://www.gnu.org/software/gdb/ .. _ELDK: http://www.denx.de/wiki/DULG/ELDK .. _Linaro: http://linaro.org/ .. _CodeSourcery: http://www.codesourcery.com/ .. _Scratchbox: http://www.scratchbox.org/ .. _Buildroot: http://www.buildroot.net/ .. _OpenADK: http://www.openadk.org/ .. _Crosstool-NG: http://crosstool-ng.org/ .. _OSELAS.Toolchain(): http://www.pengutronix.de/oselas/toolchain/index_en.html