Mis à jour le jeudi 31 octobre 2013
  • Facile
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Bonjour !

Le but de ce tuto est de vous expliquer le principe de la cross compilation et de l'appliquer à une application Qt.

Principe

La théorie

La cross compilation consiste à compiler une application pour un environnement d'exécution différent de celui où est effectuée la compilation. Ce procédé est utilisé en informatique industrielle (on ne peut compiler un programme pour un automate en utilisant l'automate lui-même ; c'est plus pratique de le faire depuis un PC, par exemple).

Source : Wikipédia.

Dans notre cas, il va s'agir de créer un exécutable Windows en restant sous Linux. C'est pratique dans le cas où l'on développe une application qu'on veut distribuer à un maximum de gens, mais que l'on n'a pas Windows par exemple (et pourquoi pas ? :p ).

Prérequis

Pour suivre le tutoriel, vous aurez besoin d'une distribution Linux.

Ensuite, il faudra installer les paquets suivants :

  • mingw32 qui permettra de compiler (les paquets mingw32-binutils et mingw32-runtime seront automatiquement installés) ;

  • wine pour installer Qt pour Windows et tester vos applications.

Voici la commande pour les distributions basées sur Debian (en tant que root) :

# aptitude install mingw32 wine

Installation de Qt pour Windows

Tout d'abord, il faut télécharger la version Windows de Qt : http://trolltech.com/developer/downloads/qt/windows.
Choisissez l'installateur en .exe (au milieu de la page).

Nous allons exécuter cet installateur grâce à Wine :

wine /home/tuto/qt-win-opensource-4.4.0-mingw.exe

On suit l'assistant en prenant bien soin de choisir un chemin d'installation sans espace. Pour la suite, je considérerai que vous avez pris le dossier d'installation C:\Qt\4.4.0\ (qui correspond dans l'arborescence Linux à /home/tuto/.wine/drive_c/Qt/4.4.0/).

Le chemin de ce dossier dans l'arborescence Linux sera utilisé par la suite, donc notez-le bien (et remplacez le nom d'utilisateur tuto par le vôtre).

Créer un nouveau mkspec

Maintenant que la version Windows de Qt est installée, nous allons devoir créer un nouveau mkspec pour pouvoir compiler comme il faut.
Les mkspec sont présents dans le dossier /usr/share/qt4/. Il s'agit de fichiers de configuration qui vont aider la commande qmake à créer notre fichier Makefile.

Nous allons nous baser sur un mkspec existant : win32-g++.
On copie donc ce dossier vers un nouveau, que nous appellerons win32-x-g++.
Il suffit d'exécuter cette commande (en root) :

cp -r /usr/share/qt4/mkspecs/win32-g++ /usr/share/qt4/mkspecs/win32-x-g++

Nous allons ensuite remplacer le fichier /usr/share/qt4/mkspecs/win32-x-g++/qmake.conf par un nouveau :

  • sudo nano /usr/share/qt4/mkspecs/win32-x-g++/qmake.conf en console OU,

  • kdesu kate /usr/share/qt4/mkspecs/win32-x-g++/qmake.conf en utilisant le bloc-note de la suite KDE.

  • sudo gedit /usr/share/qt4/mkspecs/win32-x-g++/qmake.conf en utilisant le bloc-note de la suite Gnome.

Voici le nouveau fichier :

#
# qmake configuration for win32-x-g++
#
# Written for MinGW
#

MAKEFILE_GENERATOR        = MINGW
TEMPLATE                = app
CONFIG                        += qt warn_off release link_prl copy_dir_files precompile_header
QT                        += core gui
DEFINES                        += UNICODE QT_LARGEFILE_SUPPORT
QMAKE_COMPILER_DEFINES  += __GNUC__ WIN32

QMAKE_EXT_OBJ           = .o
QMAKE_EXT_RES           = _res.o

QMAKE_CC                = i586-mingw32msvc-gcc
QMAKE_LEX                = flex
QMAKE_LEXFLAGS                =
QMAKE_YACC                = byacc
QMAKE_YACCFLAGS                = -d
QMAKE_CFLAGS                =
QMAKE_CFLAGS_DEPS        = -M
QMAKE_CFLAGS_WARN_ON        = -Wall
QMAKE_CFLAGS_WARN_OFF        = -w
QMAKE_CFLAGS_RELEASE        = -O2
QMAKE_CFLAGS_DEBUG        = -g
QMAKE_CFLAGS_YACC        = -Wno-unused -Wno-parentheses

QMAKE_CXX                = i586-mingw32msvc-g++
QMAKE_CXXFLAGS                = $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_DEPS        = $$QMAKE_CFLAGS_DEPS
QMAKE_CXXFLAGS_WARN_ON        = $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF        = $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE        = $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG        = $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_YACC        = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_THREAD        = $$QMAKE_CFLAGS_THREAD
QMAKE_CXXFLAGS_RTTI_ON        = -frtti
QMAKE_CXXFLAGS_RTTI_OFF        = -fno-rtti
QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads
QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -fno-exceptions

QMAKE_INCDIR                = /usr/i586-mingw32msvc/include
QMAKE_INCDIR_QT                = /home/tuto/.wine/drive_c/Qt/4.4.0/include # A MODIFIER !!!!!!!!!!!!!!!!!!!!!
QMAKE_LIBDIR_QT                = /home/tuto/.wine/drive_c/Qt/4.4.0/lib # A MODIFIER !!!!!!!!!!!!!!!!!!!!!

