Artisan Numérique

/vintage/zaurus/ Construire l'environnement de Cross-Compilation pour pdaXrom

Le cross-compiler fournit avec pdaXrom est un vrai bonheur. Il permet de récupérer des sources d'applications manquantes dans la distribution et de les compiler de sort à être exécutable directement sur le Zaurus. Le "petit" tutorial suivant permet de mettre cela en oeuvre.

Qu'est-ce donc qu'une cross-compilation ?

Tout d'abord, prérequis de base, tout ce qui suit ne fonctionne que sous Linux. Quelques aventureux peuvent tenter l'équivalent sous cygwin mais je n'ai aucune idée sur la viabilité d'une telle chose. Pour ma part, j'utilise une Mandriva 2007.1 qui contient tout ce qui me sera nécessaire.

La cross-compilation permet dans sur une machine spécifique (hôte) de fabriquer des binaires pour une autre machine spécifique (cible). L'hôte est donc ici la Mandriva sur architecture i586 et la cible pdaXrom sur architecture ARM (le cpu du Zaurus). Pour pouvoir effectuer une telle opération, il faut donc disposer d'un compilateur (gcc) et l'ensemble des outils qui va avec (appelé tool-chain) qui s'exécute sur un i586 mais qui fabrique des binaire ARM. Une telle tool-chain est généreusement fournit avec pdaXrom . Il contient gcc, les utilitaires associés mais aussi toutes les librairies de base pour compiler une application moderne (gtk, qt, X, etc.).

Dans la majorité des cas, un système linux est installé avec sa propre tool-chain et ses propres librairies. C'est le cas de la Mandriva et l'on comprends sans peine qu'un des "danger" de la cross-compilation, est que le compilateur s'emmêle les pattes entres les librairies i586 de l'hôte et celles de pdaXrom (binaires ARM). La résolution de ce problème passe d'abord par une habile manipulation des variables d'environnements pour tromper le systèmes (PATH, LD_LIBRARY_PATH, etc...). Le plus gros de la magie est ensuite pris en charge par l'utilitaire de configuration fournit avec les sources qui va générer les scripts de construction qui vont bien (chaîne automake, autoconf). C'est grâce à cela qu'une application qui n'avait jamais été pensée pour cela peut finir sur l'écran de notre Zaurus préféré.

Installation du kit de cross-compilation de pdaXrom

La première chose à faire est d'installer cross-sdk-armv5tel-cacko-linux-3.4.6-2.2.5-softfloat.tar.bz2 (le lien est mort..) dédié à la cross-compilation. Ce paquet est à décompresser à la racine, donc en tant que root. Les commandes suivantes vont se charger de cette tâche et le cross-compiler pdaXrom sera installé en /opt/cross.

sudo su -
cd /
wget http://www.pdaxrom.org/download/1.1.0r121/Zaurus-7x0-860/cross-sdk-armv5tel-cacko-linux-3.4.6-2.2.5-softfloat.tar.bz2
tar -jxvf sources/cross-sdk-armv5tel-cacko-linux-3.4.6-2.2.5-softfloat.tar.bz2
chmod gou+rX /opt/cross -R
exit

Voilà, nous avons maintenant en /opt/cross un ensemble assez important de fichiers comprenant toutes les librairies ainsi que le fameux compilateur de binaire pour architecture ARM. Il ne reste plus qu'à passer à l'action :)

Création de l'environnement de compilation

Une fois le kit installé, nous allos créer notre environnement de compilation d'application pdaXrom pour Zaurus. Tout ce qui suit n'a pas besoin d'être effectué en tant que root. En tout premier lieu, il faut créer sur l'ordinateur hôte un dossier qui va tout contenir. Dans cet exemple, le dossier sera ~/pdaXrom. Nous allons ensuite créer les dossiers suivants :

# création de la racine
mkdir ~/pdaXrom
cd ~/pdaXrom

# dossier contenant les tarballs
mkdir sources

# dossier contenant les ipk
mkdir feed

# dossier contenant les sources en cours de compilation
mkdir build

# nos futurs scripts d'automatisation
mkdir script

Création du script d'initialisation

Pour éviter de se perdre dans les commandes à taper, un petit script à lancer avant toute compilation va nous être bien utile. Il va initializer un certain nombre de variable d'environnement et nous placer dans un sous-shell nous permettant de nous concentrer sur le seul portage. Une fois votre session de compilation terminé, il suffira de tape exit pour revenir à votre environnement normale.

