Follow me
RSS feed
My sources
My Viadeo

Installer un environnement de cross compilation

Greg | 19 Feb 2011

Projets Quand on n'y a jamais été confronté, on a tendance à croire que la cross-compilation est un sujet compliqué. C'est oublié le côté primitif1 d'un compilateur. En effet, ce dernier n'est rien d'autre qu'un traducteur dont le rôle consiste à générer un code cible compréhensible par une machine donnée, à partir d'un code source. Dans cette définition, rien n'indique, à juste titre, que cette traduction doit être faite sur la machine à laquelle est destiné le code cible. Ainsi rien ne m'empêche d'installer, sur mon Mac, un compilateur dans le but de créer des exécutables pour Windows. C'est ce que nous allons voir ici.

MinGW

MinGW est un projet ayant pour objectif de porter les outils de développement du projet GNU sur la plateforme Windows. C'est donc une excellente base de départ pour ce que nous voulons faire, car il met à notre disposition un ensemble de fichiers d'entêtes pour le développement d'application Windows. Ces éléments sont disponibles dans la partie RuntimeLibrary du projet.

Commencez donc par télécharger la dernière version des Win32-API ainsi que celle du runtime MinGW.

J'ai l'habitude d'installer mes environnements de cross-compilation2 dans le répertoire /opt/cross. Dans la suite, je partirais du principe que nous ferons une installation dans /opt/cross/win32.

Décompresser le contenu des deux archives récupérées précédemment dans le répertoire d'installation choisis pour l'environnement, soit, /opt/cross/win32 si vous suivez mon exemple.

Nous allons maintenant pouvoir compiler et installer GCC. Avant cela, une préparation s'impose !

GMP, MPFR, MPC

Les dépendances de GCC sont relativement importantes. Cependant, la major partie est résolue par l'installation des outils de développement Mac. Si ces outils ne sont pas installés sur votre machine, récupérez-les sur le site développeurs Apple et installez-les.

A l'heure où j'écris ces lignes, Xcode 4 est encore en GM et donc non disponible au commun des mortels, je travaille donc avec Xcode 3. Si vous tombez sur cet article après la mise à disposition d'Xcode 4, je ne pense pas que cela devrait changer quoi que ce soit, mais je ne peux rien garantir...

Parmi les autres dépendances, nous avons besoin d'installer GMP, MPFR et MPC. Pour cela, vous avez le choix entre compiler vous même ces librairies ou les installer via fink ou homebrew. En ce qui me concerne, j'utilise ce dernier pour lequel l'installation se fait très simplement :

brew install gmp
brew install mpfr
brew install libmpc

binutils

Pour terminer avec les dépendances de GCC, nous avons également besoin de binutils. Cet ensemble d'outils comprend, entre autres, l'assembleur GNU. Nous allons donc devoir compiler binutils de façon à avoir des outils capables de travailler avec Windows comme plateforme cible. Récupérez la dernière version des sources, décompressez le contenu de l'archive dans un répertoire de votre choix et compilez-les de la façon suivante :

cd binutils-2.21
mkdir build
cd build
../configure --prefix=/opt/concf/cross/win32/ \
  --target=i386-mingw32 --host=i386-apple-darwin  --build=i386-apple-darwin \
  --with-libs=/opt/concf/cross/win32/lib \
  --with-headers=/opt/concf/cross/win32/include \
  --with-gxx-include-dir=/opt/concf/cross/win32/include/c++
make
sudo make install

Vous remarquerez que nous avons utilisé les options --target, --host et --build. La première de ces options nous permet d'indiquer la plateforme cible. La seconde indique sur quel type de plateforme nous allons travailler. La dernière indique sur quelle plateforme nous sommes. Dans le cas présent, nous faisons notre installation sur Mac, pour Mac avec Windows (via MinGW) comme cible.

GCC

Les dépendances étant installées, nous pouvons maintenant compiler GCC. Récupérez la dernière version des sources et extrayez le contenu de l'archive dans le répertoire de votre choix. Vous pouvez compiler :

ln -s gcc-4.5.2 gcc
cd gcc-4.5.2
mkdir build
cd build
../configure --prefix=/opt/concf/cross/win32/ \
  --target=i386-mingw32 --host=i386-apple-darwin --build=i386-apple-darwin \
  --with-gmp=/Users/greg/bin/homebrew --with-mpfr=/Users/greg/bin/homebrew \
  --with-mpc=/Users/greg/bin/homebrew --with-libs=/opt/concf/cross/win32/lib \
  --with-headers=/opt/concf/cross/win32/include \
  --with-gxx-include-dir=/opt/concf/cross/win32/include/c++ --with-gcc \
  --with-tune=generic --disable-werror  --disable-win32-registry --enable-sjlj-exceptions \
  --enable-cxx-flags='-fno-function-sections -fno-data-sections' \
  --enable-version-specific-runtime-libs --disable-bootstrap --enable-threads --disable-nls \
  --enable-languages=c,c++
make
sudo make install

Vous remarquerez que là encore, nous avons utilisé les options --target, --host et --build.

Notez aussi la création du lien symbolique gcc. Je n'avais pas eu besoin de le faire avec les précédentes versions de GCC. Cependant, avec la version 4.5.2 que j'utilise ici, sans ce lien symbolique, la compilation échoue. J'ai peut-être raté quelque chose, mais vu le coût que cela représente, je ne me suis pas posé plus de questions ;)

Testons !

Notre environnement est maintenant installé. Je vous propose un petit programme d'exemple qui vous permettra de tester que tout fonctionne bien.

#include <stdio.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
#include <direct.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#endif

#define MY_MASK 0755

int main(int argc, char** argv) {
  printf("Default mask: %o\n", MY_MASK & ~022 & MY_MASK);
  int temp = umask(0);
  printf("Previous umask = %o\n", temp);

  if(argc < 2) {
    printf("Usage: %s [new dir name]\n", argv[0]);
    return(1);
  }

#ifdef _WIN32
  if(mkdir(argv[1]) == -1) {
#else
  if(mkdir(argv[1], MY_MASK) != 0) {
#endif
    printf("Error !\n");
    return(1);
  }
}

Pour compiler cet exemple, exécutez la commande suivante :

/opt/cross/win32/bin/i386-mingw32-gcc -o mkdir2.exe \
  -I/opt/cross/win32/include -L/opt/cross/win32/lib -D_WIN32 mkdir2.c

Vous obtiendrez un exécutable mkdir2.exe parfaitement fonctionnel sous Windows ! Pour compiler ce même exemple de façon à obtenir un exécutable Mac, vous pouvez utiliser la commande suivante :

gcc -o mkdir2 -m64 -m32 -O -arch x86_64 -arch i386 \
  -isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 mkdir2.c

Pourquoi tout cela ?

Je ne vais pas faire mon Fred C. et vous lister les 10 bonnes raisons de faire de la cross compilation en 2011. Mais, pour ceux qui se posent la question du pourquoi ?, je répondrai simplement : Pour éviter de passer son temps à jongler avec les différents environnements cibles. Personnellement, je trouve que travailler toujours sur la même machine, avec les outils dont j'ai l'habitude, est bien plus agréable que de passer mon temps à sauter d'une machine à un autre, fut elle virtuelle. En installant un tel environnement, je peux à tout instant vérifier que mon projet compile bien sous Windows et Mac. Et même si je ne peux pas tester, cela permet tout de même de gagner pas mal de temps.


1 Il n'y a là rien de péjoratif !
2 J'en ai un pour Windows et un pour Linux.

Copyright © 2009 - 2011 Grégoire Lejeune.
All documents licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License, except ones with specified licence.
Powered by Jekyll.