QMAKE_RUN_CC                = $(CC) -c $(CFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CC_IMP        = $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
QMAKE_RUN_CXX                = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CXX_IMP        = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

QMAKE_LINK                = i586-mingw32msvc-g++
QMAKE_LFLAGS                = -mthreads -Wl,-enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -mwindows
QMAKE_LFLAGS_EXCEPTIONS_ON = -mthreads -Wl
QMAKE_LFLAGS_EXCEPTIONS_OFF =
QMAKE_LFLAGS_RELEASE        = -Wl,-s
QMAKE_LFLAGS_DEBUG        =
QMAKE_LFLAGS_CONSOLE        = -Wl,-subsystem,console
QMAKE_LFLAGS_WINDOWS        = -Wl,-subsystem,windows
QMAKE_LFLAGS_DLL        = -shared
QMAKE_LINK_OBJECT_MAX        = 10
QMAKE_LINK_OBJECT_SCRIPT= object_script

QMAKE_LIBS                =
QMAKE_LIBS_CORE         = -lkernel32 -luser32 -lshell32 -luuid -lole32 -ladvapi32 -lws2_32
QMAKE_LIBS_GUI          = -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lws2_32 -lole32 -luuid -luser32 -ladvapi32
QMAKE_LIBS_NETWORK      = -lws2_32
QMAKE_LIBS_OPENGL       = -lopengl32 -lglu32 -lgdi32 -luser32
QMAKE_LIBS_COMPAT       = -ladvapi32 -lshell32 -lcomdlg32 -luser32 -lgdi32 -lws2_32
QMAKE_LIBS_QT_ENTRY     = -lmingw32 -lqtmain

QMAKE_DIR_SEP                = /
        QMAKE_COPY                = cp
        QMAKE_COPY_DIR                = cp -r
        QMAKE_MOVE                = mv
        QMAKE_DEL_FILE                = rm
        QMAKE_MKDIR                = mkdir -p
        QMAKE_DEL_DIR                = rm -r
    QMAKE_CHK_DIR_EXISTS = test -d

QMAKE_MOC                = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc
QMAKE_UIC                = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic
QMAKE_IDC                = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc
QMAKE_RCC               = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}rcc

QMAKE_IDL                = midl
QMAKE_LIB                = i586-mingw32-ar -ru
QMAKE_RC                = i586-mingw32msvc-windres
QMAKE_ZIP                = zip -r -9

QMAKE_STRIP                = i586-mingw32msvc-strip
QMAKE_STRIPFLAGS_LIB         += --strip-unneeded
load(qt_config)

Ce fichier est donc une version modifiée de l'ancien, qui permet d'utiliser les utilitaires de notre environnement Linux pendant la compilation. N'oubliez pas de le modifier (là où j'ai commenté) en fonction du répertoire d'installation de Qt Windows et de votre nom d'utilisateur.

Nous allons également éditer le fichier /usr/share/qt4/mkspecs/qconfig.pri et enlever le mot debug de la ligne :

CONFIG +=  no_mocdepend debug stl qt_no_framework

On obtient donc :

CONFIG +=  no_mocdepend stl qt_no_framework

Compilation

Nous avons créé notre nouveau mkspec, il ne reste plus qu'à l'utiliser !

On ouvre un terminal et on se place dans le dossier où sont nos sources (et surtout le précieux fichier .pro, généré avec la commande qmake -project ou à la main) et on crée un dossier win32 qui contiendra les fichiers compilés pour Windows. On va ensuite lancer la commande qmake, mais en lui indiquant d'utiliser notre nouveau mkspec (et le bon dossier) :

cd /home/tuto/mon_programme
mkdir win32
qmake -spec win32-x-g++ -o win32/

À ce stade, on a normalement un fichier Makefile dans le dossier /home/tuto/mon_programme/win32/. On va pouvoir lancer la compilation, après s'être placé dans le bon dossier :

cd win32/
make

Il ne reste plus qu'à lancer le résultat avec Wine :

wine mon_programme.exe

C'est normal ! Nous avons oublié une particularité de Windows : il faut les bonnes DLL pour permettre à notre programme de fonctionner.

Nous allons devoir récupérer trois DLL (peut-être plus, en fonction des fonctionnalités que vous avez utilisées dans votre programme Qt). On a deux possibilités : placer les DLL dans le même dossier que notre programme, ou les placer dans C:\Windows\system32\.

On va opter pour la première solution, mais vous savez qu'il en existe une autre : ;)

  • mingw32m10.dll : elle est fournie avec les paquets mingw32 :
    gunzip -c /usr/share/doc/mingw32-runtime/mingwm10.dll.gz > /home/tuto/mon_programme/win32/mingwm10.dll

  • QtCore4.dll : elle est dans le dossier bin installé avec Qt Windows :
    cp /home/tuto/.wine/drive_c/Qt/4.4.0/bin/QtCore4.dll /home/tuto/mon_programme/win32/QtCore4.dll

  • QtGui4.dll : elle est aussi dans le dossier bin installé avec Qt Windows :
    cp /home/tuto/.wine/drive_c/Qt/4.4.0/bin/QtGui4.dll /home/tuto/mon_programme/win32/QtGui4.dll

Nous pouvons maintenant relancer notre programme, qui doit alors fonctionner.

J'espère que ce tutoriel vous a été profitable !

Vous pouvez me contacter par MP si vous avez un problème.

Image utilisateur

Ce tutoriel a été inspiré par un article de P@sNox sur Qtfr.org.

Exemple de certificat de réussite
Exemple de certificat de réussite