Le script est à stocker dans le fichier ./script/start.sh :

  # recherche de la racine de notre builder
  pushd $(dirname $0)/.. > /dev/null
  export BUILDER_HOME=$PWD
  popd > /dev/null

  # Définition des divers variables de compilation
  export CROSS_COMPILER_HOME=/opt/cross/arm/3.4.6-xscale-softvfp
 export PATH=$CROSS_COMPILER_HOME/bin:$PATH
 export QTDIR=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/qt
 export KDEDIR=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/qt
 export X11INC=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/include
 export X11LIB=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/lib
 export PKG_CONFIG_PATH=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/lib/pkgconfig:/usr/lib/pkgconfig
 export CPPFLAGS="-O3"
 export CFLAGS="-O3"
 export LD_LIBRARY_PATH=$CROSS_COMPILER_HOME/lib:$CROSS_COMPILER_HOME/i686-host-linux-gnu/armv5tel-cacko-linux/lib
 export LDFLAGS="-Wl,-rpath-link,$CROSS_COMPILER_HOME/armv5tel-cacko-linux/X11R6/lib,-L/usr/lib"
 export DEFAULT_CONFIGURE_OPTIONS="-host=armv5tel-cacko-linux --build=i686-linux --x-includes=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/X11R6/include --x-libraries=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/X11R6/lib --oldincludedir=$CROSS_COMPILER_HOME/armv5tel-cacko-linux/include"
 export QMAKESPEC="$CROSS_COMPILER_HOME/armv5tel-cacko-linux/qt/mkspecs/default"
 export CC=$CROSS_COMPILER_HOME/bin/armv5tel-cacko-linux-gcc
 export ac_cv_func_getpgrp_void=yes
 export ac_cv_func_setpgrp_void=yes
 export ICONV="/usr/bin/iconv"

  # fin du script, lancement d'un shell imbriqué
  echo "Taper exit pour sortir de l'environnement de cross-compilation."
  export PS1='pdaXrom/ARM [\W] $ '
/bin/bash --noprofile --norc

Une fois ce fichier créé, lui donner l'attribut "exécutable" et le lancer :

chmod +x script/start.sh
./script/start.sh

Une invite vous indique que vous êtres dans l'environnement de cross-compilation, vous êtes maintenant près à compiler votre première application pour Zaurus...

Récupération des sources à compiler

L'exemple que je vais prendre est la dernière version d'OpenBox que nous allons créer de toute pièce :

La première étape est donc de récupérer les deux paquets de source :

cd sources
wget http://icculus.org/openbox/releases/openbox-3.4.4.tar.gz
cd ../build
tar -zxvf ../sources/openbox-3.4.4.tar.gz

Compilation

Cette étapes est somme toute classique pour qui a déjà compilé une application sous linux. Elle consiste en la classique trinité config/make/make install.

cd openbox-3.4.4
./configure $DEFAULT_CONFIGURE_OPTIONS --prefix=$PWD/dist/usr

Un ensemble de test va alors s'afficher pendant un certain temps. L'utilitaire est en train de vérifier que toutes les librairies nécessaire à la compilation sont bien présente sur la machine. Il va ensuite fabriquer les scripts de compilation. Notez le $DEFAULT_CONFIGURE_OPTIONS qui est une variable initialisée par notre script de démarrage. Elle contient un tas d'option permettant à la compilation de se passer correctement et à vous d'en taper le moins possible ;-)

Autre détail important, le paramètre --prefix. Nous allons grâce à lui forcer l'installation de la librairie à se faire dans le sous dossier ./dist/usr. C'est très important car sinon l'installation des librairies se feraients dans votre linux (en /usr...) et là, bonjour l'horreur ;-)

Sans options complémentaires le configurateur va désactiver de nombreuses options de pilot-link (support Java, Perl, etc...). C'est normal donc que ces choix se reflettent dans le résumé. Si vous lancez ./configure --help vous aurez une liste des options activables si vos besoins sont plus spécifiques.

Il est maintenant temps de compiler notre application:

make

Avec une machine rapide, cette opération ne prends qu'une grosse minute pour se terminer (espérons le ;-) sans erreurs. Il ne reste alors plus qu'à générer une installation :

