La cross-compilation

La technique consistant à compiler pour un autre environnement que le sien se nomme cross-compilation.

Sous Gentoo, il existe un utilitaire qui permet de définir des environnements de compilation différents du sien.

Cet utilitaire se nomme crossdev.

Si vous n'êtes pas sous Gentoo, c'est peut être l'occasion de se poser la question d'y passer. La cross-compilation n'est pas un sujet trivial lorsqu'on ne possède pas les outils adaptés.

Comme d'habitude, cet article comprend le strict minimum pour installer un environnement de compilation. Pour les détails (qui sont fort intéressants), vous devrez vous référer à la documentation Gentoo.

Tout savoir sur la cross-compilation Gentoo

How-To spécifique MinGW

HowTo spécifique MinGW et SDL


Quelques définitions

  • cross compilation : compilation pour un autre système que le sien (que ce soit du point de vue de l'OS ou du matériel).
  • toolchain : l'ensemble des utilitaires nécessaires à une cross compilation.
    • Un toolchain typique comprends:les binutils, les compilateurs spécifiques à la plateforme, un débugger, plus éventuellement quelques particularités propres au système cible (libc pour systèmes embarqués par exemple).
  • host system : le système utilisé pour la cross compilation.
  • target system : le système cible de la compilation.
  • sysroot : correspond à un répertoire du host system dans lequel la toolchain est installée.
    • Ce répertoire va servir de racine à un système de fichier simulant l'environnement du système cible, et permettra la création de binaires pour celui-ci.
    • c'est à partir de ce répertoire racine que le compilateur va chercher ses includes et ses libs.
  • crossdev : utilitaire Gentoo servant à mettre en place les environnements de cross compilation.
  • overlay : ceci ne concerne pas spécifiquement la cross-compilation. Un overlay (=une couche) est un ensemble d'ebuilds Gentoo qui ne font pas partie des ebuilds officiels de l'arbre portage. Un overlay correspond donc à une série d' ebuilds additionels.


Utilitaires Gentoo

  • binutils-config : pour gérer les versions slottées des binutils
    • Exemple affichant la liste des binutils installés:
~$ binutils-config -l
[1] i686-pc-linux-gnu-2.16.1 *


  • gcc-config : pour gérer les compilateurs installés
    • Exemple affichant la liste des compilateurs installés:
~$ gcc-config -l
 [1] i686-pc-linux-gnu-4.1.1 *


  • crossdev : compile et installe les toolchains pour une plateforme supportés par GCC.
  • qpkg : créer des paquets binaires pour des ebuilds cross-compilés sur le sysroot.


Installation des paquets nécessaires

  • emerge -va portage-utils
  • emerge -va crossdev
  • emerge -va layman : va permettre de gérer les overlays (lister et installer)
    • layman -S équivaut à emerge --sync, mais pour les overlays.
    • layman -L va lister les overlays disponibles.
    • layman -a overlay-name pour ajouter un des overlays listé précédemment (il faut les ajouter soi-même).
    • layman -i toolchain pour avoir des informations sur un overlay particulier (ici, toolchain).
  • important : une fois votre premier overlay ajouté, insérer cette ligne dans make.conf :
    • source /usr/portage/local/layman/make.conf
    • il ne faut surtout pas l'insérer avant d'avoir sélectionné votre premier overlay, sinon portage échouera.
    • on peut choisir un autre path en modifiant le fichier de config /etc/layman/layman.config
  • Je ne m'étends pas plus sur le sujet, car pour l'exemple développé ici (installation de la toolchain mingw32), nous n'aurons pas besoin des overlays de toolchain.
    • Les overlays de toolchain seront donc à réserver aux environnements de cross-compilation plus exotiques.
  • Par contre, pensez à ajouter (si ce n'est pas déja fait) dans votre make.conf:
    • echo 'PORTDIR_OVERLAY="/usr/local/portage"' >> /etc/make.conf
    • Ceci vous permettra d'utiliser par la suite vos ebuild "fait maison" (les overlays).


Nommage des toolchains

  • Les toolchains sont désignées par des tuples :
    • machine-vendor-kernel-operating system
  • quelques exemples de valeurs pour les tuples (voir la doc pour toutes les possibilités).
    • machine  : ia64, i686, x86_64 , ...
    • vendor : pc parait le plus logique
    • kernel : mingw32 ou mingw64 pour les MS-Windows 32/64 bits
    • operating system : gnu (tous les OS qui possèdent une glibc)
  • Donc, pour compiler pour un cpu générique (mais récent) vers un Windows 32 bits, la toolchain devrait se nommer:
    • i686-pc-mingw32-gnu
  • sauf que ... si vous utilisez cette chaine, crossdev va échouer et vous aurez dans le log:
    • checking target system type... Invalid configuration `i686-pc-mingw32-gnu': machine `i686-pc-mingw32' not recognized
  • Donc, nous utiliserons: i686-mingw32


Construction d'une toolchain

  • Nous allons utiliser crossdev
  • Ne vous inquiétez pas si vous faites une erreur dans la création de la toolchain, chaque toolchain est isolée des autres: une erreur ne cassera pas votre système de base.
  • Nous reprenons la toolchain du paragraphe précédent: i686-mingw32 , en stage 3 (pour gagner du temps).
    • Je rappelle que le stage 3 ne comprend pas le compilateur C++.
~ # crossdev -s3 --target i686-mingw32
--------------------------------------------------------------------------------
 * Host Portage ARCH:     x86
 * Target Portage ARCH:   x86
 * Target System:         i686-mingw32
 * Stage:                 3 (C compiler & libc)

 * binutils:              binutils-[latest]
 * gcc:                   gcc-[latest]
 * headers:               w32api-[latest]
 * libc:                  mingw-runtime-[latest]

 * PORTDIR_OVERLAY:       /usr/local/portage
 * PORT_LOGDIR:           /var/log/portage
 * PKGDIR:                /usr/portage/packages/cross/i686-mingw32
 * PORTAGE_TMPDIR:        /var/tmp/cross/i686-mingw32

 * Forcing the latest versions of {binutils,gcc}-config/gnuconfig ...     [ ok ]
 * Log: /var/log/portage/cross-i686-mingw32-binutils.log
 * Emerging cross-binutils ...

etc...
  • par défaut, tous les utilitaires sont générés, des binutils au compilateur C (ou C++ si vous êtes en stage4)
    • soyez patients, même en stage3 c'est long.
    • tout est loggé bien sagement dans /var/log/portage/.
  • on peut également choisir sa version de la libc, de gcc, de binutils ...
    • par exemple, si vous avez des soucis avec gcc-4, vous pouvez repasser dans une version plus stable:
    • crossdev --gcc 3.4.2 -t i686-mingw32
    • (j'ai lu que gcc-4 posait problème lors de la création de bibliothèques partagées).
  • crossdev pour avoir un résumé des options


Tout s'est-il bien passé ?

  • Quelques tests de base pour s'assurer qu'il n'y a pas de gros soucis:
    • Tout d'abord, demander les infos de version du compilateur C
    • On remarquera avec intêret l'emplacement du sysroot
~$ /usr/bin/i686-mingw32-gcc -v
Utilisation des specs internes.
Target: i686-mingw32
Configuré avec: /var/tmp/cross/i686-mingw32/portage/cross-i686-mingw32/gcc-4.2.3/work/gcc-4.2.3/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/i686-mingw32/gcc-bin/4.2.3 --includedir=/usr/lib/gcc/i686-mingw32/4.2.3/include --datadir=/usr/share/gcc-data/i686-mingw32/4.2.3 --mandir=/usr/share/gcc-data/i686-mingw32/4.2.3/man --infodir=/usr/share/gcc-data/i686-mingw32/4.2.3/info --with-gxx-include-dir=/usr/lib/gcc/i686-mingw32/4.2.3/include/g++-v4 --host=i686-pc-linux-gnu --target=i686-mingw32 --build=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --disable-libunwind-exceptions --disable-libmudflap --disable-libssp --disable-libgcj --with-arch=i686 --enable-languages=c --disable-shared --with-sysroot=/usr/i686-mingw32 --disable-bootstrap --disable-libgomp
Modèle de thread: win32
version gcc 4.2.3 (Gentoo 4.2.3 p1.0)


  • Vous pouvez également vous promener dans le sysroot, afin de voir tout ce qui est installé.
    • Vous devriez trouver DirectX, mais également OpenGL, GLUT, et tout ce qui a trait à Win32 (sockets, WinMM, OLE etc..)
  • Compiler un "hello world"
    • Vous trouverez le source ci-dessous.
    • Compilez avec : /usr/bin/i686-mingw32-gcc -mwindows hello_mingw.c -o hello_mingw
    • Important : n'oubliez pas le flag -mwindows , autrement vous compilerez un programme console (ce qui peut servir pour la mise au point, mais a tendance à dérouter les utilisateurs dans la version de prod.)
#include <windows.h>

int WINAPI WinMain (HINSTANCE hInstance, 
      HINSTANCE hPrevInstance, 
      PSTR szCmdLine, 
      int iCmdShow) 
{
  MessageBox (NULL, "Win32 test", "Hello mingw32", MB_OK);
  return 0;
}
  • Plus qu'à tester votre hello world.
    • Avec Wine (pour les jusqu'au-boutistes).
    • Transfert vers un vrai MS-Windows (allez, faites vous plaisir).


Des regrets ?

  • Ca ne marche pas (j'adore cette expression qui désigne en général les problèmes situés entre la chaise et le clavier).
  • Vous n'en pouvez plus (ça m'arrive aussi).
  • Du passé, faisons table rase:
    • crossdev --clean i686-mingw32


Cela en vaut-il vraiment la peine ?

Pour les indécis et les incrédules, pensez simplement à ceci: mingw et les portages GNU sous MS-Windows sont certes très utiles, mais le principe de crossdev est de permettre de monter un environnement cohérent avec une chaine de développement complète et à jour.

Un autre gros avantage: vous n'avez plus besoin d'utiliser MS-Windows et vous pourrez programmer sur un système qui est pensé pour le développement.

Avec tout ça, si vous bootez encore sous MS-Windows, c'est que vraiment vous aimez ça.