Ceci est une ancienne révision du document !
[modernisation du setup.py le 29/3/2013]
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 Windows XP, Vista ou 7.
Pour mettre au point ce tuto, j'ai utilisé deux Windows:
Mon but est de pouvoir transporter sur la version “brute d'install”, le programme traité par cx_freeze.
Pour qu'un programme PyQt4 fonctionne sous Windows, il faut peu de choses:
Ces 2 logiciels existent sous forme de binaire, et donc sont très faciles à installer.
Et c'est tout!
cx_freeze est aussi présenté sous forme de binaire facile à installer.
Choisir de préférence une verson >=4.2.1. (http://cx-freeze.sourceforge.net/)
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 Windows dans lequel il n'y a ni Python, ni PyQt4!
Voilà un exemple de code du setup.py que j'ai utilisé pour un logiciel de concours photos pour un photo-club (environ 25000 lignes de code et utilisation de QtSql).
Pour que le setup.py puisse, sans modification, servir sous Windows et sous Linux, il faudra utiliser à plusieurs endroits les tests habituels de plateforme (if sys.platform == “win32” ou if sys.platform == “linux2”) puisque certaines adresses de bibliothèques seront différentes. Peut-être que des adaptations mineures permettraient l'utilisation sur Mac OSX et plus (Solaris, …) mais je n'ai pas essayé.
#!/usr/bin/python # -*- coding: utf-8 -*- # Python 2.7 # 03/2013 """ Pas d'accent dans le setup, ni dans la description, ni dans les commentaires Icone sous Windows: il faut: => un xxx.ico pour integration dans le exe, avec "icon=xxx.ico" => un xxx.png pour integration avec PyQt4 + demander la copie avec includefiles. """ import sys, os from cx_Freeze import setup, Executable ############################################################################# # preparation des options # chemins de recherche des modules path = sys.path + ["bordereaux", "etiquettes", "fenetre", "integrebase", "jugement", "publications", "retourcolis"] # options d'inclusion/exclusion des modules includes = ["sip", "atexit"] excludes = [] packages = ["biblio"] # copier les fichiers et/ou repertoires et leur contenu: includefiles = [("aide", "aide"), ("fichiers", "fichiers"), ("navigweb", "navigweb"), ("simplediteur", "simplediteur"), 'adresse.ini', "concoursphotos.png", ("etiquettes/CODE39.TTF", "etiquettes/CODE39.TTF"), ("qt_cx.conf", "qt.conf")] if sys.platform == "linux2": includefiles += [(r"/usr/lib/qt4/plugins","plugins")] includefiles += [(r"/usr/share/qt4/translations","translations")] elif sys.platform == "win32": includefiles += [(r"C:\Python27\Lib\site-packages\PyQt4\plugins","plugins")] includefiles += [(r"C:\Python27\Lib\site-packages\PyQt4\translations","translations")] else: pass # inclure les fichiers non-py et non-pyw dans library.zip zipincludes = [] # pour que les bibliotheques de /usr/lib soient copiees aussi sous Linux binpathincludes = [] if sys.platform == "linux2": binpathincludes += ["/usr/lib"] # construction du dictionnaire des options options = {"path": path, "includes": includes, "excludes": excludes, "packages": packages, "include_files": includefiles, "zip_includes": zipincludes, "bin_path_includes": binpathincludes, "create_shared_zip": True, "include_in_shared_zip": True, "compressed": False } # pour inclure sous Windows les dll system necessaires if sys.platform == "win32": options["include_msvcr"] = True ############################################################################# # preparation des cibles base = None if sys.platform == "win32": base = "Win32GUI" #base = "Console" icone = None if sys.platform == "win32": icone = "concoursphotos.ico" cible_1 = Executable( script = "bordereaux.pyw", base = base, compress = False, copyDependentFiles = True, appendScriptToExe = True, appendScriptToLibrary = False, icon = icone ) cible_2 = Executable( script = "jugement.pyw", base = base, compress = False, copyDependentFiles = True, appendScriptToExe = True, appendScriptToLibrary = False, icon = icone ) cible_3 = Executable( script = "publications.pyw", base = base, compress = False, copyDependentFiles = True, appendScriptToExe = True, appendScriptToLibrary = False, icon = icone ) cible_4 = Executable( script = "retourcolis.pyw", base = base, compress = False, copyDependentFiles = True, appendScriptToExe = True, appendScriptToLibrary = False, icon = icone ) cible_5 = Executable( script = "etiquettes.pyw", base = base, compress = False, copyDependentFiles = True, appendScriptToExe = True, appendScriptToLibrary = False, icon = icone ) ############################################################################# # creation du setup setup( name = "concoursphotos", version = "1", description = "concoursphotos", author = "Tyrtamos", options = {"build_exe": options}, executables = [cible_1, cible_2, cible_3, cible_4, cible_5] )
Une fois le setup.py écrit et mis dans la racine du répertoire du programme à traiter (\chemin par exemple):
python setup.py build
On peut aussi aller plus loin en encapsulant les fichiers obtenus dans un programme d'installation comme “innosetup” (http://www.jrsoftware.org/isinfo.php). Vous avez un bon tutoriel en français ici: ftp://ftp-developpez.com/jlelong/tutoriels/delphi/deployer-votre-application-innosetup/installation-innosetup.pdf. Vous obtiendrez alors un programme diffusé par un seul fichier qui s'installera et se désinstallera comme n'importe quel logiciel Windows: les utilisateurs se sauront même pas que c'est du Python…
Amusez-vous bien!