make install

L'opération est rapide. Une fois que l'utilitaire vous rends la main, vous pouvez vérifier que la compilation s'est correctement déroulée en tapant :

file  dist/usr/lib/libobrender.so.16.0.1
> dist/usr/lib/libobrender.so.16.0.1: ELF 32-bit LSB shared object, ARM, version 1, not stripped
ls -la dist/usr/lib/libobrender.so.16.0.1
> -rwxr-xr-x 1 ulhume ulhume 94762 aoû 11 16:24 dist/usr/lib/libobrender.so.16.0.

Nos fichiers sont donc bien installés. Essayons d'optimiser un peu tout cela.

Optimisation de l'installation

#

Enlever les fichiers qui ne "servent à rien"

Avant toute chose, nous devons penser à optimiser l'espace occupé par nos paquets Zaurus. La place y est grandement comptée. Pour cela deux opérations. D'abord enlever ce qui n'est pas absolument utile, ici le manuel :

rm -rf dist/usr/share/man

Il y aurait encore du ménage à faire dans le même dossier, je vous laisse optimiser cela à votre goût mais faite attention de ne rien enlever de "vitale"

Optimisation des binaires

Ensuite nous pouvons optimiser la taille des binaires eux-même. C'est le rôle de la commande strip que nous pouvons efficacement combiner avec la commande find :

find dist -perm /u=x,g=x,o=x -exec armv5tel-cacko-linux-strip {} \;

Ne pas tenir compte des erreurs dans la mesure où strip râle lorsque je lui passes des fichiers non binaires :)

Nous pouvons vérifier le résultat en retappant les commande précédentes :

file  dist/usr/lib/libobrender.so.16.0.1
> dist/usr/lib/libobrender.so.16.0.1: ELF 32-bit LSB shared object, ARM, version 1, stripped
ls -la dist/usr/lib/libobrender.so.16.0.1
> -rwxr-xr-x 1 ulhume ulhume 80100 aoû 11 16:24 dist/usr/lib/libobrender.so.16.0.

Nous constatons alors que la commande files qui donnait le fichier comme non stripped, le donne maintenant comme stripped. Et que sa taille a perdu plus de 14ko, ce qui n'est pas mal du tout !!

Séparation des packages

Vous l'avez déjà remarqué, une même application est souvent déclinée en plusieurs paquets ayant chacun son rôle. Généralement nous avons le paquet de l'application elle-même, celui des documentations, celui de développement. L'objectif étant de n'installer que le stricte minimum. Nous allons donc faire de même et créer deux paquets, l'un pour l'application openBox, l'autre pour les fichiers qui permettent de compiler des applications utilisant openbox.

Nous alons partir du principe que ./dist contiendra les fichiers de l'application seule. Nous allons donc créer un dossier au même niveau nommé dist-devel dans lequel nous allons déplacer les fichiers liés au développement.

mkdir -p dist-devel/usr
mv dist/usr/include dist-devel/usr/

Voilà, nous avons maintenant deux dossiers dist. Nous pourrions aller beaucoup plus loin en créant par exemple un dossier dist par langue (/usr/share/locale/), un autre contenant les themes d'openBox, etc.

Création des packets IPK

Il ne reste plus qu'à fabriquer le fichier .ipk. Pour cela, créons dans le dossier dist, le dossier CONTROL dans lequel nous écrirons un fichier control contenant les informations suivantes :

Package: OpenBox
Installed-Size: 1.3M
Filename: ./openbox-3.4.4.ipk
Version: 3.4.4
Depends:
Priority: optional
Section: system
Maintainer: site.artisan@_bad_karma-lab.net (remove _bad_ to send an email)
Architecture: armv5tel
Description: OpenBox le gestionnaire de fenêtres

Comme nous avons aussi un dist-devel, nous allons y répéter l'opération en mettant cette fois FileName: ./openbox-devel-3.4.4.ipk

Il ne reste plus qu'à lancer la commande mkipkg pour produire notre deux fichiers ipk dans le dossier ../../feed

mkipkg dist ../../feed
mkipkg dist-devel ../../feed

Et le tour est joué!! Vous pouvez vérifier dans le dossier feed, les deux paquets devraient y être. Il ne reste plus qu'à installer le nouvel ipk dans Zaurus.