Cross Compiler
Unter einem Cross-Compiler versteht man einen Compiler, der auf einem bestimmten System (auch Hostplattform genannt) läuft, aber Kompilate (Objektdateien oder ausführbare Programme) für andere Systeme erzeugt. Diese Ziel-Systeme können andere Betriebssysteme, andere Prozessoren oder eine Kombination der beiden sein. Ein konkretes Beispiel wäre ein Compiler, der auf einem Intel-basierten Windows-System läuft und Programme für PowerPC-basierte Linux-Systeme erzeugt. Handelt es sich bei der Zielplattform um ein eingebettetes System, das selbst nicht für Entwicklung und Übersetzung geeignet ist, spricht man auch von einem Target-Compiler.
Vorgestellt wird hier ein Cross-Compiler, der auf der auf unseren ARM-Boxen läuft und Code für Mips-Boxen erstellt. Motivation dazu ist, dass unsere 4k Boxen genügend Flash-Speicher und Hauptspeicher bereitstellen, dass ein Cross-Compiler für Mips problemlos neben einem ARM-Compiler auf den Boxen erstellt und installiert werden kann. Und natürlich, dass wir als Entwickler gerne beide von Vu+ bereit gestellten Architekturen unterstützen möchten, auch wenn wir selber nicht beide Architekturen im Zugriff haben.
Beispielhaft zeigt dieser Artikel die Installation und Benutzung des Cross-Compilers.
Inhaltsverzeichnis
Installation
In der Database haben wir einen Mips-Cross-Compiler für ARM-Boxen zur Verfügung gestellt. Dieser besteht aus mehreren Paketen :
- Binutils
- Compiler
- Grundstock an Include-Dateien und Libraries ("Sysroot").
Um Binaries für Mips-Boxen auf unseren ARM-Boxen zu erstellen, müssen alle drei Pakete installiert sein.
Nach dem Download der Pakete auf eine ARM-Box können die drei Pakete mit opkg install <Paket.ipk> wie jedes andere Paket auch installiert werden. Nach der Installation befinden sich unter /usr/bin diverse Programme mit dem Präfix mipsel-oe-linux- und unterhalb von /usr/mipsel-oe-linux das "Sysroot" mit Include-Dateien und Bibliotheken, um Mipsel-Binaries zu compilieren.
Benutzung
Beispielhaft wird jetzt die Benutzung des Cross-Compilers anhand eines Pakets beschrieben, welches ich oft und viel benutze: "grep".
Schritt 1: Sourcen besorgen
Die Sourcen für grep befinden sich auf dem GNU-FTP-Server unter https://ftp.gnu.org/gnu/grep/ - die momentan aktuelle Version ist grep-3.8. Die Sourcen werden von dort heruntergeladen und irgendwo auf der Festplatte der Box entpackt, z.B. unter /media/hdd/build. Ausgepackt wird in der Konsole (z.B. Putty) mit dem tar-Befehl: tar xvf grep-3.8.tar.gz
Schritt 2: Sourcen konfigurieren
Mit cd grep-3.8
wird in den ausgpackten Source-Tree gewechselt. Die meisten der heute benutzten Software-Pakete werden mit einem configure
konfiguriert; dieses schaut, ob alle benötigten Komponenten für ein erfolgreiches übersetzen vorhanden sind, und generiert die Makefiles, um das Programm anschließend zu übersetzen.
Um Makefiles benutzen zu können, benötigt man das make
-Programm. Ein fertig übersetztes Programm befindet sich in der Database beim aktuellen GCC für die ARM-Boxen.
Ein erster Versuch, den Cross-Compiler zu benutzen, ist immer, den Aufruf von configure
mit der CC
-Variablen zu testen; es gibt eine Reihe von Umgebungsvariablen, die man auf diese Weise (nicht nur) an das configure-Script weiterreichen kann. Ein paar weitere sind: CXX (c++-Compiler), CFLAGS (Flags für den C-Compiler), CXXFLAGS (Flags für den C++-Compiler)
CC=mipsel-oe-linux-gcc ./configure --prefix=/usr
Das funktioniert bei grep
nicht, die Fehlermeldung sagt, dass man den Compiler über den Switch --host=mipsel-oe-linux
angeben soll. Das funktioniert. Also zweiter Versuch:
./configure --host=mipsel-oe-linux --prefix=/usr
Der Switch --prefix=/usr
sagt der Umgebung, dass das fertig übersetzte Programm später nach /usr
installiert werden soll; das bedeutet, dass das Binary unter /usr/bin/grep
installiert wird. Ohne diesen Switch wird normalerweise /usr/local
als Ziel benutzt, und das Binary findet sich später unter /usr/local/bin/grep
.
Schritt 3: Compilieren
Als nächstes soll das Programm übersetzt werden; dazu wird make
aufgerufen:
make
Meistens dauert der Configure-Schritt genauso lange wie das eigentliche Übersetzen des Programms. Wenn beim Übersetzen keine Fehler passiert sind, kann das Programm installiert werden.
Schritt 4: Installation
Ich kontrolliere gerne vor dem installieren, was installiert werden soll. Fast alle Makefiles kennen das "Target" "install", viele können auch mit dem Target "install-strip" umgehen, und viele kennen auch eine Möglichkeit, das Programm in einem anderen Verzeichnis zu installieren. In der Regel wird das mit der Variablen DESTDIR
erreicht. Wir führen also aus:
make install-strip DESTDIR=/media/hdd/install
Das installiert das übersetzte Programm unterhalb von /media/hdd/install
, wo wir noch einmal schauen können, was wir mitnehmen möchten, und was nicht.
Schritt 5: Programm einpacken und testen
Der nächste Schritt ist bei mir immer, die Dateien als IPK einzupacken. Wie das gemacht werden kann, soll hier nicht gezeigt werden; dazu habe ich unter Paketmanager opkg schon einiges geschrieben.
Wir kontrollieren aber noch einmal, dass der Cross-Compiler ein Mipsel-Binary erstellt hat. Dazu wechseln wir in der Konsole mit "cd" nach /media/hdd/install/usr/bin
. Ein ls -l
zeigt hier drei Dateien an, egrep
, fgrep
und grep
. egrep und fgrep sind Shell-Scripten, das eigentliche Binary ist grep
. Wir können uns den Inhalt mit einigen Tools anschauen. Als erstes:
file grep
: Ausgabe sollte sein: grep: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 2.6.32, stripped
Schauen wir etwas genauer in das Binary:
mipsel-oe-linux-objdump -p grep
Hier sehen wir alle interessanten Informationen, zum Beispiel welche Shared-Libraries das Programm in welcher Version auf der Mips-Maschine benötigt.
Das Binary kann jetzt auf eine Mips-Box kopiert werden, um endgültig sicherzustellen, dass wir hier keinen Murks produziert haben.