Faire un joli programme qui marche est une (bonne) chose, le diffuser en est une autre.
Il faut en effet que le PC du nouvel utilisateur dispose déjà des programmes nécessaires de Python, de PyQt4 (, etc…), avec les bonnes versions, sans lesquels votre programme ne fonctionnera pas (et vous porterez le chapeau…).
Alors, il est important de pouvoir diffuser votre programme, accompagné de toutes les bibliothèques qui lui permettront de fonctionner correctement, même si l'utilisateur n'a rien installé du tout! C'est l'objet du présent tuto.
On va utiliser le logiciel cx_freeze pour cela (http://cx-freeze.sourceforge.net/). Il a l'avantage d'être multiplateforme (Windows-Linux). Il faudra bien sûr l'utiliser sous Windows pour avoir la version Windows et sous Linux pour avoir la version Linux, car les bibliothèques ne sont pas les mêmes.
On va étudier ici l'utilisation de cx_freeze sur Ubuntu 10.10, une des distributions Linux les plus utilisées.
Pour mettre au point ce tuto, j'ai installé deux Ubuntu 10.10:
Mon but est de pouvoir transporter sur la version “brute d'install”, le programme traité par cx_freeze.
Ubuntu 10.10 est installé avec Python 2.6.6. Il est possible d'installer Python 2.7, voire Python 3.1, mais je ne l'ai pas fait par prudence: certains autres programmes, y compris du système, fonctionnent avec la version de Python pré-installée.
Pour qu'un programme PyQt4 fonctionne, il faut peu de choses:
Il faut, bien sûr ajouter les autres modules utilisés par votre programme. Par exemple:
Et c'est tout! Avec synaptic, c'est l'affaire de 2 minutes.
Une chose importante: en s'installant, python-qt4 installe aussi, au titre des dépendances, python-sip: il est important de ne pas installer d'autres “sip”, car PyQt4 est configuré avec une version précise de sip, et la bibliothèque correspondante, sip.so, devra accompagner votre programme “standalone”.
cx_freeze est un paquet qui existe sous Ubuntu 10.10, et la première chose qu'on pense à faire est de l'installer. C'est en général une bonne pratique, mais pas ici: la version fournie, la 4.0.1, est insuffisante pour l'option dont on aura besoin: bin_path_includes, qui permettra d'intégrer des bibliothèques supplémentaires, et qui n'est apparu qu'avec la version 4.2.1. On va donc télécharger le code source et l'intégrer par compilation:
python setup.py build sudo python setup.py install
Il vient un grand nombre de messages: ne vous laissez pas impressionner: il suffit de vérifier qu'il n'y a pas d'erreur!
Voilà, vous avez le cx_freeze le plus récent!
Il existe plusieurs façons d'utiliser cx_freeze, et j'ai choisi l'utilisation de setup.py (même méthode que pour py2exe sous Windows). L'avantage est que, si on débrouille bien, le même setup.py pourra être utilisé sous Windows et sous Linux.
J'utilise un “modèle” de setup.py que je fais évoluer au gré de mes programmes, et, il faut bien le dire, au gré de mes (nombreux et longs) tâtonnements.
Voilà les particularités des options de setup.py pour des programmes complexes PyQt4 avec QtSql (se reporter au code plus bas):
Et c'est tout: avec ça, vous récupérez un répertoire avec tout ce qu'il faut pour une exécution “standalone” sur un Ubuntu “brut d'install”!
Voilà un exemple de code du setup.py que j'ai utilisé pour un logiciel de concours photos pour un photo-club (environ 10000 lignes de code et utilisation de QtSql).
Le code ci-dessous fonctionne sans modification sous Windows et sous Linux. Si on veut utiliser le même code pour Windows et Linux, il faut utiliser à plusieurs endroits les tests habituels de plateforme (if sys.platform == “win32” ou if sys.platform == “linux2”) puisque certaines adresses de bibliothèques sont différentes.
#!/usr/bin/python # -*- coding: utf-8 -*- # Python 2.7 # 02/2011 import sys, os from cx_Freeze import setup, Executable ############################################################################# # preparation des options # chemins de recherche des modules path = sys.path + ["biblio", "consultations", "etatbase", "etiquettes", "jugement", "publications", "retourcolis", "saisiebord", "verifications", "vuetable"] # options d'inclusion/exclusion des modules includes = ["sip"] excludes = [] packages = [] # copier les fichiers et/ou répertoires et leur contenu: includefiles = [("aide", "aide")] if sys.platform == "linux2": includefiles += [(r"/usr/lib/qt4/plugins/sqldrivers","sqldrivers")] elif sys.platform == "win32": includefiles += [(r"C:\Python27\Lib\site-packages\PyQt4\plugins\sqldrivers","sqldrivers")] else: pass # pour inclusion éventuelle de bibliothèques supplémentaires binpathincludes = [] if sys.platform == "linux2": # pour que les bibliothèques de /usr/lib soient copiées aussi binpathincludes += ["/usr/lib"] # construction du dictionnaire des options options = {"path": path, "includes": includes, "excludes": excludes, "packages": packages, "include_files": includefiles, "bin_path_includes": binpathincludes } ############################################################################# # preparation des cibles base = None if sys.platform == "win32": base = "Win32GUI" cible_1 = Executable( script = "concoursphotos.pyw", base = base, compress = True, icon = None, ) ############################################################################# # creation du setup setup( name = "concoursphotos", version = "1", description = "Traitement de concours photos sous Windows et Linux", author = "Tyrtamos", options = {"build_exe": options}, executables = [cible_1] )
Une fois le setup.py écrit et mis dans la racine du répertoire du programme à traiter (/chemin par exemple):
python setup.py build
Amusez-vous bien!